Imported Upstream version 0.37.0 upstream/0.37.0
authorbiao716.wang <biao716.wang@samsung.com>
Fri, 8 Jul 2022 11:04:51 +0000 (20:04 +0900)
committerbiao716.wang <biao716.wang@samsung.com>
Fri, 8 Jul 2022 11:04:51 +0000 (20:04 +0900)
Change-Id: I44d8429f225ee9f63fa9ad35365861ed11badd14
Signed-off-by: biao716.wang <biao716.wang@samsung.com>
681 files changed:
BSSolv.pm
BSSolv.xs
Makefile.PL
debian/control
libsolv-0.6.15/.emacs-dirvars [deleted file]
libsolv-0.6.15/.gitignore [deleted file]
libsolv-0.6.15/.travis.yml [deleted file]
libsolv-0.6.15/BUGS [deleted file]
libsolv-0.6.15/CMakeLists.txt [deleted file]
libsolv-0.6.15/CREDITS [deleted file]
libsolv-0.6.15/INSTALL [deleted file]
libsolv-0.6.15/LICENSE.BSD [deleted file]
libsolv-0.6.15/NEWS [deleted file]
libsolv-0.6.15/README [deleted file]
libsolv-0.6.15/VERSION.cmake [deleted file]
libsolv-0.6.15/bindings/CMakeLists.txt [deleted file]
libsolv-0.6.15/bindings/perl/CMakeLists.txt [deleted file]
libsolv-0.6.15/bindings/python/CMakeLists.txt [deleted file]
libsolv-0.6.15/bindings/ruby/CMakeLists.txt [deleted file]
libsolv-0.6.15/bindings/solv.i [deleted file]
libsolv-0.6.15/bindings/tcl/CMakeLists.txt [deleted file]
libsolv-0.6.15/bindings/tcl/solv.tm.in [deleted file]
libsolv-0.6.15/cmake/modules/FindCheck.cmake [deleted file]
libsolv-0.6.15/cmake/modules/FindEXPAT.cmake [deleted file]
libsolv-0.6.15/cmake/modules/FindLZMA.cmake [deleted file]
libsolv-0.6.15/cmake/modules/FindLibSolv.cmake [deleted file]
libsolv-0.6.15/cmake/modules/FindPackageHandleStandardArgs.cmake [deleted file]
libsolv-0.6.15/cmake/modules/FindRuby.cmake [deleted file]
libsolv-0.6.15/cmake/modules/_CMakeParseArguments.cmake [deleted file]
libsolv-0.6.15/doc/CMakeLists.txt [deleted file]
libsolv-0.6.15/doc/Makefile.gen [deleted file]
libsolv-0.6.15/doc/appdata2solv.1 [deleted file]
libsolv-0.6.15/doc/appdata2solv.txt [deleted file]
libsolv-0.6.15/doc/archpkgs2solv.1 [deleted file]
libsolv-0.6.15/doc/archpkgs2solv.txt [deleted file]
libsolv-0.6.15/doc/archrepo2solv.1 [deleted file]
libsolv-0.6.15/doc/archrepo2solv.txt [deleted file]
libsolv-0.6.15/doc/comps2solv.1 [deleted file]
libsolv-0.6.15/doc/comps2solv.txt [deleted file]
libsolv-0.6.15/doc/deb2solv.1 [deleted file]
libsolv-0.6.15/doc/deb2solv.txt [deleted file]
libsolv-0.6.15/doc/deltainfoxml2solv.1 [deleted file]
libsolv-0.6.15/doc/deltainfoxml2solv.txt [deleted file]
libsolv-0.6.15/doc/dumpsolv.1 [deleted file]
libsolv-0.6.15/doc/dumpsolv.txt [deleted file]
libsolv-0.6.15/doc/filters/xcode.conf [deleted file]
libsolv-0.6.15/doc/filters/xcode.pl [deleted file]
libsolv-0.6.15/doc/helix2solv.1 [deleted file]
libsolv-0.6.15/doc/helix2solv.txt [deleted file]
libsolv-0.6.15/doc/installcheck.1 [deleted file]
libsolv-0.6.15/doc/installcheck.txt [deleted file]
libsolv-0.6.15/doc/libsolv-bindings.3 [deleted file]
libsolv-0.6.15/doc/libsolv-bindings.txt [deleted file]
libsolv-0.6.15/doc/libsolv-constantids.3 [deleted file]
libsolv-0.6.15/doc/libsolv-constantids.txt [deleted file]
libsolv-0.6.15/doc/libsolv-history.3 [deleted file]
libsolv-0.6.15/doc/libsolv-history.txt [deleted file]
libsolv-0.6.15/doc/libsolv-pool.3 [deleted file]
libsolv-0.6.15/doc/libsolv-pool.txt [deleted file]
libsolv-0.6.15/doc/libsolv.3 [deleted file]
libsolv-0.6.15/doc/libsolv.txt [deleted file]
libsolv-0.6.15/doc/mdk2solv.1 [deleted file]
libsolv-0.6.15/doc/mdk2solv.txt [deleted file]
libsolv-0.6.15/doc/mergesolv.1 [deleted file]
libsolv-0.6.15/doc/mergesolv.txt [deleted file]
libsolv-0.6.15/doc/repomdxml2solv.1 [deleted file]
libsolv-0.6.15/doc/repomdxml2solv.txt [deleted file]
libsolv-0.6.15/doc/rpmdb2solv.1 [deleted file]
libsolv-0.6.15/doc/rpmdb2solv.txt [deleted file]
libsolv-0.6.15/doc/rpmmd2solv.1 [deleted file]
libsolv-0.6.15/doc/rpmmd2solv.txt [deleted file]
libsolv-0.6.15/doc/rpms2solv.1 [deleted file]
libsolv-0.6.15/doc/rpms2solv.txt [deleted file]
libsolv-0.6.15/doc/susetags2solv.1 [deleted file]
libsolv-0.6.15/doc/susetags2solv.txt [deleted file]
libsolv-0.6.15/doc/testsolv.1 [deleted file]
libsolv-0.6.15/doc/testsolv.txt [deleted file]
libsolv-0.6.15/doc/updateinfoxml2solv.1 [deleted file]
libsolv-0.6.15/doc/updateinfoxml2solv.txt [deleted file]
libsolv-0.6.15/examples/CMakeLists.txt [deleted file]
libsolv-0.6.15/examples/p5solv [deleted file]
libsolv-0.6.15/examples/pysolv [deleted file]
libsolv-0.6.15/examples/rbsolv [deleted file]
libsolv-0.6.15/examples/solv/CMakeLists.txt [deleted file]
libsolv-0.6.15/examples/solv/checksig.c [deleted file]
libsolv-0.6.15/examples/solv/checksig.h [deleted file]
libsolv-0.6.15/examples/solv/deltarpm.c [deleted file]
libsolv-0.6.15/examples/solv/deltarpm.h [deleted file]
libsolv-0.6.15/examples/solv/fastestmirror.c [deleted file]
libsolv-0.6.15/examples/solv/fastestmirror.h [deleted file]
libsolv-0.6.15/examples/solv/fileconflicts.c [deleted file]
libsolv-0.6.15/examples/solv/fileconflicts.h [deleted file]
libsolv-0.6.15/examples/solv/fileprovides.c [deleted file]
libsolv-0.6.15/examples/solv/fileprovides.h [deleted file]
libsolv-0.6.15/examples/solv/mirror.c [deleted file]
libsolv-0.6.15/examples/solv/mirror.h [deleted file]
libsolv-0.6.15/examples/solv/patchjobs.c [deleted file]
libsolv-0.6.15/examples/solv/patchjobs.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_cache.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_cache.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_config_debian.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_config_debian.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_config_yum.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_config_yum.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_download.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_download.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_system_debian.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_system_debian.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_system_rpm.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_system_rpm.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_debian.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_debian.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_mdk.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_mdk.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.h [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_susetags.c [deleted file]
libsolv-0.6.15/examples/solv/repoinfo_type_susetags.h [deleted file]
libsolv-0.6.15/examples/solv/solv.c [deleted file]
libsolv-0.6.15/examples/tclsolv [deleted file]
libsolv-0.6.15/ext/CMakeLists.txt [deleted file]
libsolv-0.6.15/ext/libsolvext.ver [deleted file]
libsolv-0.6.15/ext/pool_fileconflicts.c [deleted file]
libsolv-0.6.15/ext/pool_fileconflicts.h [deleted file]
libsolv-0.6.15/ext/pool_parserpmrichdep.c [deleted file]
libsolv-0.6.15/ext/pool_parserpmrichdep.h [deleted file]
libsolv-0.6.15/ext/repo_appdata.c [deleted file]
libsolv-0.6.15/ext/repo_appdata.h [deleted file]
libsolv-0.6.15/ext/repo_arch.c [deleted file]
libsolv-0.6.15/ext/repo_arch.h [deleted file]
libsolv-0.6.15/ext/repo_autopattern.c [deleted file]
libsolv-0.6.15/ext/repo_autopattern.h [deleted file]
libsolv-0.6.15/ext/repo_comps.c [deleted file]
libsolv-0.6.15/ext/repo_comps.h [deleted file]
libsolv-0.6.15/ext/repo_content.c [deleted file]
libsolv-0.6.15/ext/repo_content.h [deleted file]
libsolv-0.6.15/ext/repo_cudf.c [deleted file]
libsolv-0.6.15/ext/repo_cudf.h [deleted file]
libsolv-0.6.15/ext/repo_deb.c [deleted file]
libsolv-0.6.15/ext/repo_deb.h [deleted file]
libsolv-0.6.15/ext/repo_deltainfoxml.c [deleted file]
libsolv-0.6.15/ext/repo_deltainfoxml.h [deleted file]
libsolv-0.6.15/ext/repo_haiku.cpp [deleted file]
libsolv-0.6.15/ext/repo_haiku.h [deleted file]
libsolv-0.6.15/ext/repo_helix.c [deleted file]
libsolv-0.6.15/ext/repo_helix.h [deleted file]
libsolv-0.6.15/ext/repo_mdk.c [deleted file]
libsolv-0.6.15/ext/repo_mdk.h [deleted file]
libsolv-0.6.15/ext/repo_products.c [deleted file]
libsolv-0.6.15/ext/repo_products.h [deleted file]
libsolv-0.6.15/ext/repo_pubkey.c [deleted file]
libsolv-0.6.15/ext/repo_pubkey.h [deleted file]
libsolv-0.6.15/ext/repo_releasefile_products.c [deleted file]
libsolv-0.6.15/ext/repo_releasefile_products.h [deleted file]
libsolv-0.6.15/ext/repo_repomdxml.c [deleted file]
libsolv-0.6.15/ext/repo_repomdxml.h [deleted file]
libsolv-0.6.15/ext/repo_rpmdb.c [deleted file]
libsolv-0.6.15/ext/repo_rpmdb.h [deleted file]
libsolv-0.6.15/ext/repo_rpmmd.c [deleted file]
libsolv-0.6.15/ext/repo_rpmmd.h [deleted file]
libsolv-0.6.15/ext/repo_susetags.c [deleted file]
libsolv-0.6.15/ext/repo_susetags.h [deleted file]
libsolv-0.6.15/ext/repo_updateinfoxml.c [deleted file]
libsolv-0.6.15/ext/repo_updateinfoxml.h [deleted file]
libsolv-0.6.15/ext/repo_zyppdb.c [deleted file]
libsolv-0.6.15/ext/repo_zyppdb.h [deleted file]
libsolv-0.6.15/ext/solv_pgpvrfy.c [deleted file]
libsolv-0.6.15/ext/solv_pgpvrfy.h [deleted file]
libsolv-0.6.15/ext/solv_xfopen.c [deleted file]
libsolv-0.6.15/ext/solv_xfopen.h [deleted file]
libsolv-0.6.15/ext/testcase.c [deleted file]
libsolv-0.6.15/ext/testcase.h [deleted file]
libsolv-0.6.15/ext/tools_util.h [deleted file]
libsolv-0.6.15/libsolv.pc.in [deleted file]
libsolv-0.6.15/package/libsolv.changes [deleted file]
libsolv-0.6.15/package/libsolv.spec.in [deleted file]
libsolv-0.6.15/src/CMakeLists.txt [deleted file]
libsolv-0.6.15/src/bitmap.c [deleted file]
libsolv-0.6.15/src/bitmap.h [deleted file]
libsolv-0.6.15/src/chksum.c [deleted file]
libsolv-0.6.15/src/chksum.h [deleted file]
libsolv-0.6.15/src/cplxdeps.c [deleted file]
libsolv-0.6.15/src/cplxdeps.h [deleted file]
libsolv-0.6.15/src/dataiterator.h [deleted file]
libsolv-0.6.15/src/dirpool.c [deleted file]
libsolv-0.6.15/src/dirpool.h [deleted file]
libsolv-0.6.15/src/evr.c [deleted file]
libsolv-0.6.15/src/evr.h [deleted file]
libsolv-0.6.15/src/hash.h [deleted file]
libsolv-0.6.15/src/knownid.h [deleted file]
libsolv-0.6.15/src/libsolv.ver [deleted file]
libsolv-0.6.15/src/linkedpkg.c [deleted file]
libsolv-0.6.15/src/linkedpkg.h [deleted file]
libsolv-0.6.15/src/md5.c [deleted file]
libsolv-0.6.15/src/md5.h [deleted file]
libsolv-0.6.15/src/order.c [deleted file]
libsolv-0.6.15/src/policy.c [deleted file]
libsolv-0.6.15/src/policy.h [deleted file]
libsolv-0.6.15/src/pool.c [deleted file]
libsolv-0.6.15/src/pool.h [deleted file]
libsolv-0.6.15/src/poolarch.c [deleted file]
libsolv-0.6.15/src/poolarch.h [deleted file]
libsolv-0.6.15/src/poolid.c [deleted file]
libsolv-0.6.15/src/poolid.h [deleted file]
libsolv-0.6.15/src/poolid_private.h [deleted file]
libsolv-0.6.15/src/pooltypes.h [deleted file]
libsolv-0.6.15/src/poolvendor.c [deleted file]
libsolv-0.6.15/src/poolvendor.h [deleted file]
libsolv-0.6.15/src/problems.c [deleted file]
libsolv-0.6.15/src/problems.h [deleted file]
libsolv-0.6.15/src/qsort_r.c [deleted file]
libsolv-0.6.15/src/queue.c [deleted file]
libsolv-0.6.15/src/queue.h [deleted file]
libsolv-0.6.15/src/repo.c [deleted file]
libsolv-0.6.15/src/repo.h [deleted file]
libsolv-0.6.15/src/repo_solv.c [deleted file]
libsolv-0.6.15/src/repo_solv.h [deleted file]
libsolv-0.6.15/src/repo_write.c [deleted file]
libsolv-0.6.15/src/repo_write.h [deleted file]
libsolv-0.6.15/src/repodata.c [deleted file]
libsolv-0.6.15/src/repodata.h [deleted file]
libsolv-0.6.15/src/repopack.h [deleted file]
libsolv-0.6.15/src/repopage.c [deleted file]
libsolv-0.6.15/src/repopage.h [deleted file]
libsolv-0.6.15/src/rules.c [deleted file]
libsolv-0.6.15/src/rules.h [deleted file]
libsolv-0.6.15/src/selection.c [deleted file]
libsolv-0.6.15/src/selection.h [deleted file]
libsolv-0.6.15/src/sha1.c [deleted file]
libsolv-0.6.15/src/sha1.h [deleted file]
libsolv-0.6.15/src/sha2.c [deleted file]
libsolv-0.6.15/src/sha2.h [deleted file]
libsolv-0.6.15/src/solvable.c [deleted file]
libsolv-0.6.15/src/solvable.h [deleted file]
libsolv-0.6.15/src/solver.c [deleted file]
libsolv-0.6.15/src/solver.h [deleted file]
libsolv-0.6.15/src/solver_private.h [deleted file]
libsolv-0.6.15/src/solverdebug.c [deleted file]
libsolv-0.6.15/src/solverdebug.h [deleted file]
libsolv-0.6.15/src/solvversion.c [deleted file]
libsolv-0.6.15/src/solvversion.h.in [deleted file]
libsolv-0.6.15/src/strpool.c [deleted file]
libsolv-0.6.15/src/strpool.h [deleted file]
libsolv-0.6.15/src/transaction.c [deleted file]
libsolv-0.6.15/src/transaction.h [deleted file]
libsolv-0.6.15/src/util.c [deleted file]
libsolv-0.6.15/src/util.h [deleted file]
libsolv-0.6.15/test/CMakeLists.txt [deleted file]
libsolv-0.6.15/test/runtestcases [deleted file]
libsolv-0.6.15/test/testcases/choose/default.t [deleted file]
libsolv-0.6.15/test/testcases/choose/enhanced.t [deleted file]
libsolv-0.6.15/test/testcases/choose/oldversion.t [deleted file]
libsolv-0.6.15/test/testcases/choose/suggested.t [deleted file]
libsolv-0.6.15/test/testcases/choose/versioned.t [deleted file]
libsolv-0.6.15/test/testcases/choose/versioned2.t [deleted file]
libsolv-0.6.15/test/testcases/cleandeps/cleandeps_dup.t [deleted file]
libsolv-0.6.15/test/testcases/cleandeps/cleandeps_in.t [deleted file]
libsolv-0.6.15/test/testcases/cleandeps/cleandeps_up.t [deleted file]
libsolv-0.6.15/test/testcases/cleandeps/mistake.t [deleted file]
libsolv-0.6.15/test/testcases/distupgrade/dup_allowuninstall [deleted file]
libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion1 [deleted file]
libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2 [deleted file]
libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3 [deleted file]
libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange [deleted file]
libsolv-0.6.15/test/testcases/evrcmp/conflicts.repo [deleted file]
libsolv-0.6.15/test/testcases/evrcmp/system.repo [deleted file]
libsolv-0.6.15/test/testcases/evrcmp/testevr.t [deleted file]
libsolv-0.6.15/test/testcases/forcebest/forcebest_dup.t [deleted file]
libsolv-0.6.15/test/testcases/forcebest/forcebest_in.t [deleted file]
libsolv-0.6.15/test/testcases/forcebest/forcebest_up.t [deleted file]
libsolv-0.6.15/test/testcases/lockstep/lockstep_install.t [deleted file]
libsolv-0.6.15/test/testcases/lockstep/lockstep_update.t [deleted file]
libsolv-0.6.15/test/testcases/multiversion/multiversion.t [deleted file]
libsolv-0.6.15/test/testcases/namespace/namespaceprovides.t [deleted file]
libsolv-0.6.15/test/testcases/sat/assert.t [deleted file]
libsolv-0.6.15/test/testcases/sat/mm-test.t [deleted file]
libsolv-0.6.15/test/testcases/targeted/targeted_dup.t [deleted file]
libsolv-0.6.15/test/testcases/targeted/targeted_up.t [deleted file]
libsolv-0.6.15/test/testcases/testcase/str2dep.t [deleted file]
libsolv-0.6.15/test/testcases/yumobs/split.t [deleted file]
libsolv-0.6.15/tools/CMakeLists.txt [deleted file]
libsolv-0.6.15/tools/appdata2solv.c [deleted file]
libsolv-0.6.15/tools/archpkgs2solv.c [deleted file]
libsolv-0.6.15/tools/archrepo2solv.c [deleted file]
libsolv-0.6.15/tools/common_write.c [deleted file]
libsolv-0.6.15/tools/common_write.h [deleted file]
libsolv-0.6.15/tools/comps2solv.c [deleted file]
libsolv-0.6.15/tools/cudftest.c [deleted file]
libsolv-0.6.15/tools/deb2solv.c [deleted file]
libsolv-0.6.15/tools/deltainfoxml2solv.c [deleted file]
libsolv-0.6.15/tools/diskusagexml2solv.c [deleted file]
libsolv-0.6.15/tools/dumpsolv.c [deleted file]
libsolv-0.6.15/tools/findfileconflicts.c [deleted file]
libsolv-0.6.15/tools/helix2solv.c [deleted file]
libsolv-0.6.15/tools/installcheck.c [deleted file]
libsolv-0.6.15/tools/mdk2solv.c [deleted file]
libsolv-0.6.15/tools/mergesolv.c [deleted file]
libsolv-0.6.15/tools/patchcheck.c [deleted file]
libsolv-0.6.15/tools/repo2solv.sh [deleted file]
libsolv-0.6.15/tools/repomdxml2solv.c [deleted file]
libsolv-0.6.15/tools/rpmdb2solv.c [deleted file]
libsolv-0.6.15/tools/rpmmd2solv.c [deleted file]
libsolv-0.6.15/tools/rpms2solv.c [deleted file]
libsolv-0.6.15/tools/susetags2solv.c [deleted file]
libsolv-0.6.15/tools/testsolv.c [deleted file]
libsolv-0.6.15/tools/updateinfoxml2solv.c [deleted file]
libsolv-0.7.2/.emacs-dirvars [new file with mode: 0644]
libsolv-0.7.2/.gitignore [new file with mode: 0644]
libsolv-0.7.2/.travis.yml [new file with mode: 0644]
libsolv-0.7.2/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/CREDITS [new file with mode: 0644]
libsolv-0.7.2/INSTALL [new file with mode: 0644]
libsolv-0.7.2/LICENSE.BSD [new file with mode: 0644]
libsolv-0.7.2/NEWS [new file with mode: 0644]
libsolv-0.7.2/README [new file with mode: 0644]
libsolv-0.7.2/TODO_1.0 [new file with mode: 0644]
libsolv-0.7.2/VERSION.cmake [new file with mode: 0644]
libsolv-0.7.2/bindings/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/bindings/perl/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/bindings/python/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/bindings/python3/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/bindings/ruby/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/bindings/solv.i [new file with mode: 0644]
libsolv-0.7.2/bindings/tcl/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/bindings/tcl/solv.tm.in [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/FindCheck.cmake [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/FindEXPAT.cmake [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/FindLZMA.cmake [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/FindLibSolv.cmake [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/FindPackageHandleStandardArgs.cmake [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/FindRuby.cmake [new file with mode: 0644]
libsolv-0.7.2/cmake/modules/_CMakeParseArguments.cmake [new file with mode: 0644]
libsolv-0.7.2/doc/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/doc/Makefile.gen [new file with mode: 0644]
libsolv-0.7.2/doc/appdata2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/archpkgs2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/archrepo2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/comps2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/deb2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/deltainfoxml2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/dumpsolv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/filters/xcode.conf [new file with mode: 0644]
libsolv-0.7.2/doc/filters/xcode.pl [new file with mode: 0755]
libsolv-0.7.2/doc/gen/appdata2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/archpkgs2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/archrepo2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/comps2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/deb2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/deltainfoxml2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/dumpsolv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/helix2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/installcheck.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/libsolv-bindings.3 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/libsolv-constantids.3 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/libsolv-history.3 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/libsolv-pool.3 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/libsolv.3 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/mdk2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/mergesolv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/repo2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/repomdxml2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/rpmdb2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/rpmmd2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/rpms2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/susetags2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/testsolv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/gen/updateinfoxml2solv.1 [new file with mode: 0644]
libsolv-0.7.2/doc/helix2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/installcheck.txt [new file with mode: 0644]
libsolv-0.7.2/doc/libsolv-bindings.txt [new file with mode: 0644]
libsolv-0.7.2/doc/libsolv-constantids.txt [new file with mode: 0644]
libsolv-0.7.2/doc/libsolv-history.txt [new file with mode: 0644]
libsolv-0.7.2/doc/libsolv-pool.txt [new file with mode: 0644]
libsolv-0.7.2/doc/libsolv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/mdk2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/mergesolv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/repo2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/repomdxml2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/rpmdb2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/rpmmd2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/rpms2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/susetags2solv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/testsolv.txt [new file with mode: 0644]
libsolv-0.7.2/doc/updateinfoxml2solv.txt [new file with mode: 0644]
libsolv-0.7.2/examples/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/examples/p5solv [new file with mode: 0755]
libsolv-0.7.2/examples/pysolv [new file with mode: 0755]
libsolv-0.7.2/examples/rbsolv [new file with mode: 0755]
libsolv-0.7.2/examples/repo2solv.sh [new file with mode: 0755]
libsolv-0.7.2/examples/solv/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/examples/solv/checksig.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/checksig.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/deltarpm.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/deltarpm.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/fastestmirror.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/fastestmirror.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/fileconflicts.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/fileconflicts.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/fileprovides.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/fileprovides.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/mirror.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/mirror.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/patchjobs.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/patchjobs.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_cache.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_cache.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_config_debian.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_config_debian.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_config_yum.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_config_yum.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_download.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_download.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_system_debian.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_system_debian.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_system_rpm.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_system_rpm.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_debian.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_debian.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_mdk.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_mdk.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_susetags.c [new file with mode: 0644]
libsolv-0.7.2/examples/solv/repoinfo_type_susetags.h [new file with mode: 0644]
libsolv-0.7.2/examples/solv/solv.c [new file with mode: 0644]
libsolv-0.7.2/examples/tclsolv [new file with mode: 0755]
libsolv-0.7.2/ext/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/ext/libsolvext.ver [new file with mode: 0644]
libsolv-0.7.2/ext/pool_fileconflicts.c [new file with mode: 0644]
libsolv-0.7.2/ext/pool_fileconflicts.h [new file with mode: 0644]
libsolv-0.7.2/ext/pool_parserpmrichdep.c [new file with mode: 0644]
libsolv-0.7.2/ext/pool_parserpmrichdep.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_appdata.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_appdata.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_arch.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_arch.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_autopattern.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_autopattern.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_comps.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_comps.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_content.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_content.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_cudf.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_cudf.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_deb.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_deb.c.orig [new file with mode: 0644]
libsolv-0.7.2/ext/repo_deb.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_deltainfoxml.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_deltainfoxml.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_haiku.cpp [new file with mode: 0644]
libsolv-0.7.2/ext/repo_haiku.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_helix.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_helix.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_mdk.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_mdk.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_products.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_products.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_pubkey.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_pubkey.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_releasefile_products.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_releasefile_products.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_repomdxml.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_repomdxml.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_rpmdb.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_rpmdb.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_rpmdb_bdb.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_rpmdb_librpm.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_rpmmd.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_rpmmd.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_susetags.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_susetags.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_updateinfoxml.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_updateinfoxml.h [new file with mode: 0644]
libsolv-0.7.2/ext/repo_zyppdb.c [new file with mode: 0644]
libsolv-0.7.2/ext/repo_zyppdb.h [new file with mode: 0644]
libsolv-0.7.2/ext/repodata_diskusage.c [new file with mode: 0644]
libsolv-0.7.2/ext/repodata_diskusage.h [new file with mode: 0644]
libsolv-0.7.2/ext/solv_jsonparser.c [new file with mode: 0644]
libsolv-0.7.2/ext/solv_jsonparser.h [new file with mode: 0644]
libsolv-0.7.2/ext/solv_pgpvrfy.c [new file with mode: 0644]
libsolv-0.7.2/ext/solv_pgpvrfy.h [new file with mode: 0644]
libsolv-0.7.2/ext/solv_xfopen.c [new file with mode: 0644]
libsolv-0.7.2/ext/solv_xfopen.h [new file with mode: 0644]
libsolv-0.7.2/ext/solv_xmlparser.c [new file with mode: 0644]
libsolv-0.7.2/ext/solv_xmlparser.h [new file with mode: 0644]
libsolv-0.7.2/ext/solv_zchunk.c [new file with mode: 0644]
libsolv-0.7.2/ext/solv_zchunk.h [new file with mode: 0644]
libsolv-0.7.2/ext/testcase.c [new file with mode: 0644]
libsolv-0.7.2/ext/testcase.h [new file with mode: 0644]
libsolv-0.7.2/ext/tools_util.h [new file with mode: 0644]
libsolv-0.7.2/libsolv.pc.in [new file with mode: 0644]
libsolv-0.7.2/libsolvext.pc.in [new file with mode: 0644]
libsolv-0.7.2/package/libsolv.changes [new file with mode: 0644]
libsolv-0.7.2/package/libsolv.spec.in [new file with mode: 0644]
libsolv-0.7.2/src/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/src/bitmap.c [new file with mode: 0644]
libsolv-0.7.2/src/bitmap.h [new file with mode: 0644]
libsolv-0.7.2/src/chksum.c [new file with mode: 0644]
libsolv-0.7.2/src/chksum.h [new file with mode: 0644]
libsolv-0.7.2/src/cleandeps.c [new file with mode: 0644]
libsolv-0.7.2/src/cplxdeps.c [new file with mode: 0644]
libsolv-0.7.2/src/cplxdeps.h [new file with mode: 0644]
libsolv-0.7.2/src/dataiterator.h [new file with mode: 0644]
libsolv-0.7.2/src/dirpool.c [new file with mode: 0644]
libsolv-0.7.2/src/dirpool.h [new file with mode: 0644]
libsolv-0.7.2/src/diskusage.c [new file with mode: 0644]
libsolv-0.7.2/src/evr.c [new file with mode: 0644]
libsolv-0.7.2/src/evr.h [new file with mode: 0644]
libsolv-0.7.2/src/filelistfilter.c [new file with mode: 0644]
libsolv-0.7.2/src/fileprovides.c [new file with mode: 0644]
libsolv-0.7.2/src/hash.h [new file with mode: 0644]
libsolv-0.7.2/src/knownid.h [new file with mode: 0644]
libsolv-0.7.2/src/libsolv.ver [new file with mode: 0644]
libsolv-0.7.2/src/linkedpkg.c [new file with mode: 0644]
libsolv-0.7.2/src/linkedpkg.h [new file with mode: 0644]
libsolv-0.7.2/src/md5.c [new file with mode: 0644]
libsolv-0.7.2/src/md5.h [new file with mode: 0644]
libsolv-0.7.2/src/order.c [new file with mode: 0644]
libsolv-0.7.2/src/policy.c [new file with mode: 0644]
libsolv-0.7.2/src/policy.h [new file with mode: 0644]
libsolv-0.7.2/src/pool.c [new file with mode: 0644]
libsolv-0.7.2/src/pool.h [new file with mode: 0644]
libsolv-0.7.2/src/poolarch.c [new file with mode: 0644]
libsolv-0.7.2/src/poolarch.h [new file with mode: 0644]
libsolv-0.7.2/src/poolid.c [new file with mode: 0644]
libsolv-0.7.2/src/poolid.h [new file with mode: 0644]
libsolv-0.7.2/src/poolid_private.h [new file with mode: 0644]
libsolv-0.7.2/src/pooltypes.h [new file with mode: 0644]
libsolv-0.7.2/src/poolvendor.c [new file with mode: 0644]
libsolv-0.7.2/src/poolvendor.h [new file with mode: 0644]
libsolv-0.7.2/src/problems.c [new file with mode: 0644]
libsolv-0.7.2/src/problems.h [new file with mode: 0644]
libsolv-0.7.2/src/qsort_r.c [new file with mode: 0644]
libsolv-0.7.2/src/queue.c [new file with mode: 0644]
libsolv-0.7.2/src/queue.h [new file with mode: 0644]
libsolv-0.7.2/src/repo.c [new file with mode: 0644]
libsolv-0.7.2/src/repo.h [new file with mode: 0644]
libsolv-0.7.2/src/repo_solv.c [new file with mode: 0644]
libsolv-0.7.2/src/repo_solv.h [new file with mode: 0644]
libsolv-0.7.2/src/repo_write.c [new file with mode: 0644]
libsolv-0.7.2/src/repo_write.h [new file with mode: 0644]
libsolv-0.7.2/src/repodata.c [new file with mode: 0644]
libsolv-0.7.2/src/repodata.h [new file with mode: 0644]
libsolv-0.7.2/src/repopack.h [new file with mode: 0644]
libsolv-0.7.2/src/repopage.c [new file with mode: 0644]
libsolv-0.7.2/src/repopage.h [new file with mode: 0644]
libsolv-0.7.2/src/rules.c [new file with mode: 0644]
libsolv-0.7.2/src/rules.h [new file with mode: 0644]
libsolv-0.7.2/src/selection.c [new file with mode: 0644]
libsolv-0.7.2/src/selection.h [new file with mode: 0644]
libsolv-0.7.2/src/sha1.c [new file with mode: 0644]
libsolv-0.7.2/src/sha1.h [new file with mode: 0644]
libsolv-0.7.2/src/sha2.c [new file with mode: 0644]
libsolv-0.7.2/src/sha2.h [new file with mode: 0644]
libsolv-0.7.2/src/solvable.c [new file with mode: 0644]
libsolv-0.7.2/src/solvable.h [new file with mode: 0644]
libsolv-0.7.2/src/solver.c [new file with mode: 0644]
libsolv-0.7.2/src/solver.h [new file with mode: 0644]
libsolv-0.7.2/src/solver_private.h [new file with mode: 0644]
libsolv-0.7.2/src/solver_util.c [new file with mode: 0644]
libsolv-0.7.2/src/solverdebug.c [new file with mode: 0644]
libsolv-0.7.2/src/solverdebug.h [new file with mode: 0644]
libsolv-0.7.2/src/solvversion.c [new file with mode: 0644]
libsolv-0.7.2/src/solvversion.h.in [new file with mode: 0644]
libsolv-0.7.2/src/strpool.c [new file with mode: 0644]
libsolv-0.7.2/src/strpool.h [new file with mode: 0644]
libsolv-0.7.2/src/suse.c [new file with mode: 0644]
libsolv-0.7.2/src/transaction.c [new file with mode: 0644]
libsolv-0.7.2/src/transaction.h [new file with mode: 0644]
libsolv-0.7.2/src/userinstalled.c [new file with mode: 0644]
libsolv-0.7.2/src/util.c [new file with mode: 0644]
libsolv-0.7.2/src/util.h [new file with mode: 0644]
libsolv-0.7.2/test/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/test/runtestcases [new file with mode: 0755]
libsolv-0.7.2/test/testcases/allowuninstall/conflict.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/choose/default.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/choose/enhanced.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/choose/oldversion.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/choose/suggested.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/choose/versioned.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/choose/versioned2.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cleandeps/cleandeps_dup.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cleandeps/cleandeps_in.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cleandeps/cleandeps_up.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cleandeps/mistake.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cplxdeps/and.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cplxdeps/andor.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cplxdeps/if.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cplxdeps/or.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/cplxdeps/orand.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_allowuninstall.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion1.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/evrcmp/caret.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/evrcmp/conflicts.repo [new file with mode: 0644]
libsolv-0.7.2/test/testcases/evrcmp/system.repo [new file with mode: 0644]
libsolv-0.7.2/test/testcases/evrcmp/testevr.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/favor/recommends.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/favor/requires.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/favor/supplements.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/focus/best.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/focus/installed.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/focus/normal.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/forcebest/forcebest_dup.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/forcebest/forcebest_in.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/forcebest/forcebest_up.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/lockstep/lockstep_install.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/lockstep/lockstep_update.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/multiversion/multiversion.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/multiversion/update.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/namespace/namespaceprovides.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/recommended_version.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/recommendations/suggested_version.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/sat/assert.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/sat/mm-test.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/sat/reuse.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/selection/selection_filelist.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/selection/selection_name.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/selection/selection_provides.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/strongrecommends/break.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/strongrecommends/strongr.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/targeted/targeted_dup.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/targeted/targeted_up.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/testcase/nested.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/testcase/str2dep.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t [new file with mode: 0644]
libsolv-0.7.2/test/testcases/yumobs/split.t [new file with mode: 0644]
libsolv-0.7.2/tools/CMakeLists.txt [new file with mode: 0644]
libsolv-0.7.2/tools/appdata2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/archpkgs2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/archrepo2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/common_write.c [new file with mode: 0644]
libsolv-0.7.2/tools/common_write.h [new file with mode: 0644]
libsolv-0.7.2/tools/comps2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/cudftest.c [new file with mode: 0644]
libsolv-0.7.2/tools/deb2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/deltainfoxml2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/diskusagexml2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/dumpsolv.c [new file with mode: 0644]
libsolv-0.7.2/tools/findfileconflicts.c [new file with mode: 0644]
libsolv-0.7.2/tools/helix2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/installcheck.c [new file with mode: 0644]
libsolv-0.7.2/tools/mdk2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/mergesolv.c [new file with mode: 0644]
libsolv-0.7.2/tools/repo2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/repomdxml2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/rpmdb2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/rpmmd2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/rpms2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/susetags2solv.c [new file with mode: 0644]
libsolv-0.7.2/tools/testsolv.c [new file with mode: 0644]
libsolv-0.7.2/tools/updateinfoxml2solv.c [new file with mode: 0644]
packaging/perl-BSSolv.spec

index 82db1e18668326759a599066cc1bc93317ec154a..7a2213a623a3ee75874764ede8974dfe555bc850 100644 (file)
--- a/BSSolv.pm
+++ b/BSSolv.pm
@@ -6,7 +6,7 @@ require Exporter;
 
 our @ISA = qw(Exporter);
 
-our $VERSION = '0.08';
+our $VERSION = '0.17';
 
 require XSLoader;
 
index c00237fe354822d8894946989270e93d061cad41..ffd992c44595b0c6c27fce94c47eb4a6706a5913 100644 (file)
--- a/BSSolv.xs
+++ b/BSSolv.xs
@@ -1,3 +1,10 @@
+/*
+ * Copyright (c) 2009 - 2017 SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the same terms as Perl itself.
+ *
+ */
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 
 #define MULTI_SEMANTICS
 
+#include "solvversion.h"
+#if LIBSOLV_VERSION < 623
+#define LIBSOLVEXT_FEATURE_DEBIAN
+#define LIBSOLVEXT_FEATURE_ARCHREPO
+#endif
+
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
 #include "evr.h"
 #include "hash.h"
 #include "chksum.h"
+#include "testcase.h"
 #include "repo_solv.h"
 #include "repo_write.h"
 #include "repo_rpmdb.h"
+#if defined(LIBSOLVEXT_FEATURE_DEBIAN)
 #include "repo_deb.h"
-#if 1
+#endif
+#if defined(LIBSOLVEXT_FEATURE_ARCHREPO)
 #include "repo_arch.h"
 #endif
+#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS)
+#include "pool_parserpmrichdep.h"
+#endif
+
+#ifndef REL_ERROR
+# define REL_ERROR 27          /* for old libsolv versions */
+#endif
+#ifndef REL_UNLESS
+# define REL_UNLESS 29         /* for old libsolv versions */
+#endif
+
+#define EXPANDER_DEBUG_ALL             (1 << 0)
+#define EXPANDER_DEBUG_STDOUT          (1 << 1)
+#define EXPANDER_DEBUG_STR             (1 << 2)
+
+#define EXPANDER_OPTION_IGNOREIGNORE                   (1 << 0)
+#define EXPANDER_OPTION_IGNORECONFLICTS                        (1 << 1)
+#define EXPANDER_OPTION_DORECOMMENDS                   (1 << 2)
+#define EXPANDER_OPTION_DOSUPPLEMENTS                  (1 << 3)
+#define EXPANDER_OPTION_USERECOMMENDSFORCHOICES                (1 << 4)
+#define EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES       (1 << 5)
 
 typedef struct _Expander {
   Pool *pool;
@@ -38,17 +75,54 @@ typedef struct _Expander {
   Queue conflictsq;
   Map conflicts;
 
-  int debug;
   int havefileprovides;
-  int ignoreconflicts;
-  int ignoreignore;
 
+  /* debug support */
+  int debug;
   char *debugstr;
   int debugstrl;
   int debugstrf;
+
+  /* options */
+  int ignoreconflicts;
+  int ignoreignore;
   int userecommendsforchoices;
+  int usesupplementsforchoices;
+  int dorecommends;
+  int dosupplements;
 } Expander;
 
+typedef struct _ExpanderCtx {
+  Pool *pool;
+  Expander *xp;
+  Queue *out;                  /* the result */
+  Map installed;               /* installed packages */
+  Map conflicts;               /* conflicts from installed packages */
+  Queue conflictsinfo;         /* source info for the above */
+  int cidone;                  /* conflictsinfo done position */
+  Queue todo;                  /* requires todo list */
+  Queue errors;                        /* expansion errors */
+  Queue cplxq;                 /* complex dep work queue */
+  Queue cplxblks;              /* complex dep block data, add only */
+  Queue todo_cond;             /* delayed requires/conflicts */
+  Queue pruneq;                        /* multi purpose queue for pruning packages */
+  Map todo_condmap;            /* all neg packages in todo_cond blocks */
+  Map recommended;             /* recommended packages */
+  int recdone;                 /* recommended done position */
+
+  /* options */
+  int ignoreconflicts;
+  int ignoreignore;
+  int userecommendsforchoices;
+  int usesupplementsforchoices;
+  int dorecommends;
+  int dosupplements;
+
+  /* hacks */
+  Solvable *ignore_s;          /* small hack: ignore requires of this solvable */
+} ExpanderCtx;
+
+
 typedef Pool *BSSolv__pool;
 typedef Repo *BSSolv__repo;
 typedef Expander *BSSolv__expander;
@@ -57,8 +131,14 @@ static Id buildservice_id;
 static Id buildservice_repocookie;
 static Id buildservice_external;
 static Id buildservice_dodurl;
-static Id expander_directdepsend;
 static Id buildservice_dodcookie;
+static Id buildservice_dodresources;
+static Id buildservice_annotation;
+static Id buildservice_modules;
+static Id expander_directdepsend;
+
+static int genmetaalgo;
+static int depsortsccs;
 
 /* make sure bit n is usable */
 #define MAPEXP(m, n) ((m)->size < (((n) + 8) >> 3) ? map_grow(m, n + 256) : 0)
@@ -149,7 +229,7 @@ id2name(Pool *pool, Id id)
 }
 
 static Id
-dep2id(Pool *pool, char *s)
+dep2id_rec(Pool *pool, char *s)
 {
   char *n;
   Id id;
@@ -157,17 +237,26 @@ dep2id(Pool *pool, char *s)
 
   if ((n = strchr(s, '|')) != 0)
     {
-      id = dep2id(pool, n + 1);
+      id = dep2id_rec(pool, n + 1);
       *n = 0;
-      id = pool_rel2id(pool, dep2id(pool, s), id, REL_OR, 1);
+      id = pool_rel2id(pool, dep2id_rec(pool, s), id, REL_OR, 1);
       *n = '|';
       return id;
     }
   while (*s == ' ' || *s == '\t')
     s++;
   n = s;
-  while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
-    s++;
+  if (pool->disttype == DISTTYPE_RPM)
+    {
+      /* rpm delimits the name by whitespace only */
+      while (*s && *s != ' ' && *s != '\t')
+        s++;
+    }
+  else
+    {
+      while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
+        s++;
+    }
 #ifdef REL_MULTIARCH
   if (s - n > 4 && s[-4] == ':' && !strncmp(s - 4, ":any", 4))
     {
@@ -185,13 +274,13 @@ dep2id(Pool *pool, char *s)
   for (;;s++)
     {
       if (*s == '<')
-       flags |= REL_LT;
+       flags |= REL_LT;
       else if (*s == '=')
-       flags |= REL_EQ;
+       flags |= REL_EQ;
       else if (*s == '>')
-       flags |= REL_GT;
+       flags |= REL_GT;
       else
-       break;
+       break;
     }
   if (!flags)
     return id;
@@ -203,11 +292,38 @@ dep2id(Pool *pool, char *s)
   return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1);
 }
 
-static inline Offset
+static Id
+parsedep_error(Pool *pool, const char *s)
+{
+  Id id;
+  id = pool_str2id(pool, s, 1);
+  return pool_rel2id(pool, pool_str2id(pool, "dependency parse error", 1), id, REL_ERROR, 1);
+}
+
+static Id
+dep2id(Pool *pool, char *s)
+{
+  Id id;
+  if (pool->disttype == DISTTYPE_RPM && *s == '(')
+    {
+#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS)
+      id = pool_parserpmrichdep(pool, s);
+#else
+      id = 0;
+#endif
+    }
+  else
+    id = dep2id_rec(pool, s);
+  if (!id)
+    id = parsedep_error(pool, s);
+  return id;
+}
+
+static Offset
 importdeps(HV *hv, const char *key, int keyl, Repo *repo)
 {
   Pool *pool = repo->pool;
-  int i;
+  SSize_t i;
   AV *av = hvlookupav(hv, key, keyl);
   Offset off = 0;
   if (av)
@@ -216,13 +332,18 @@ importdeps(HV *hv, const char *key, int keyl, Repo *repo)
        {
          char *str = avlookupstr(av, i);
          if (str)
-           off = repo_addid_dep(repo, off, dep2id(pool, str), 0);
+           {
+             Id id = testcase_str2dep(pool, str);
+             if (!id)
+               id = parsedep_error(pool, str);
+             off = repo_addid_dep(repo, off, id, 0);
+           }
        }
     }
   return off;
 }
 
-void
+static void
 exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
 {
   Pool *pool = repo->pool;
@@ -238,64 +359,7 @@ exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
     {
       if (id == SOLVABLE_FILEMARKER)
        break;
-      str = pool_dep2str(pool, id);
-      if (ISRELDEP(id))
-       {
-         Reldep *rd = GETRELDEP(pool, id);
-         if (skey == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
-           {
-           if (!strncmp(str, "namespace:", 10))
-             str += 10;
-           }
-         if (skey == SOLVABLE_SUPPLEMENTS)
-           {
-             if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM)
-               {
-                 if (!strncmp(str, "namespace:", 10))
-                   str += 10;
-               }
-             else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS)
-               {
-                 if (!strncmp(str, "namespace:", 10))
-                   str += 10;
-               }
-             else if (rd->flags == REL_AND)
-               {
-                 /* either packageand chain or modalias */
-                 str = 0;
-                 if (ISRELDEP(rd->evr))
-                   {
-                     Reldep *mrd = GETRELDEP(pool, rd->evr);
-                     if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS)
-                       {
-                         str = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":");
-                         str = pool_tmpappend(pool, str, pool_dep2str(pool, mrd->evr), ")");
-                       }
-                     else if (mrd->flags >= 8)
-                       continue;
-                   }
-                 if (!str)
-                   {
-                     /* must be and chain */
-                     str = pool_dep2str(pool, rd->evr);
-                     for (;;)
-                       {
-                         id = rd->name;
-                         if (!ISRELDEP(id))
-                           break;
-                         rd = GETRELDEP(pool, id);
-                         if (rd->flags != REL_AND)
-                           break;
-                         str = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", str);
-                       }
-                     str = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", str);
-                     str = pool_tmpjoin(pool, "packageand(", str, ")");
-                   }
-               }
-             else if (rd->flags >= 8)
-               continue;
-           }
-       }
+      str = testcase_dep2str(pool, id);
       if (skey == SOLVABLE_REQUIRES)
        {
          if (id == SOLVABLE_PREREQMARKER)
@@ -311,104 +375,179 @@ exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
     (void)hv_store(hv, key, keyl, newRV_noinc((SV*)av), 0);
 }
 
-void
-data2solvables(Repo *repo, Repodata *data, HV *rhv)
+static int
+data2pkg(Repo *repo, Repodata *data, HV *hv, int isdod)
 {
   Pool *pool = repo->pool;
-  SV *sv;
-  HV *hv;
-  char *str, *key;
-  I32 keyl;
+  char *str;
   Id p;
   Solvable *s;
+  AV *av;
 
-  hv_iterinit(rhv);
-  while ((sv = hv_iternextsv(rhv, &key, &keyl)) != 0)
+  str = hvlookupstr(hv, "name", 4);
+  if (!str)
+    return 0;  /* need to have a name */
+  p = repo_add_solvable(repo);
+  s = pool_id2solvable(pool, p);
+  s->name = pool_str2id(pool, str, 1);
+  str = hvlookupstr(hv, "arch", 4);
+  if (!str)
+    str = "";  /* dummy, need to have arch */
+  s->arch = pool_str2id(pool, str, 1);
+  s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
+  str = hvlookupstr(hv, "path", 4);
+  if (str)
     {
-      if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
-       continue;
-      hv = (HV *)SvRV(sv);
-      str = hvlookupstr(hv, "name", 4);
-      if (!str)
-       continue;       /* need to have a name */
-      p = repo_add_solvable(repo);
-      s = pool_id2solvable(pool, p);
-      s->name = pool_str2id(pool, str, 1);
-      str = hvlookupstr(hv, "arch", 4);
-      if (!str)
-       str = "";       /* dummy, need to have arch */
-      s->arch = pool_str2id(pool, str, 1);
-      s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
-      str = hvlookupstr(hv, "path", 4);
-      if (str)
+      char *ss = strrchr(str, '/');
+      if (ss)
        {
-         char *ss = strrchr(str, '/');
-         if (ss)
-           {
-             *ss = 0;
-             repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
-             *ss++ = '/';
-           }
-         else
-           ss = str;
-         repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
+         *ss = 0;
+         repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
+         *ss++ = '/';
        }
+      else
+       ss = str;
+      repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
+    }
+  if (isdod)
+    repodata_set_str(data, p, buildservice_id, "dod");
+  else
+    {
       str = hvlookupstr(hv, "id", 2);
       if (str)
        repodata_set_str(data, p, buildservice_id, str);
-      str = hvlookupstr(hv, "source", 6);
-      if (str)
-       repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
+    }
+  str = hvlookupstr(hv, "source", 6);
+  if (str)
+    repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
+  if (isdod)
+    {
+      static unsigned char dod_pkgid[16] = { 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0 };
+      repodata_set_bin_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, dod_pkgid);
+    }
+  else
+    {
       str = hvlookupstr(hv, "hdrmd5", 6);
       if (str && strlen(str) == 32)
        repodata_set_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, str);
-      s->provides    = importdeps(hv, "provides", 8, repo);
-      s->obsoletes   = importdeps(hv, "obsoletes", 9, repo);
-      s->conflicts   = importdeps(hv, "conflicts", 9, repo);
-      s->requires    = importdeps(hv, "requires", 8, repo);
-      s->recommends  = importdeps(hv, "recommends", 10, repo);
-      s->suggests    = importdeps(hv, "suggests", 8, repo);
-      s->supplements = importdeps(hv, "supplements", 11, repo);
-      s->enhances    = importdeps(hv, "enhances", 8, repo);
-      if (!s->evr && s->provides)
-       {
-         /* look for self provides */
-         Id pro, *prop = s->repo->idarraydata + s->provides;
-         while ((pro = *prop++) != 0)
-           {
-             Reldep *rd;
-             if (!ISRELDEP(pro))
-               continue;
-             rd = GETRELDEP(pool, pro);
-             if (rd->name == s->name && rd->flags == REL_EQ)
-               s->evr = rd->evr;
-           }
+    }
+  s->provides    = importdeps(hv, "provides", 8, repo);
+  s->obsoletes   = importdeps(hv, "obsoletes", 9, repo);
+  s->conflicts   = importdeps(hv, "conflicts", 9, repo);
+  s->requires    = importdeps(hv, "requires", 8, repo);
+  s->recommends  = importdeps(hv, "recommends", 10, repo);
+  s->suggests    = importdeps(hv, "suggests", 8, repo);
+  s->supplements = importdeps(hv, "supplements", 11, repo);
+  s->enhances    = importdeps(hv, "enhances", 8, repo);
+  if (!s->evr && s->provides)
+    {
+      /* look for self provides */
+      Id pro, *prop = s->repo->idarraydata + s->provides;
+      while ((pro = *prop++) != 0)
+       {
+         Reldep *rd;
+         if (!ISRELDEP(pro))
+           continue;
+         rd = GETRELDEP(pool, pro);
+         if (rd->name == s->name && rd->flags == REL_EQ)
+           s->evr = rd->evr;
+       }
+    }
+  if (s->evr && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+  str = hvlookupstr(hv, "checksum", 8);
+  if (str)
+    {
+      char *cp, typebuf[8];
+      Id ctype;
+      if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
+       {
+         strncpy(typebuf, str, cp - str);
+         typebuf[cp - str] = 0;
+         ctype = solv_chksum_str2type(typebuf);
+         if (ctype)
+           repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
+       }
+    }
+  str = hvlookupstr(hv, "annotation", 10);
+  if (str && strlen(str) < 100000)
+    repodata_set_str(data, p, buildservice_annotation, str);
+  av = hvlookupav(hv, "modules", 7);
+  if (av)
+    {
+      SSize_t i;
+      for (i = 0; i <= av_len(av); i++)
+       {
+         char *str = avlookupstr(av, i);
+         repodata_add_idarray(data, p, buildservice_modules, pool_str2id(pool, str, 1));
+       }
+    }
+  return p;
+}
+
+static void
+data2solvables(Repo *repo, Repodata *data, SV *rsv, int isdod)
+{
+  AV *rav = 0;
+  SSize_t ravi = 0;
+  HV *rhv = 0;
+  SV *sv;
+  char *key;
+  I32 keyl;
+
+  if (SvTYPE(rsv) == SVt_PVAV)
+    rav = (AV *)rsv;
+  else
+    rhv = (HV *)rsv;
+
+  if (rhv)
+    hv_iterinit(rhv);
+  for (;;)
+    {
+      if (rhv)
+       {
+         sv = hv_iternextsv(rhv, &key, &keyl);
+         if (!sv)
+           break;
+       }
+      else
+       {
+         SV **svp;
+         if (ravi > av_len(rav))
+           break;
+         svp = av_fetch(rav, ravi++, 0);
+         if (!svp || !*svp)
+           continue;
+         sv = *svp;
        }
-      if (s->evr)
-       s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-      str = hvlookupstr(hv, "checksum", 8);
+      if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
+       continue;
+      data2pkg(repo, data, (HV *)SvRV(sv), isdod);
+    }
+
+  /* set meta information */
+  repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
+  if (rhv)
+    {
+      char *str;
+      AV *av;
+      str = hvlookupstr(rhv, "/url", 4);
       if (str)
+       repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
+      str = hvlookupstr(rhv, "/dodcookie", 10);
+      if (str)
+       repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
+      av = hvlookupav(rhv, "/dodresources", 13);
+      if (av)
        {
-         char *cp, typebuf[8];
-         Id ctype;
-         if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
+         SSize_t i;
+         for (i = 0; i <= av_len(av); i++)
            {
-             strncpy(typebuf, str, cp - str);
-             typebuf[cp - str] = 0;
-             ctype = solv_chksum_str2type(typebuf);
-             if (ctype)
-               repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
+             Id id = pool_str2id(repo->pool, avlookupstr(av, i), 1);
+             repodata_add_idarray(data, SOLVID_META, buildservice_dodresources, id);
            }
        }
     }
-
-  repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
-  str = hvlookupstr(rhv, "/url", 4);
-  if (str)
-    repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
-  str = hvlookupstr(rhv, "/dodcookie", 10);
-  if (str)
-    repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
 }
 
 static SV *
@@ -524,133 +663,895 @@ retrieve(unsigned char **srcp, STRLEN *srclp, int depth)
   return sv;
 }
 
-static void
-expander_dbg(Expander *xp, const char *format, ...)
+#define CPLXDEPS_TODNF (1 << 0)
+
+static int
+invert_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r)
 {
-  va_list args;
-  char buf[1024];
-  int l;
-  if (!xp->debug)
-    return;
-  va_start(args, format);
-  vsnprintf(buf, sizeof(buf), format, args);
-  va_end(args);
-  printf("%s", buf);
-  l = strlen(buf);
-  if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
-    fflush(stdout);
-  if (l >= xp->debugstrf)      /* >= because of trailing \0 */
+  int i, j, end;
+  if (r == 0 || r == 1)
+    return r ? 0 : 1;
+  end = bq->count;
+  for (i = j = start; i < end; i++)
     {
-      xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
-      xp->debugstrf = l + 1024;
+      if (bq->elements[i])
+        {
+          bq->elements[i] = -bq->elements[i];
+          continue;
+        }
+      /* end of block reached, reverse */
+      if (i - 1 > j)
+        {
+          int k;
+          for (k = i - 1; j < k; j++, k--)
+            {
+              Id t = bq->elements[j];
+              bq->elements[j] = bq->elements[k];
+              bq->elements[k] = t;
+            }
+        }
+      j = i + 1;
     }
-  strcpy(xp->debugstr + xp->debugstrl, buf);
-  xp->debugstrl += l;
-  xp->debugstrf -= l;
-}
-
-static const char *
-expander_solvid2name(Expander *xp, Id p)
-{
-  const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
-  Repo *r; 
-  if (!xp->debug)
-    return n;
-  r = xp->pool->solvables[p].repo;
-  if (!r) 
-    return n;
-  return pool_tmpjoin(xp->pool, n, "@", r->name);
+  return -1;
 }
 
-static inline void
-expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *conflictsinfo, int *cidone, Queue *out, Queue *todo)
+static int
+distribute_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int start2, int flags)
 {
-  Pool *pool = xp->pool;
-  Solvable *s = pool->solvables + p;
-  Id req, id, *reqp, con, *conp;
-  const char *n;
-
-  MAPSET(installed, p);
-  queue_push(out, p);
-  if (MAPTST(&xp->conflicts, s->name))
-    {
-      int i;
-      for (i = 0; i < xp->conflictsq.count; i++)
-       {
-         Id p2, pp2;
-         Id id = xp->conflictsq.elements[i];
-         if (id != s->name)
-           continue;
-         id = xp->conflictsq.elements[i ^ 1];
-         FOR_PROVIDES(p2, pp2, id)
-           {
-             if (pool->solvables[p2].name == id)
-               {
-                 MAPEXP(conflicts, pool->nsolvables);
-                 MAPSET(conflicts, p2);
-               }
-           }
-       }
-    }
-  if (s->requires)
+  int i, j, end2 = bq->count;
+  for (i = start; i < start2; i++)
     {
-      reqp = s->repo->idarraydata + s->requires;
-      while ((req = *reqp++) != 0)
+      for (j = start2; j < end2; j++)
        {
-         if (req == SOLVABLE_PREREQMARKER)
-           continue;
-         id = id2name(pool, req);
-         if (!xp->ignoreignore)
+         int a, b;
+         int bqcnt4 = bq->count;
+         int k = i;
+
+         /* distribute i block with j block, both blocks are sorted */
+         while (bq->elements[k] && bq->elements[j])
            {
-             if (MAPTST(&xp->ignored, id))
-               continue;
-             if (MAPTST(&xp->ignoredx, id))
+             if (bq->elements[k] < bq->elements[j])
+               queue_push(bq, bq->elements[k++]);
+             else
                {
-                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
-                 if (xid && MAPTST(&xp->ignored, xid))
-                   continue;
+                 if (bq->elements[k] == bq->elements[j])
+                   k++;
+                 queue_push(bq, bq->elements[j++]);
                }
            }
-         n = pool_id2str(pool, id);
-         if (!strncmp(n, "rpmlib(", 7))
-           {
-             MAPEXP(&xp->ignored, id);
-             MAPSET(&xp->ignored, id);
-             continue;
-           }
-         if (*n == '/')
+         while (bq->elements[j])
+           queue_push(bq, bq->elements[j++]);
+         while (bq->elements[k])
+           queue_push(bq, bq->elements[k++]);
+
+         /* block is finished, check for A + -A */
+         for (a = bqcnt4, b = bq->count - 1; a < b; )
            {
-             if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
-               {
-                 MAPEXP(&xp->ignored, id);
-                 MAPSET(&xp->ignored, id);
-                 continue;
-               }
+             if (-bq->elements[a] == bq->elements[b])
+               break;
+             if (-bq->elements[a] > bq->elements[b])
+               a++;
+             else
+               b--;
            }
-         queue_push2(todo, req, p);
+         if (a < b)
+           queue_truncate(bq, bqcnt4);     /* ignore this block */
+         else
+           queue_push(bq, 0);      /* finish block */
        }
+      /* advance to next block */
+      while (bq->elements[i])
+       i++;
     }
-  if (!xp->ignoreconflicts)
+  queue_deleten(bq, start, end2 - start);
+  if (start == bq->count)
+    return flags & CPLXDEPS_TODNF ? 0 : 1;
+  return -1;
+}
+
+#if 0
+static void
+print_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r)
+{
+  Pool *pool = xpctx->pool;
+  int i;
+
+  if (r == 0)
     {
-      if (s->conflicts)
-       {
-         conp = s->repo->idarraydata + s->conflicts;
-         while ((con = *conp++) != 0)
-           {
-             Id p2, pp2;
-             FOR_PROVIDES(p2, pp2, con)
-               {
-                 if (p2 == p)
-                   continue;
-                 MAPEXP(conflicts, pool->nsolvables);
-                 MAPSET(conflicts, p2);
-                 if (xp->debug)
-                   queue_push2(conflictsinfo, p2, p);
-               }
-           }
-       }
-      if (s->obsoletes)
-       {
+      printf("[NONE]\n");
+      return;
+    }
+  if (r == 1)
+    {
+      printf("[ALL]\n");
+      return;
+    }
+  for (i = start; i < bq->count; i++)
+    {
+      if (bq->elements[i] > 0)
+        printf(" %s", pool_solvid2str(pool, bq->elements[i]));
+      else if (bq->elements[i] < 0)
+        printf(" -%s", pool_solvid2str(pool, -bq->elements[i]));
+      else
+        printf(" ||");
+    }
+  printf("\n");
+}
+#endif
+
+
+static int
+pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
+{
+  for (;;)
+    {
+      if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS)        /* those are the complex ones */
+        return 1;
+      if (rd->flags != REL_OR)
+        return 0;
+      if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name)))
+        return 1;
+      if (!ISRELDEP(rd->evr))
+        return 0;
+      rd = GETRELDEP(pool, rd->evr);
+    }
+}
+
+static inline int
+pool_is_complex_dep(Pool *pool, Id dep)
+{
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags >= 8 && pool_is_complex_dep_rd(pool, rd))
+        return 1;
+    }
+  return 0;
+}
+
+static int normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags);
+
+static int
+normalize_dep_or(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep(xpctx, dep1, bq, flags);
+  if (r1 == 1)
+    return 1;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags);
+  if (invflags)
+    r2 = invert_depblocks(xpctx, bq, bqcnt2, r2);
+  if (r1 == 1 || r2 == 1)
+    {
+      queue_truncate(bq, bqcnt);
+      return 1;
+    }
+  if (r1 == 0)
+    return r2;
+  if (r2 == 0)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) == 0)
+    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int
+normalize_dep_and(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep(xpctx, dep1, bq, flags);
+  if (r1 == 0)
+    return 0;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags);
+  if (invflags)
+    r2 = invert_depblocks(xpctx, bq, bqcnt2, r2);
+  if (r1 == 0 || r2 == 0)
+    {
+      queue_truncate(bq, bqcnt);
+      return 0;
+    }
+  if (r1 == 1)
+    return r2;
+  if (r2 == 1)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) != 0)
+    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int
+normalize_dep_if_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+  /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep_or(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+  if (r1 == 0)
+    return 0;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep_or(xpctx, dep2, dep3, bq, flags, 0);
+  if (r1 == 0 || r2 == 0)
+    {
+      queue_truncate(bq, bqcnt);
+      return 0;
+    }
+  if (r1 == 1)
+    return r2;
+  if (r2 == 1)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) != 0)
+    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int
+normalize_dep_unless_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+  /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep_and(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+  if (r1 == 1)
+    return 1;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep_and(xpctx, dep2, dep3, bq, flags, 0);
+  if (r1 == 1 || r2 == 1)
+    {
+      queue_truncate(bq, bqcnt);
+      return 1;
+    }
+  if (r1 == 0)
+    return r2;
+  if (r2 == 0)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) == 0)
+    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int expander_isignored(Expander *xp, Solvable *s, Id req);
+
+static int
+normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags)
+{
+  Pool *pool = xpctx->pool;
+  Id p, dp;
+  
+  if (pool_is_complex_dep(pool, dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND)
+       {
+         Id evr = rd->evr;
+         if (ISRELDEP(evr))
+           {
+             Reldep *rd2 = GETRELDEP(pool, evr);
+             if (rd2->flags == REL_ELSE)
+               return normalize_dep_if_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags);
+           }
+         return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+       }
+      if (rd->flags == REL_UNLESS)
+       {
+         Id evr = rd->evr;
+         if (ISRELDEP(evr))
+           {
+             Reldep *rd2 = GETRELDEP(pool, evr);
+             if (rd2->flags == REL_ELSE)
+               return normalize_dep_unless_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags);
+           }
+         return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+       }
+      if (rd->flags == REL_OR)
+       return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, 0);
+      if (rd->flags == REL_AND)
+       return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, 0);
+    }
+
+  if (xpctx->ignore_s && (flags & CPLXDEPS_TODNF) == 0)
+    {
+      if (expander_isignored(xpctx->xp, xpctx->ignore_s, dep))
+       return 1;
+    }
+
+  dp = pool_whatprovides(pool, dep);
+  if (dp == 2)
+    return 1;
+  if (dp < 2 || !pool->whatprovidesdata[dp])
+    return 0;
+  if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
+    return 1;
+  if ((flags & CPLXDEPS_TODNF) != 0)
+    {
+      while ((p = pool->whatprovidesdata[dp++]) != 0)
+        queue_push2(bq, p, 0);
+    }
+  else
+    {
+      while ((p = pool->whatprovidesdata[dp++]) != 0)
+        queue_push(bq, p);
+      queue_push(bq, 0);
+    }
+  return -1;
+}
+
+#define ISCPLX(pool, d) (ISRELDEP(d) && GETRELID(d) >= pool->nrels)
+#define GETCPLX(pool, d) (GETRELID(d) - pool->nrels)
+#define MAKECPLX(pool, d) (MAKERELDEP(pool->nrels + d))
+
+#define DEPTYPE_REQUIRES               0
+#define DEPTYPE_CONFLICTS              1
+#define DEPTYPE_OBSOLETES              2
+#define DEPTYPE_RECOMMENDS             3
+#define DEPTYPE_PROVIDES               4
+
+#define ERROR_NOPROVIDER               1
+#define ERROR_CHOICE                   2
+#define ERROR_CONFLICTINGPROVIDERS     3
+#define ERROR_PROVIDERINFO             4
+#define ERROR_PROVIDERINFO2            5
+#define ERROR_BADDEPENDENCY            6
+#define ERROR_CONFLICT                 7
+#define ERROR_CONFLICT2                        8
+#define ERROR_ALLCONFLICT              9
+#define ERROR_NOPROVIDERINFO           10
+
+static void
+expander_dbg(Expander *xp, const char *format, ...)
+{
+  va_list args;
+  char buf[1024];
+  int l;
+
+  if (!xp->debug)
+    return;
+  va_start(args, format);
+  vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  l = strlen(buf);
+  if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STDOUT)) != 0)
+    {
+      printf("%s", buf);
+      if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
+        fflush(stdout);
+    }
+  if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STR)) != 0)
+    {
+      if (l >= xp->debugstrf)  /* >= because of trailing \0 */
+       {
+         xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
+         xp->debugstrf = l + 1024;
+       }
+      strcpy(xp->debugstr + xp->debugstrl, buf);
+      xp->debugstrl += l;
+      xp->debugstrf -= l;
+    }
+}
+
+static void
+expander_clrdbg(Expander *xp)
+{
+  if (xp->debugstr)
+    free(xp->debugstr);
+  xp->debugstr = 0;
+  xp->debugstrl = xp->debugstrf = 0;
+}
+
+static const char *
+expander_solvid2name(Expander *xp, Id p)
+{
+  const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
+  Repo *r; 
+  if (!xp->debug)
+    return n;
+  r = xp->pool->solvables[p].repo;
+  if (!r) 
+    return n;
+  return pool_tmpjoin(xp->pool, n, "@", r->name);
+}
+
+static const char *
+expander_solvid2str(Expander *xp, Id p)
+{
+  const char *n = pool_solvid2str(xp->pool, p);
+  Repo *r; 
+  if (!xp->debug)
+    return n;
+  r = xp->pool->solvables[p].repo;
+  if (!r) 
+    return n;
+  return pool_tmpjoin(xp->pool, n, "@", r->name);
+}
+
+static int
+pkgname_sort_cmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = (Pool *)dp;
+  Id a = *(Id *)ap;
+  Id b = *(Id *)bp;
+  return strcmp(pool_id2str(pool, pool->solvables[a].name), pool_id2str(pool, pool->solvables[b].name));
+}
+
+static int
+expander_isignored(Expander *xp, Solvable *s, Id req)
+{
+  Pool *pool = xp->pool;
+  Id id = id2name(pool, req);
+  const char *n;
+
+  if (!xp->ignoreignore)
+    {
+      if (MAPTST(&xp->ignored, id))
+       return 1;
+      if (MAPTST(&xp->ignoredx, id))
+       {
+         Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
+         if (xid && MAPTST(&xp->ignored, xid))
+           return 1;
+       }
+    }
+  n = pool_id2str(pool, id);
+  if (!strncmp(n, "rpmlib(", 7))
+    {
+      MAPEXP(&xp->ignored, id);
+      MAPSET(&xp->ignored, id);
+      return 1;
+    }
+  if (*n == '/')
+    {
+      if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
+       {
+         MAPEXP(&xp->ignored, id);
+         MAPSET(&xp->ignored, id);
+         return 1;
+       }
+    }
+  return 0;
+}
+
+static int
+expander_to_cplxblks(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr)
+{
+  int blkoff = xpctx->cplxblks.count;
+  queue_push(&xpctx->cplxblks, p);
+  queue_push(&xpctx->cplxblks, dep);
+  queue_push(&xpctx->cplxblks, deptype);
+  for (;;)
+    {
+      Id pp = *ptr++;
+      queue_push(&xpctx->cplxblks, pp);
+      if (!pp)
+       break;
+    }
+  return blkoff;
+}
+
+static int
+expander_check_cplxblock(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr, int blkoff)
+{
+  Pool *pool = xpctx->pool;
+  int posn = 0, posi = 0, negn = 0, negi = 0;
+  Id pp, *ptr2 = ptr;
+  Id lastcon = 0;
+
+  while ((pp = *ptr2++) != 0)
+    {
+      if (pp > 0)
+       {
+         posn++;
+         if (MAPTST(&xpctx->installed, pp))
+           posi++;
+       }
+      else
+       {
+         if (p == -pp)
+           continue;   /* ignore redundant self-entry */
+         negn++;
+         if (MAPTST(&xpctx->installed, -pp))
+           negi++;
+         else
+           lastcon = -pp;
+       }
+    }
+#if 0
+  printf("expander_check_cplxblock pos: %d,%d neg: %d,%d\n", posn, posi, negn, negi);
+#endif
+  if (posi)
+    return -1;
+  if (!posn && deptype == DEPTYPE_RECOMMENDS)
+    return -1;
+  if (negi == negn)
+    {
+      /* all neg installed */
+      if (posn)
+       {
+         /* posn > 0 and all neg installed, add to todo */
+         if (blkoff < 0)
+           blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr);
+#if 0
+         printf("put on todo, blkoff = %d\n", blkoff);
+#endif
+         queue_push2(&xpctx->todo, MAKECPLX(pool, blkoff), p);
+       }
+      else
+       {
+         /* no posn, conflict */
+         for (ptr2 = ptr; (pp = *ptr2++) != 0; )
+           {
+             if (p == -pp)
+               continue;       /* ignore redundant self-entry */
+             if (deptype == DEPTYPE_REQUIRES)
+               {
+                 /* do not report a requires as conflicts */
+                 queue_push(&xpctx->errors, ERROR_NOPROVIDER);
+                 queue_push2(&xpctx->errors, dep, p);
+                 break;
+               }
+             queue_push(&xpctx->errors, ERROR_CONFLICT);
+             queue_push2(&xpctx->errors, p, -pp);
+           }
+       }
+      return -1;
+    }
+  else if (!posn && negn && negi == negn - 1)
+    {
+      /* add conflict */
+#if 0
+      printf("add conflict %d %d\n", lastcon, p);
+#endif
+      MAPEXP(&xpctx->conflicts, pool->nsolvables);
+      MAPSET(&xpctx->conflicts, lastcon);
+      if (p)
+        queue_push2(&xpctx->conflictsinfo, lastcon, p);        /* always do this for rich deps */
+      return -1;
+    }
+  else
+    {
+#ifdef DEBUG_COND
+      printf("put/stay on cond queue, blkoff = %d\n", blkoff);
+#endif
+      /* either posn > 0 and 1 neg not installed or more than 1 neg not installed */
+      if (blkoff < 0)
+       blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr);
+      return blkoff;
+    }
+}
+
+static void
+expander_installed_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype)
+{
+  Queue *cplxq = &xpctx->cplxq;
+  int r, i, start = cplxq->count, blkoff;
+
+#if 0
+  printf("expander_installed_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype);
+#endif
+  if (deptype == DEPTYPE_CONFLICTS)
+    {
+      r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF);
+      r = invert_depblocks(xpctx, cplxq, start, r);
+    }
+  else
+    r = normalize_dep(xpctx, dep, cplxq, 0);
+#if 0
+  print_depblocks(xpctx, cplxq, start, r);
+#endif
+  if (r == 1)
+    return;
+  if (r == 0)
+    {
+      if (deptype == DEPTYPE_CONFLICTS)
+       {
+         queue_push(&xpctx->errors, ERROR_ALLCONFLICT);
+         queue_push2(&xpctx->errors, dep, p);
+       }
+      else if (deptype != DEPTYPE_RECOMMENDS)
+       {
+         queue_push(&xpctx->errors, ERROR_NOPROVIDER);
+         queue_push2(&xpctx->errors, dep, p);
+       }
+      return;
+    }
+  while (start < cplxq->count)
+    {
+      /* find end */
+      for (i = start; cplxq->elements[i] != 0; i++)
+       ;
+      blkoff = expander_check_cplxblock(xpctx, p, dep, deptype, cplxq->elements + start, -1);
+      if (blkoff >= 0)
+       {
+         Pool *pool = xpctx->pool;
+         Id p;
+         MAPEXP(&xpctx->todo_condmap, pool->nsolvables);
+         for (i = start; (p = cplxq->elements[i]) != 0; i++)
+           if (p < 0)
+             MAPSET(&xpctx->todo_condmap, -p);
+         queue_push(&xpctx->todo_cond, blkoff);
+       }
+      start = i + 1;
+    }
+  queue_truncate(cplxq, start);
+}
+
+static int
+expander_checkconflicts_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype, int recorderrors)
+{
+  Queue *cplxq = &xpctx->cplxq;
+  int r, i, start = cplxq->count;
+  Id pp;
+  int ret = 0;
+
+#if 0
+  printf("expander_checkconflicts_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype);
+#endif
+  if (deptype == DEPTYPE_CONFLICTS)
+    {
+      r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF);
+      r = invert_depblocks(xpctx, cplxq, start, r);
+    }
+  else
+    r = normalize_dep(xpctx, dep, cplxq, 0);
+#if 0
+  print_depblocks(xpctx, cplxq, start, r);
+#endif
+  /* r == 0: conflict with everything. Ignore here, pick error up when package gets installed */
+  if (r == 0 || r == 1)
+    return 0;
+  while (start < cplxq->count)
+    {
+      for (i = start; (pp = cplxq->elements[i]) != 0; i++)
+        if (pp > 0 || (pp < 0 && !MAPTST(&xpctx->installed, -pp)))
+         break;
+      if (pp == 0)
+       {
+         /* no pos and all neg installed -> conflict */
+         for (i = start; (pp = cplxq->elements[i]) != 0; i++)
+           {
+             pp = -cplxq->elements[i];
+             if (recorderrors)
+               {
+                 queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO);
+                 queue_push2(&xpctx->errors, p, pp);
+               }
+             else if (xpctx->xp->debug)
+               {
+                 Pool *pool = xpctx->pool;
+                 expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, pp));
+               }
+             ret = ret ? 1 : pp;
+           }
+       }
+      for (; cplxq->elements[i] != 0; i++)
+       ;
+      start = i + 1;
+    }
+  queue_truncate(cplxq, start);
+  return ret;
+}
+
+static void
+updateconflictsinfo(ExpanderCtx *xpctx)
+{
+  int i;
+  Pool *pool = xpctx->pool;
+  Queue *out = xpctx->out;
+  Queue *conflictsinfo = &xpctx->conflictsinfo;
+
+  if (xpctx->ignoreconflicts)
+    return;
+  for (i = xpctx->cidone; i < out->count; i++)
+    {
+      Id p, p2, pp2;
+      Id con, *conp;
+      Solvable *s;
+      p = out->elements[i];
+      s = pool->solvables + p;
+      /* keep in sync with expander_installed! */
+      if (s->conflicts)
+       {
+         conp = s->repo->idarraydata + s->conflicts;
+         while ((con = *conp++) != 0)
+           {
+             if (pool_is_complex_dep(pool, con))
+               continue;       /* already pushed */
+             FOR_PROVIDES(p2, pp2, con)
+               {
+                 if (p2 == p)
+                   continue;
+                 queue_push2(conflictsinfo, p2, p);
+               }
+           }
+       }
+      if (s->obsoletes)
+       {
+         conp = s->repo->idarraydata + s->obsoletes;
+         while ((con = *conp++) != 0)
+           {
+             FOR_PROVIDES(p2, pp2, con)
+               {
+                 if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
+                   continue;
+                 queue_push2(conflictsinfo, p2, -p);
+               }
+           }
+       }
+    }
+  xpctx->cidone = out->count;
+}
+
+static int
+findconflictsinfo(ExpanderCtx *xpctx, Id p, int recorderrors)
+{
+  Queue *conflictsinfo = &xpctx->conflictsinfo;
+  int i, ret = 0;
+
+  if (xpctx->cidone < xpctx->out->count)
+    updateconflictsinfo(xpctx);
+
+  for (i = 0; i < conflictsinfo->count; i++)
+    if (conflictsinfo->elements[i] == p)
+      {
+       ret = conflictsinfo->elements[i + 1];
+       if (recorderrors)
+         {
+           queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2);
+           queue_push2(&xpctx->errors, p, ret);
+         }
+       else if (xpctx->xp->debug)
+         {
+           Pool *pool = xpctx->pool;
+           expander_dbg(xpctx->xp, "ignoring provider %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_solvid2str(pool, ret > 0 ? ret : -ret), ret > 0 ? "conflicts with" : "obsoletes");
+         }
+      }
+  if (!ret)
+    {
+      /* conflict from our job, i.e. a !xxx dep */
+      if (recorderrors)
+       {
+         queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2);
+         queue_push2(&xpctx->errors, p, 0);
+       }
+      else if (xpctx->xp->debug)
+       {
+         Pool *pool = xpctx->pool;
+         expander_dbg(xpctx->xp, "ignoring conflicted provider %s\n", pool_solvid2str(pool, p));
+       }
+    }
+  return ret;
+}
+
+
+static void
+recheck_conddeps(ExpanderCtx *xpctx)
+{
+  int i;
+  for (i = 0; i < xpctx->todo_cond.count; i++)
+    {
+      int blkoff = xpctx->todo_cond.elements[i];
+#ifdef DEBUG_COND
+      printf("todo_cond %d\n", blkoff);
+#endif
+      Id *ptr = xpctx->cplxblks.elements + blkoff;
+      if (expander_check_cplxblock(xpctx, ptr[0], ptr[1], ptr[2], ptr + 3, blkoff) < 0)
+       {
+#ifdef DEBUG_COND
+         printf("remove no longer needed cond entry\n");
+#endif
+         queue_delete(&xpctx->todo_cond, i);
+         i--;
+       }
+    }
+}
+
+/* install a single package */
+static void
+expander_installed(ExpanderCtx *xpctx, Id p)
+{
+  Pool *pool = xpctx->pool;
+  Expander *xp = xpctx->xp;
+  Solvable *s = pool->solvables + p;
+  Id req, *reqp, con, *conp;
+
+#if 0
+printf("expander_installed %s\n", pool_solvid2str(pool, p));
+#endif
+  MAPSET(&xpctx->installed, p);
+  queue_push(xpctx->out, p);
+
+  if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p))
+    findconflictsinfo(xpctx, p, 2);
+
+  /* add synthetic conflicts from the project config */
+  if (MAPTST(&xp->conflicts, s->name))
+    {
+      int i;
+      for (i = 0; i < xp->conflictsq.count; i++)
+       {
+         Id p2, pp2;
+         Id id = xp->conflictsq.elements[i];
+         if (id != s->name)
+           continue;
+         id = xp->conflictsq.elements[i ^ 1];
+         FOR_PROVIDES(p2, pp2, id)
+           {
+             if (pool->solvables[p2].name != id)
+               continue;
+             if (MAPTST(&xpctx->installed, p2))
+               {
+                 queue_push(&xpctx->errors, ERROR_CONFLICT);
+                 queue_push2(&xpctx->errors, p, p2);
+                 continue;
+               }
+             MAPEXP(&xpctx->conflicts, pool->nsolvables);
+             MAPSET(&xpctx->conflicts, p2);
+             queue_push2(&xpctx->conflictsinfo, p2, p);
+           }
+       }
+    }
+
+  if (s->requires)
+    {
+      reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)
+       {
+         if (req == SOLVABLE_PREREQMARKER)
+           continue;
+         if (ISRELDEP(req) && GETRELDEP(pool, req)->flags == REL_ERROR)
+           {
+             queue_push(&xpctx->errors, ERROR_BADDEPENDENCY);
+             queue_push2(&xpctx->errors, GETRELDEP(pool, req)->evr, p);
+             continue;
+           }
+         if (pool_is_complex_dep(pool, req))
+           {
+             xpctx->ignore_s = s;
+             expander_installed_complexdep(xpctx, p, req, DEPTYPE_REQUIRES);
+             xpctx->ignore_s = 0;
+             continue;
+           }
+         if (expander_isignored(xp, s, req))
+           continue;
+         queue_push2(&xpctx->todo, req, p);
+       }
+    }
+  if (!xpctx->ignoreconflicts)
+    {
+      if (s->conflicts)
+       {
+         conp = s->repo->idarraydata + s->conflicts;
+         while ((con = *conp++) != 0)
+           {
+             Id p2, pp2;
+             if (ISRELDEP(con) && GETRELDEP(pool, con)->flags == REL_ERROR)
+               {
+                 queue_push(&xpctx->errors, ERROR_BADDEPENDENCY);
+                 queue_push2(&xpctx->errors, GETRELDEP(pool, con)->evr, p);
+                 continue;
+               }
+             if (pool_is_complex_dep(pool, con))
+               {
+                 expander_installed_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS);
+                 continue;
+               }
+             FOR_PROVIDES(p2, pp2, con)
+               {
+                 if (p2 == p)
+                   continue;
+                 if (MAPTST(&xpctx->installed, p2))
+                   {
+                     queue_push(&xpctx->errors, ERROR_CONFLICT);
+                     queue_push2(&xpctx->errors, p, p2);
+                     continue;
+                   }
+                 MAPEXP(&xpctx->conflicts, pool->nsolvables);
+                 MAPSET(&xpctx->conflicts, p2);
+                 if (xp->debug)
+                   queue_push2(&xpctx->conflictsinfo, p2, p);
+               }
+           }
+       }
+      if (s->obsoletes)
+       {
          conp = s->repo->idarraydata + s->obsoletes;
          while ((con = *conp++) != 0)
            {
@@ -659,28 +1560,77 @@ expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *co
                {
                  if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
                    continue;
-                 MAPEXP(conflicts, pool->nsolvables);
-                 MAPSET(conflicts, p2);
+                 if (MAPTST(&xpctx->installed, p2))
+                   {
+                     queue_push(&xpctx->errors, ERROR_CONFLICT);
+                     queue_push2(&xpctx->errors, p, -p2);
+                     continue;
+                   }
+                 MAPEXP(&xpctx->conflicts, pool->nsolvables);
+                 MAPSET(&xpctx->conflicts, p2);
                  if (xp->debug)
-                   queue_push2(conflictsinfo, p2, -p);
+                   queue_push2(&xpctx->conflictsinfo, p2, -p);
                }
            }
        }
       if (xp->debug)
-       *cidone = out->count;
+       xpctx->cidone = xpctx->out->count;
     }
+  if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p))
+    recheck_conddeps(xpctx);
 }
 
-static inline int
-expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int isobsoletes)
+/* same as expander_installed, but install multiple packages
+ * in one block */
+static void
+expander_installed_multiple(ExpanderCtx *xpctx, Queue *toinstall)
 {
-  Pool *pool = xp->pool;
+  int i, j, havecond = 0;
+
+  /* unify */
+  for (i = j = 0; i < toinstall->count; i++)
+    {
+      Id p = toinstall->elements[i];
+      if (MAPTST(&xpctx->installed, p))
+       continue;       /* already seen */
+      MAPSET(&xpctx->installed, p);
+      toinstall->elements[j++] = p;
+      if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p))
+       {
+         havecond = 1;
+         MAPCLR(&xpctx->todo_condmap, p);      /* no longer needed */
+       }
+    }
+  queue_truncate(toinstall, j);
+  
+  /* run conditionals first */
+  if (havecond)
+    recheck_conddeps(xpctx);
+
+  if (!xpctx->errors.count)
+    for (i = 0; i < toinstall->count; i++)
+      expander_installed(xpctx, toinstall->elements[i]);
+  queue_empty(toinstall);
+}
+
+static int
+expander_checkconflicts(ExpanderCtx *xpctx, Id p, Id *conflicts, int isobsoletes, int recorderrors)
+{
+  Map *installed = &xpctx->installed;
+  Pool *pool = xpctx->pool;
   Id con, p2, pp2;
+  int ret = 0;
 
-  if (xp->ignoreconflicts)
+  if (xpctx->ignoreconflicts)
     return 0;
   while ((con = *conflicts++) != 0)
     {
+      if (!isobsoletes && pool_is_complex_dep(pool, con))
+       {
+         p2 = expander_checkconflicts_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS, recorderrors);
+         ret = ret ? 1 : p2;
+         continue;
+       }
       FOR_PROVIDES(p2, pp2, con)
        {
          if (p == p2)
@@ -688,154 +1638,500 @@ expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int i
          if (isobsoletes && !pool_match_nevr(pool, pool->solvables + p2, con))
            continue;
          if (MAPTST(installed, p2))
-           return p2;
+           {
+             if (recorderrors)
+               {
+                 queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO);
+                 queue_push2(&xpctx->errors, p, isobsoletes ? -p2 : p2);
+               }
+             else if (xpctx->xp->debug)
+               {
+                 if (isobsoletes)
+                   expander_dbg(xpctx->xp, "ignoring provider %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2));
+                 else
+                   expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2));
+               }
+             ret = ret ? 1 : p2;
+           }
        }
     }
-  return 0;
+  return ret;
 }
 
 static void
-expander_updateconflictsinfo(Expander *xp, Queue *conflictsinfo, int *cidone, Queue *out)
+expander_updaterecommendedmap(ExpanderCtx *xpctx)
 {
-  Pool *pool = xp->pool;
+  Pool *pool = xpctx->pool;
+  Queue *out = xpctx->out;
+  Map *recommended = &xpctx->recommended;
+
   int i;
-  if (xp->ignoreconflicts)
-    return;
-  for (i = *cidone; i < out->count; i++)
+  Id p, pp, rec, *recp;
+  for (i = xpctx->recdone; i < out->count; i++)
     {
-      Id p, p2, pp2;
-      Id con, *conp;
       Solvable *s;
-      p = out->elements[i];
-      s = pool->solvables + p;
-      /* keep in sync with expander_installed! */
-      if (s->conflicts)
+      s = pool->solvables + out->elements[i];
+      if (s->recommends)
        {
-         conp = s->repo->idarraydata + s->conflicts;
-         while ((con = *conp++) != 0)
+          MAPEXP(recommended, pool->nsolvables);
+          for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
+           FOR_PROVIDES(p, pp, rec)
+             MAPSET(recommended, p);
+       }
+    }
+  xpctx->recdone = out->count;
+}
+
+static int
+expander_dep_fulfilled(ExpanderCtx *xpctx, Id dep)
+{
+  Pool *pool = xpctx->pool;
+  Id p, pp; 
+
+  if (ISRELDEP(dep))
+    {   
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND)
+       {
+         if (ISRELDEP(rd->evr))
            {
-             FOR_PROVIDES(p2, pp2, con)
+             Reldep *rd2 = GETRELDEP(pool, rd->evr);
+             if (rd2->flags == REL_ELSE)
                {
-                 if (p2 == p)
-                   continue;
-                 queue_push2(conflictsinfo, p2, p);
+                 if (expander_dep_fulfilled(xpctx, rd2->name))
+                   return expander_dep_fulfilled(xpctx, rd->name);
+                 return expander_dep_fulfilled(xpctx, rd2->evr);
                }
            }
+         if (expander_dep_fulfilled(xpctx, rd->name))  /* A OR ~B */
+           return 1;
+         return !expander_dep_fulfilled(xpctx, rd->evr);
        }
-      if (s->obsoletes)
+      if (rd->flags == REL_UNLESS)
        {
-         conp = s->repo->idarraydata + s->obsoletes;
-         while ((con = *conp++) != 0)
+         if (ISRELDEP(rd->evr))
            {
-             FOR_PROVIDES(p2, pp2, con)
+             Reldep *rd2 = GETRELDEP(pool, rd->evr);
+             if (rd2->flags == REL_ELSE)
                {
-                 if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
-                   continue;
-                 queue_push2(conflictsinfo, p2, -p);
+                 if (!expander_dep_fulfilled(xpctx, rd2->name))
+                   return expander_dep_fulfilled(xpctx, rd->name);
+                 return expander_dep_fulfilled(xpctx, rd2->evr);
                }
            }
+         if (!expander_dep_fulfilled(xpctx, rd->name)) /* A AND ~B */
+           return 0;
+         return !expander_dep_fulfilled(xpctx, rd->evr);
+       }
+      if (rd->flags == REL_AND)
+       {
+         if (!expander_dep_fulfilled(xpctx, rd->name))
+           return 0;
+         return expander_dep_fulfilled(xpctx, rd->evr);
+       }
+      if (rd->flags == REL_OR)
+       {
+         if (expander_dep_fulfilled(xpctx, rd->name))
+           return 1;
+         return expander_dep_fulfilled(xpctx, rd->evr);
        }
     }
-  *cidone = out->count;
+  FOR_PROVIDES(p, pp, dep)
+    {
+      if (MAPTST(&xpctx->installed, p))
+       return 1;
+    }
+  return 0;
 }
 
-static void
-expander_updaterecommendedmap(Expander *xp, Map *recommended, int *recdone, Queue *out)
+static int
+prune_neg_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n)
 {
-  Pool *pool = xp->pool;
+  Expander *xp = xpctx->xp;
+  Pool *pool = xpctx->pool;
+  Id whon = who ? pool->solvables[who].name : 0;
+  int i, j;
+  for (i = j = 0; i < n; i++)
+    {
+      Id p = e[i];
+      Id pn = pool->solvables[p].name;
+      if (MAPTST(&xp->preferneg, pn))
+       continue;
+      if (who && MAPTST(&xp->prefernegx, pn))
+       {
+         Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+         if (xid && MAPTST(&xp->preferneg, xid))
+           continue;
+       }
+      e[j++] = p;
+    }
+  return j ? j : n;
+}
 
-  int i;
+static int
+prune_pos_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n, int domulti)
+{
+  Expander *xp = xpctx->xp;
+  Queue *pruneq = &xpctx->pruneq;
+  Pool *pool = xpctx->pool;
+  Id whon = who ? pool->solvables[who].name : 0;
+  int i, j;
+
+  if (pruneq->count)
+    queue_empty(pruneq);
+  for (i = j = 0; i < n; i++)
+    {
+      Id p = e[i];
+      Id pn = pool->solvables[p].name;
+      if (MAPTST(&xp->preferpos, pn))
+       queue_push2(pruneq, pn, p);
+      else if (who && MAPTST(&xp->preferposx, pn))
+       {
+         Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+         if (xid && MAPTST(&xp->preferpos, xid))
+           queue_push2(pruneq, xid, p);
+       }
+    }
+  if (!pruneq->count)
+    return n;
+  if (pruneq->count > 2)
+    {
+      if (!domulti)
+       return n;
+      /* pos prefers are ordered, the first one wins */
+      for (i = 0; i < xp->preferposq.count; i++)
+       {
+         Id xid = xp->preferposq.elements[i];
+         for (j = 0; j < pruneq->count; j += 2)
+           if (pruneq->elements[j] == xid)
+             {
+               e[0] = pruneq->elements[j + 1];
+               return 1;
+             }
+       }
+    }
+  e[0] = pruneq->elements[1];  /* simple case, just one prefer */
+  return 1;
+}
+
+static int
+prune_or_dep(ExpanderCtx *xpctx, Id dep, Id *e, int n)
+{
+  Pool *pool = xpctx->pool;
+  int i, j;
+  Id p, pp;
+
+  for (;;)
+    {
+      Reldep *rd = 0;
+      if (ISRELDEP(dep))
+       {
+         rd = GETRELDEP(pool, dep);
+         if (rd->flags != REL_OR)
+           rd = 0;
+       }
+      if (rd)
+       dep = rd->name;
+      i = j = 0;
+      /* both sets are ordered */
+      FOR_PROVIDES(p, pp, dep)
+       {
+         if (p < e[i])
+           continue;
+         while (i < n && p > e[i])
+           i++;
+         if (i == n)
+           break;
+         if (p == e[i])
+           e[j++] = p;
+       }
+      if (j)
+       return j;
+      if (rd)
+       dep = rd->evr;
+      else
+       break;
+    }
+  return n;
+}
+
+static int
+prune_supplemented(ExpanderCtx *xpctx, Id *e, int n)
+{
+  Pool *pool = xpctx->pool;
+  int i, j;
+  Id sup, *supp;
+
+  for (i = j = 0; i < n; i++)
+    {
+      Id p = e[i];
+      Solvable *s = pool->solvables + p;
+      if (!s->supplements)
+       continue;
+      supp = s->repo->idarraydata + s->supplements;
+      while ((sup = *supp++) != 0)
+       if (expander_dep_fulfilled(xpctx, sup))
+         break;
+      if (sup)
+        e[j++] = p;
+    }
+  return j ? j : n;
+}
+
+static void
+add_recommended_packages(ExpanderCtx *xpctx, Solvable *s)
+{
+  Pool *pool = xpctx->pool;
   Id p, pp, rec, *recp;
-  for (i = *recdone; i < out->count; i++)
+  for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
     {
-      Solvable *s;
-      s = pool->solvables + out->elements[i];
-      if (s->recommends)
-       {
-          MAPEXP(recommended, pool->nsolvables);
-          for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
-           FOR_PROVIDES(p, pp, rec)
-             MAPSET(recommended, p);
-       }
+      int haveone = 0;
+      if (pool_is_complex_dep(pool, rec))
+       {
+         expander_installed_complexdep(xpctx, s - pool->solvables, rec, DEPTYPE_RECOMMENDS);
+         continue;
+       }
+      FOR_PROVIDES(p, pp, rec)
+       {
+         if (MAPTST(&xpctx->installed, p))
+           break;
+         if (haveone)
+           continue;
+         if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p))
+           continue;
+         if (pool->solvables[p].conflicts && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0) != 0)
+           continue;
+         if (pool->solvables[p].obsoletes && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0) != 0)
+           continue;
+         haveone = 1;
+       }
+      if (p)
+       continue;       /* already fulfilled */
+      if (haveone)
+       queue_push2(&xpctx->todo, rec, s - pool->solvables);
     }
-  *recdone = out->count;
 }
 
-static inline int
-findconflictsinfo(Queue *conflictsinfo, Id p)
+static void
+expander_growmaps(Expander *xp)
 {
-  int i;
+  Pool *pool = xp->pool;
+  MAPEXP(&xp->ignored, pool->ss.nstrings);
+  MAPEXP(&xp->ignoredx, pool->ss.nstrings);
+  MAPEXP(&xp->preferpos, pool->ss.nstrings);
+  MAPEXP(&xp->preferposx, pool->ss.nstrings);
+  MAPEXP(&xp->preferneg, pool->ss.nstrings);
+  MAPEXP(&xp->prefernegx, pool->ss.nstrings);
+  MAPEXP(&xp->conflicts, pool->ss.nstrings);
+}
 
-  for (i = 0; i < conflictsinfo->count; i++)
-    if (conflictsinfo->elements[i] == p)
-      return conflictsinfo->elements[i + 1];
-  return 0;
+static Id
+str2id_dup(Pool *pool, const char *str)
+{
+  char buf[256];
+  size_t l = strlen(str);
+  if (l < 256) {
+    memcpy(buf, str, l + 1);
+    return pool_str2id(pool, buf, 1);
+  } else {
+    return pool_str2id(pool, pool_tmpjoin(pool, str, 0, 0), 1);
+  }
 }
 
-#define ERROR_NOPROVIDER               1
-#define ERROR_CHOICE                   2
-#define ERROR_CONFLICTINGPROVIDER      3
-#define ERROR_CONFLICTINGPROVIDERS     4
-#define ERROR_PROVIDERINFO             5
-#define ERROR_PROVIDERINFO2            6
+static void
+add_noproviderinfo(ExpanderCtx *xpctx, Id dep, Id who)
+{
+  Pool *pool = xpctx->pool;
+  Reldep *rd, *prd;
+  Id p, pp, prov, *provp;
+  int nprovinfo;
 
+  if (xpctx->xp->debug)
+    {
+      if (who)
+        expander_dbg(xpctx->xp, "nothing provides %s needed by %s\n", pool_dep2str(pool, dep), expander_solvid2str(xpctx->xp, who));
+      else
+        expander_dbg(xpctx->xp, "nothing provides %s\n", pool_dep2str(pool, dep));
+    }
+  if (!ISRELDEP(dep))
+    return;
+  rd = GETRELDEP(pool, dep);
+  if (rd->flags >= 8 || ISRELDEP(rd->name) || ISRELDEP(rd->evr))
+    return;
+  nprovinfo = 0;
+  FOR_PROVIDES(p, pp, rd->name)
+    {
+      Solvable *s = pool->solvables + p;
+      if (!s->repo || !s->provides)
+       continue;
+      for (provp = s->repo->idarraydata + s->provides; (prov = *provp++) != 0; )
+       {
+         if (!ISRELDEP(prov))
+           continue;
+         prd = GETRELDEP(pool, prov);
+         if (prd->name != rd->name || ISRELDEP(prd->evr))
+           continue;
+         queue_push(&xpctx->errors, ERROR_NOPROVIDERINFO);
+         if (prd->name == s->name && prd->evr == s->evr)
+           {
+             if (xpctx->xp->debug)
+               expander_dbg(xpctx->xp, "%s has version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr));
+             queue_push2(&xpctx->errors, prd->evr, 0);
+           }
+         else
+           {
+             if (xpctx->xp->debug)
+               expander_dbg(xpctx->xp, "%s provides version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr));
+             queue_push2(&xpctx->errors, prd->evr, p);
+           }
+         if (++nprovinfo >= 4)
+           return;             /* only show the first 4 providers */
+       }
+    }
+}
 
-int
-expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl)
+static int
+expander_expand(Expander *xp, Queue *in, Queue *indep, Queue *out, Queue *ignoreq, int options)
 {
+  ExpanderCtx xpctx;
   Pool *pool = xp->pool;
-  Queue todo, errors, cerrors, qq, posfoundq;
-  Map installed;
-  Map conflicts;
-  Map recommended;
-  Queue conflictsinfo;
-  int cidone;
-  int recdone;
+  Queue toinstall;
+  Queue qq, choices;
   Solvable *s;
   Id q, p, pp;
-  int i, j, nerrors, doamb, ambcnt;
-  Id id, who, whon, pn;
-  Id conflprov, conflprovpc;
-  int haverecommended = 0;
-  int haverecommended_done = 0;
-
-  map_init(&installed, pool->nsolvables);
-  map_init(&conflicts, 0);
-  map_init(&recommended, 0);
-  queue_init(&conflictsinfo);
-  queue_init(&todo);
+  int i, j, nerrors;
+  int ti, tj, tc;
+  Id todoid, id, who, whon;
+  Id conflprovpc;
+  int pass;
+  Queue revertignore;
+  int oldignoreignore = xp->ignoreignore;
+  Map oldignored, oldignoredx;
+  int ignoremapssaved = 0;
+  int dorecstart = 0;
+
+  memset(&xpctx, 0, sizeof(xpctx));
+  xpctx.xp = xp;
+  xpctx.pool = pool;
+  xpctx.out = out;
+  xpctx.ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : xp->ignoreignore;
+  xpctx.ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : xp->ignoreconflicts;
+  xpctx.userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : xp->userecommendsforchoices;
+  xpctx.usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : xp->usesupplementsforchoices;
+  xpctx.dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : xp->dorecommends;
+  xpctx.dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : xp->dosupplements;
+  map_init(&xpctx.installed, pool->nsolvables);
+  map_init(&xpctx.conflicts, 0);
+  map_init(&xpctx.recommended, 0);
+  queue_init(&xpctx.conflictsinfo);
+  queue_init(&xpctx.todo);
+  queue_init(&xpctx.todo_cond);
+  map_init(&xpctx.todo_condmap, 0);
+  queue_init(&xpctx.errors);
+  queue_init(&xpctx.cplxq);
+  queue_init(&xpctx.cplxblks);
+  queue_init(&xpctx.pruneq);
+
+  queue_init(&toinstall);
   queue_init(&qq);
-  queue_init(&errors);
-  queue_init(&cerrors);
-  queue_init(&posfoundq);
+  queue_init(&choices);
+  queue_init(&revertignore);
 
   queue_empty(out);
-  cidone = 0;
-  recdone = 0;
-  if (inconfl)
+
+  /* process ignored. hack: we mess with the ignore config in xp */
+  xp->ignoreignore = 0;
+  if (xpctx.ignoreignore && ignoreq->count)
+    {
+      /* bad: have direct ignores and we need to zero the project config ignores */
+      oldignored = xp->ignored;
+      oldignoredx = xp->ignoredx;
+      ignoremapssaved = 1;
+      /* clear project config maps */
+      memset(&xp->ignored, 0, sizeof(xp->ignored));
+      memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
+    }
+  if (ignoreq->count)
     {
-      for (i = 0; i < inconfl->count; i += 2)
+      /* mix direct ignores with ignores from project config */
+      for (i = 0; i < ignoreq->count; i++)
        {
-         Id con = inconfl->elements[i];
-         FOR_PROVIDES(p, pp, con)
+         const char *ss;
+         id = ignoreq->elements[i];
+         MAPEXP(&xp->ignored, id);
+         if (MAPTST(&xp->ignored, id))
+           continue;
+         MAPSET(&xp->ignored, id);
+         queue_push(&revertignore, id);
+         if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
            {
-             if (inconfl->elements[i + 1] && !pool_match_nevr(pool, pool->solvables + p, con))
+             id = str2id_dup(pool, ss + 1);
+             MAPEXP(&xp->ignoredx, id);
+             if (MAPTST(&xp->ignoredx, id))
                continue;
-             MAPEXP(&conflicts, pool->nsolvables);
-             MAPSET(&conflicts, p);
+             MAPSET(&xp->ignoredx, id);
+             queue_push(&revertignore, -id);
+           }
+       }
+    }
+  else if (xpctx.ignoreignore)
+    {
+      /* no direct ignores, ignore project config ignores.
+       * easy: just disable ignore processing */
+      xp->ignoreignore = 1;
+    }
+
+  /* grow maps to make bit tests cheaper */
+  expander_growmaps(xp);
+
+  /* process standard dependencies */
+  if (indep)
+    {
+      for (i = 0; i < indep->count; i += 2)
+       {
+         int deptype = indep->elements[i];
+         Id dep = indep->elements[i + 1];
+         if (ISRELDEP(dep) && GETRELDEP(pool, dep)->flags == REL_ERROR)
+           {
+             queue_push(&xpctx.errors, ERROR_BADDEPENDENCY);
+             queue_push2(&xpctx.errors, GETRELDEP(pool, dep)->evr, 0);
+             continue;
+           }
+         if ((deptype == DEPTYPE_REQUIRES || deptype == DEPTYPE_CONFLICTS) && pool_is_complex_dep(pool, dep))
+           {
+             expander_installed_complexdep(&xpctx, 0, dep, deptype);
+             continue;
+           }
+         if (deptype == DEPTYPE_REQUIRES)
+           {
+             queue_push2(&xpctx.todo, dep, 0);
+           }
+         else if (deptype == DEPTYPE_CONFLICTS || deptype == DEPTYPE_OBSOLETES)
+           {
+             FOR_PROVIDES(p, pp, dep)
+               {
+                 if (deptype == DEPTYPE_OBSOLETES && !pool_match_nevr(pool, pool->solvables + p, dep))
+                   continue;
+                 MAPEXP(&xpctx.conflicts, pool->nsolvables);
+                 MAPSET(&xpctx.conflicts, p);
+               }
            }
        }
     }
-  /* do direct expands */
+  /* process direct dependencies */
   for (i = 0; i < in->count; i++)
     {
       id = in->elements[i];
-      if (id == expander_directdepsend)
+      if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_ERROR)
        {
-         for (i = i + 1; i < in->count; i++)
-           if (in->elements[i] != expander_directdepsend)
-             queue_push2(&todo, in->elements[i], 0);
-         break;
+         queue_push(&xpctx.errors, ERROR_BADDEPENDENCY);
+         queue_push2(&xpctx.errors, GETRELDEP(pool, id)->evr, 0);
+         continue;
+       }
+      if (pool_is_complex_dep(pool, id))
+       {
+         expander_installed_complexdep(&xpctx, 0, id, DEPTYPE_REQUIRES);
+         continue;
        }
       q = 0;
       FOR_PROVIDES(p, pp, id)
@@ -852,425 +2148,738 @@ expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl)
        }
       if (!q)
        {
-         /* unclear, resolve later */
-         queue_push2(&todo, id, 0);
+         queue_push2(&xpctx.todo, id, 0);      /* unclear, resolve later */
          continue;
        }
-      if (MAPTST(&installed, q))
+      if (xp->debug)
+       expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
+      queue_push(&toinstall, q);
+    }
+
+  /* unify toinstall, check against conflicts */
+  for (i = 0; i < toinstall.count; i++)
+    {
+      p = toinstall.elements[i];
+      MAPSET(&xpctx.installed, p);
+    }
+  for (i = j = 0; i < toinstall.count; i++)
+    {
+      p = toinstall.elements[i];
+      if (!MAPTST(&xpctx.installed, p))
        continue;
-      if (conflicts.size && MAPTST(&conflicts, q))
-       {
-         queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
-         queue_push2(&errors, id, 0);
-         if (cidone < out->count)
-           expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
-         queue_push(&errors, ERROR_PROVIDERINFO2);
-         queue_push2(&errors, q, findconflictsinfo(&conflictsinfo, q));
-         continue;
-       }
-      if (pool->solvables[q].conflicts && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].conflicts, 0)) != 0)
+      MAPCLR(&xpctx.installed, p);
+      toinstall.elements[j++] = p;
+    }
+  queue_truncate(&toinstall, j);
+  if (xpctx.conflicts.size)
+    {
+      for (i = 0; i < toinstall.count; i++)
        {
-         queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
-         queue_push2(&errors, id, 0);
-         queue_push(&errors, ERROR_PROVIDERINFO);
-         queue_push2(&errors, q, pp);
-         continue;
+         p = toinstall.elements[i];
+         if (MAPTST(&xpctx.conflicts, p))
+           findconflictsinfo(&xpctx, p, 2);
        }
-      if (pool->solvables[q].obsoletes && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].obsoletes, 1)) != 0)
+    }
+
+  /* here is the big expansion loop */
+  pass = 0;
+  while (!xpctx.errors.count)
+    {
+      if (toinstall.count)
        {
-         queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
-         queue_push2(&errors, id, 0);
-         queue_push(&errors, ERROR_PROVIDERINFO);
-         queue_push2(&errors, q, -pp);
+         expander_installed_multiple(&xpctx, &toinstall);
+         pass = 0;
          continue;
        }
-      if (xp->debug)
-       expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
-      expander_installed(xp, q, &installed, &conflicts, &conflictsinfo, &cidone, out, &todo); /* unique match! */
-    }
-
-  doamb = 0;
-  ambcnt = todo.count;
-  while (todo.count)
-    {
-      id = queue_shift(&todo);
-      who = queue_shift(&todo);
-      if (ambcnt == 0)
-       {
-         if (doamb >= 2)
-           break;      /* amb pass had no progress, stop */
-        doamb = xp->userecommendsforchoices ? doamb + 1 : 3;
-         if (doamb == 1 && !haverecommended)
-           {
-             for (i = haverecommended_done; i < out->count; i++)
-               if (pool->solvables[out->elements[i]].recommends)
-                 haverecommended = 1;
-             haverecommended_done = out->count;
-             if (!haverecommended)
-               doamb = 3;
-           }
-         if (xp->debug)
-      {
-        if (doamb == 2)
-                     expander_dbg(xp, "now doing undecided dependencies with recommends\n");
-        else
-          expander_dbg(xp, "now doing undecided dependencies\n");
-      }
-         ambcnt = todo.count;
-       }
-      else
-       ambcnt -= 2;
-// printf("todo %s %s ambcnt %d\n", pool_id2str(pool, pool->solvables[who].name), pool_dep2str(pool, id), ambcnt);
-// fflush(stdout);
-      whon = who ? pool->solvables[who].name : 0;
-      queue_empty(&qq);
-      conflprov = 0;
-      conflprovpc = 0;
-      FOR_PROVIDES(p, pp, id)
+
+      if (!xpctx.todo.count)
        {
-         Id pc;
-         if (MAPTST(&installed, p))
-           break;
-         if (who && !xp->ignoreignore)
+         /* almost finished. now do weak deps if requested */
+         pass = 0;
+         if (xpctx.dorecommends)
            {
-             Id pn = pool->solvables[p].name;
-             if (MAPTST(&xp->ignored, pn))
-               break;
-             if (MAPTST(&xp->ignoredx, pn))
+             expander_dbg(xp, "--- now doing recommended packages\n");
+             for (; dorecstart < out->count; dorecstart++)
                {
-                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
-                 if (xid && MAPTST(&xp->ignored, xid))
-                   break;
+                 s = pool->solvables + out->elements[dorecstart];
+                 if (s->recommends)
+                   add_recommended_packages(&xpctx, s);
                }
+             if (xpctx.todo.count)
+               continue;
            }
-         if (conflicts.size && MAPTST(&conflicts, p))
+         if (xpctx.dosupplements)
            {
-             if (xp->debug)
+             Id sup, *supp;
+             expander_dbg(xp, "--- now doing supplemented packages\n");
+             for (p = 1; p < pool->nsolvables; p++)
                {
-                 Id pc = findconflictsinfo(&conflictsinfo, p);
-                 if (pc)
-                   expander_dbg(xp, "ignoring provider %s of %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc > 0 ? pc : -pc), pc > 0 ? "conflicts with" : "obsoletes");
-                 else
-                   expander_dbg(xp, "ignoring conflicted provider %s of %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id));
+                 s = pool->solvables + p;
+                 if (!s->supplements || !s->repo)
+                   continue;
+                 if (MAPTST(&xpctx.installed, p))
+                   continue;
+                 if (!pool_installable(pool, s))
+                   continue;
+                 if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
+                   continue;
+                 if (s->conflicts && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->conflicts, 0, 0) != 0)
+                   continue;
+                 if (s->obsoletes && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->obsoletes, 1, 0) != 0)
+                   continue;
+                 supp = s->repo->idarraydata + s->supplements;
+                 while ((sup = *supp++) != 0)
+                   if (expander_dep_fulfilled(&xpctx, sup))
+                     break;
+                 if (!sup)
+                   continue;
+                 expander_dbg(xp, "added %s because it supplements %s\n", expander_solvid2name(xp, p), pool_dep2str(pool, sup));
+                 queue_push(&toinstall, p);
                }
-             conflprov = conflprov ? 1 : p;
-             conflprovpc = 0;
-             continue;
+             if (toinstall.count)
+               continue;
            }
-         if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
+         /* no new stuff to do, we're finished! */
+         break;
+       }
+
+      expander_dbg(xp, "--- now doing normal dependencies\n");
+
+      if (pass == 1)
+       queue_empty(&choices);
+       
+      for (ti = tj = 0; ti < xpctx.todo.count; ti += 2)
+       {
+         int deptype = DEPTYPE_REQUIRES;
+         todoid = id = xpctx.todo.elements[ti];
+         who = xpctx.todo.elements[ti + 1];
+         if (!id)                      /* deleted entry? */
+           continue;
+         queue_empty(&qq);
+         if (ISCPLX(pool, id))
            {
-             expander_dbg(xp, "ignoring provider %s of %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
-             conflprov = conflprov ? 1 : p;
-             conflprovpc = pc;
-             continue;
+             pp = GETCPLX(pool, id);   /* p, dep, deptype, ids... */
+             id = xpctx.cplxblks.elements[pp + 1];
+             deptype = xpctx.cplxblks.elements[pp + 2];
+             pp += 3;
+             while ((p = xpctx.cplxblks.elements[pp++]))
+               if (p > 0)
+                 queue_push(&qq, p);
            }
-         if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
+         else
            {
-             expander_dbg(xp, "ignoring provider %s of %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
-             conflprov = conflprov ? 1 : p;
-             conflprovpc = -pc;
-             continue;
+             FOR_PROVIDES(p, pp, id)
+               queue_push(&qq, p);
            }
-         queue_push(&qq, p);
-       }
-      if (p)
-       continue;
-      if (qq.count == 0)
-       {
-         if (!conflprov)
+
+         if (qq.count == 0)
            {
-             queue_push(&errors, ERROR_NOPROVIDER);
-             queue_push2(&errors, id, who);
+             if (deptype == DEPTYPE_RECOMMENDS)
+               continue;
+             queue_push(&xpctx.errors, ERROR_NOPROVIDER);
+             queue_push2(&xpctx.errors, id, who);
+             add_noproviderinfo(&xpctx, id, who);
              continue;
            }
-         /* more work for conflicts */
-         if (conflprov != 1)
+
+         /* check installed and ignores */
+         whon = who ? pool->solvables[who].name : 0;
+         for (i = 0; i < qq.count; i++)
            {
-             /* nice, just one provider */
-             queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
-             queue_push2(&errors, id, who);
-             if (!conflprovpc)
-               {
-                 if (cidone < out->count)
-                   expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
-                 conflprovpc = findconflictsinfo(&conflictsinfo, conflprov);
-                 queue_push(&errors, ERROR_PROVIDERINFO2);
-                 queue_push2(&errors, conflprov, conflprovpc);
-               }
-             else
+             p = qq.elements[i];
+             if (MAPTST(&xpctx.installed, p))
+               break;
+             if (who && deptype == DEPTYPE_REQUIRES && !xp->ignoreignore)
                {
-                 queue_push(&errors, ERROR_PROVIDERINFO);
-                 queue_push2(&errors, conflprov, conflprovpc);
+                 Id pn = pool->solvables[p].name;
+                 if (MAPTST(&xp->ignored, pn))
+                   break;
+                 if (MAPTST(&xp->ignoredx, pn))
+                   {
+                     Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+                     if (xid && MAPTST(&xp->ignored, xid))
+                       break;
+                   }
                }
+           }
+         if (i < qq.count)
+           continue;           /* ignored dependency or fulfilled */
+
+         if (pass == 0 && qq.count > 1)
+           {
+             xpctx.todo.elements[tj++] = todoid;
+             xpctx.todo.elements[tj++] = who;
              continue;
            }
-         /* even more work if all providers conflict */
-         queue_push(&errors, ERROR_CONFLICTINGPROVIDERS);
-         queue_push2(&errors, id, who);
-         if (cidone < out->count)
-           expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
-         FOR_PROVIDES(p, pp, id)
+
+         /* do conflict pruning */
+         conflprovpc = 0;
+         for (i = j = 0; i < qq.count; i++)
            {
              Id pc;
-             if (conflicts.size && MAPTST(&conflicts, p))
+             p = qq.elements[i];
+             if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
                {
-                 pc = findconflictsinfo(&conflictsinfo, p);
-                 queue_push(&errors, ERROR_PROVIDERINFO2);
-                 queue_push2(&errors, p, pc);
+                 if (xp->debug)
+                   findconflictsinfo(&xpctx, p, 0);
+                 conflprovpc = 0;
                  continue;
                }
-             if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
+             if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0)) != 0)
                {
-                 queue_push(&errors, ERROR_PROVIDERINFO);
-                 queue_push2(&errors, p, pc);
+                 conflprovpc = pc;
                  continue;
                }
-             if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
+             if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0)) != 0)
                {
-                 queue_push(&errors, ERROR_PROVIDERINFO);
-                 queue_push2(&errors, p, -pc);
+                 conflprovpc = -pc;
                  continue;
                }
+             qq.elements[j++] = p;
            }
-         continue;
-       }
-      if (qq.count > 1 && !doamb)
-       {
-         /* try again later */
-         queue_push2(&todo, id, who);
+         if (j == 0)
+           {
+             if (deptype == DEPTYPE_RECOMMENDS)
+               continue;
+             queue_push(&xpctx.errors, ERROR_CONFLICTINGPROVIDERS);
+             queue_push2(&xpctx.errors, id, who);
+             if (qq.count == 1 && conflprovpc != 1 && conflprovpc != -1)
+               {
+                 p = qq.elements[0];
+                 if (conflprovpc)
+                   {
+                     queue_push(&xpctx.errors, ERROR_PROVIDERINFO);
+                     queue_push2(&xpctx.errors, p, conflprovpc);
+                     continue;
+                   }
+                 findconflictsinfo(&xpctx, p, 1);
+                 continue;
+               }
+             /* even more work if all providers conflict */
+             for (j = 0; j < qq.count; j++)
+               {
+                 p = qq.elements[j];
+                 if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
+                   findconflictsinfo(&xpctx, p, 1);
+                 if (pool->solvables[p].conflicts)
+                   expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 1);
+                 if (pool->solvables[p].obsoletes)
+                   expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 1);
+               }
+             continue;
+           }
+         queue_truncate(&qq, j);
+          if (qq.count == 1)
+           {
+             p = qq.elements[0];
+             if (xp->debug)
+               expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+             queue_push(&toinstall, p);
+             continue;
+           }
+         /* pass is == 1 and we have multiple choices */
          if (xp->debug)
            {
              expander_dbg(xp, "undecided about %s:%s:", whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
              for (i = 0; i < qq.count; i++)
-               expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
-             expander_dbg(xp, "\n");
+               expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
+              expander_dbg(xp, "\n");
            }
+         queue_push2(&choices, qq.count + 3, id);
+         queue_push(&choices, qq.count);
+         queue_insertn(&choices, choices.count, qq.count, qq.elements);
+         xpctx.todo.elements[tj++] = todoid;
+         xpctx.todo.elements[tj++] = who;
+       }
+      queue_truncate(&xpctx.todo, tj);
+
+      if (toinstall.count)
+       continue;
+
+      if (!xpctx.todo.count)
+       continue;
+
+      /* did not find a package to install, only choices left on todo list */
+      if (pass == 0)
+       {
+         pass = 1;     /* now do conflict pruning */
          continue;
        }
 
-      /* prune neg prefers */
-      if (qq.count > 1)
+      expander_dbg(xp, "--- now doing undecided dependencies\n");
+
+      /* prune prefers */
+      for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
        {
-         for (i = j = 0; i < qq.count; i++)
+         Id who = xpctx.todo.elements[ti + 1];
+         Id *qe = choices.elements + tc + 3;
+         Id id = choices.elements[tc + 1];
+         int qn = choices.elements[tc + 2];
+         whon = who ? pool->solvables[who].name : 0;
+         if (qn > 1)
+           qn = prune_neg_prefers(&xpctx, who, qe, qn);
+         if (qn > 1)
+           qn = prune_pos_prefers(&xpctx, who, qe, qn, 0);
+         if (qn == 1)
            {
-             p = qq.elements[i];
-             pn = pool->solvables[p].name;
-             if (MAPTST(&xp->preferneg, pn))
-               continue;
-             if (who && MAPTST(&xp->prefernegx, pn))
-               {
-                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
-                 if (xid && MAPTST(&xp->preferneg, xid))
-                   continue;
-               }
-             qq.elements[j++] = p;
+             p = qe[0];
+             if (xp->debug)
+               expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+             queue_push(&toinstall, p);
+             xpctx.todo.elements[ti] = 0;      /* kill entry */
            }
-         if (j)
-           queue_truncate(&qq, j);
+         choices.elements[tc + 2] = qn;
+         tc += choices.elements[tc];
        }
+      if (toinstall.count)
+       continue;
 
-      /* prune pos prefers */
-      if (qq.count > 1)
+      /* prune pos prefers with domulti and debian or */
+      for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
        {
-         queue_empty(&posfoundq);
-         for (i = j = 0; i < qq.count; i++)
+         Id who = xpctx.todo.elements[ti + 1];
+         Id *qe = choices.elements + tc + 3;
+         Id id = choices.elements[tc + 1];
+         int qn = choices.elements[tc + 2];
+         whon = who ? pool->solvables[who].name : 0;
+         if (qn > 1)
+           qn = prune_pos_prefers(&xpctx, who, qe, qn, 1);
+         if (qn > 1 && pool->disttype != DISTTYPE_RPM)
            {
-             p = qq.elements[i];
-             pn = pool->solvables[p].name;
-             if (MAPTST(&xp->preferpos, pn))
-               {
-                 queue_push2(&posfoundq, pn, p);
-                 qq.elements[j++] = p;
-                 continue;
-               }
-             if (who && MAPTST(&xp->preferposx, pn))
-               {
-                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
-                 if (xid && MAPTST(&xp->preferpos, xid))
-                   {
-                     queue_push2(&posfoundq, xid, p);
-                     qq.elements[j++] = p;
-                     continue;
-                   }
-               }
+             if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
+               qn = prune_or_dep(&xpctx, id, qe, qn);
            }
-         if (posfoundq.count == 2)
+         if (qn == 1)
            {
-             queue_empty(&qq);
-             queue_push(&qq, posfoundq.elements[1]);
+             p = qe[0];
+             if (xp->debug)
+               expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+             queue_push(&toinstall, p);
+             xpctx.todo.elements[ti] = 0;      /* kill entry */
            }
-         else if (posfoundq.count)
+         choices.elements[tc + 2] = qn;
+         tc += choices.elements[tc];
+       }
+      if (toinstall.count)
+       continue;
+
+      /* prune recommended packages */
+      if (xpctx.userecommendsforchoices)
+        expander_updaterecommendedmap(&xpctx);
+      if (xpctx.recommended.size)
+       {
+         expander_dbg(xp, "now doing undecided dependencies with recommends\n");
+         for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
            {
-             /* found a pos prefer, now find first hit */
-             /* (prefers are ordered) */
-             for (i = 0; i < xp->preferposq.count; i++)
+             Id who = xpctx.todo.elements[ti + 1];
+             Id *qe = choices.elements + tc + 3;
+             Id id = choices.elements[tc + 1];
+             int qn = choices.elements[tc + 2];
+             whon = who ? pool->solvables[who].name : 0;
+             for (i = j = 0; i < qn; i++)
+               if (MAPTST(&xpctx.recommended, qe[i]))
+                 qe[j++] = qe[i];
+             if (j)
+               qn = j;
+             if (qn == 1)
                {
-                 Id xid = xp->preferposq.elements[i];
-                 for (j = 0; j < posfoundq.count; j += 2)
-                   if (posfoundq.elements[j] == xid)
-                     break;
-                 if (j < posfoundq.count)
-                   {
-                     queue_empty(&qq);
-                     queue_push(&qq, posfoundq.elements[j + 1]);
-                     break;
-                   }
+                 p = qe[0];
+                 if (xp->debug)
+                   expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+                 queue_push(&toinstall, p);
+                 xpctx.todo.elements[ti] = 0;  /* kill entry */
                }
+             choices.elements[tc + 2] = qn;
+             tc += choices.elements[tc];
            }
+         if (toinstall.count)
+           continue;
        }
-
-      /* prune OR deps */
-      if (qq.count > 1 && ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
+      if (xpctx.usesupplementsforchoices)
        {
-         Id rid = id;
-         for (;;)
+         expander_dbg(xp, "now doing undecided dependencies with supplements\n");
+         for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
            {
-             Reldep *rd = 0;
-             if (ISRELDEP(rid))
+             Id who = xpctx.todo.elements[ti + 1];
+             Id *qe = choices.elements + tc + 3;
+             Id id = choices.elements[tc + 1];
+             int qn = choices.elements[tc + 2];
+             whon = who ? pool->solvables[who].name : 0;
+             qn = prune_supplemented(&xpctx, qe, qn);
+             if (qn == 1)
                {
-                 rd = GETRELDEP(pool, rid);
-                 if (rd->flags != REL_OR)
-                   rd = 0;
+                 p = qe[0];
+                 if (xp->debug)
+                   expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+                 queue_push(&toinstall, p);
+                 xpctx.todo.elements[ti] = 0;  /* kill entry */
                }
-             if (rd)
-               rid = rd->name;
-             queue_empty(&qq);
-             FOR_PROVIDES(p, pp, rid)
-               queue_push(&qq, p);
-             if (qq.count)
-               break;
-             if (rd)
-               rid = rd->evr;
-             else
-               break;
+             choices.elements[tc + 2] = qn;
+             tc += choices.elements[tc];
            }
+         if (toinstall.count)
+           continue;
        }
 
-      if (qq.count > 1 && doamb == 1)
-       {
-         queue_push2(&todo, id, who);
-         continue;
-       }
-
-      /* prioritize recommended packages. */
-      if (qq.count > 1 && doamb == 2)
-       {
-         expander_updaterecommendedmap(xp, &recommended, &recdone, out);
-         if (recommended.size)
-           {
-             for (i = j = 0; i < qq.count; i++)
-               if (MAPTST(&recommended, qq.elements[i]))
-                 qq.elements[j++] = qq.elements[i];
-             if (j)
-               queue_truncate(&qq, j);
-           }
-       }
-
+      /* nothing more to prune. record errors. */
+      for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
+       {
+         Id who = xpctx.todo.elements[ti + 1];
+         Id *qe = choices.elements + tc + 3;
+         Id id = choices.elements[tc + 1];
+         int qn = choices.elements[tc + 2];
+         queue_push(&xpctx.errors, ERROR_CHOICE);
+         queue_push2(&xpctx.errors, id, who);
+         for (i = 0; i < qn; i++)
+           queue_push(&xpctx.errors, qe[i]);
+         queue_push(&xpctx.errors, 0);
+         tc += choices.elements[tc];
+       }
+    }
 
-      if (qq.count > 1)
+  /* free data */
+  map_free(&xpctx.installed);
+  map_free(&xpctx.conflicts);
+  map_free(&xpctx.recommended);
+  map_free(&xpctx.todo_condmap);
+  queue_free(&xpctx.conflictsinfo);
+  queue_free(&xpctx.todo_cond);
+  queue_free(&xpctx.todo);
+  queue_free(&toinstall);
+  queue_free(&qq);
+  queue_free(&choices);
+  queue_free(&xpctx.pruneq);
+  queue_free(&xpctx.cplxq);
+  queue_free(&xpctx.cplxblks);
+
+  /* revert ignores */
+  xp->ignoreignore = oldignoreignore;
+  if (ignoremapssaved)
+    {
+      map_free(&xp->ignored);
+      map_free(&xp->ignoredx);
+      xp->ignored = oldignored;
+      xp->ignoredx = oldignoredx;
+    }
+  else
+    {
+      for (i = 0; i < revertignore.count; i++)
        {
-         queue_push(&cerrors, ERROR_CHOICE);
-         queue_push2(&cerrors, id, who);
-         for (i = 0; i < qq.count; i++)
-           queue_push(&cerrors, qq.elements[i]);
-         queue_push(&cerrors, 0);
-         /* try again later */
-         queue_push2(&todo, id, who);
-         continue;
+         id = revertignore.elements[i];
+         if (id > 0)
+           MAPCLR(&xp->ignored, id);
+         else
+           MAPCLR(&xp->ignoredx, -id);
        }
-      if (xp->debug)
-       expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, qq.elements[0]), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
-      expander_installed(xp, qq.elements[0], &installed, &conflicts, &conflictsinfo, &cidone, out, &todo);
-      doamb = 0;
-      ambcnt = todo.count;
-      queue_empty(&cerrors);
-    }
-  map_free(&installed);
-  map_free(&conflicts);
-  map_free(&recommended);
-  queue_free(&conflictsinfo);
+    }
+  queue_free(&revertignore);
+
+  /* finish return queue, count errors */
   nerrors = 0;
-  if (errors.count || cerrors.count)
+  if (xpctx.errors.count)
     {
       queue_empty(out);
-      for (i = 0; i < errors.count; i += 3)
+      queue_insertn(out, 0, xpctx.errors.count, xpctx.errors.elements);
+      for (i = 0; i < out->count; i += 3)
        {
-         queue_push(out, errors.elements[i]);
-         queue_push(out, errors.elements[i + 1]);
-         queue_push(out, errors.elements[i + 2]);
          nerrors++;
+         if (out->elements[i] == ERROR_CHOICE)
+           while (out->elements[i + 3])
+             i++;
        }
-      for (i = 0; i < cerrors.count; )
+    }
+  queue_free(&xpctx.errors);
+  return nerrors;
+}
+
+static Expander *
+expander_create(Pool *pool, Queue *preferpos, Queue *preferneg, Queue *ignore, Queue *conflict, Queue *fileprovides, int debug, int options)
+{
+  Expander *xp;
+  int i, j;
+  Id id, id2;
+  const char *str;
+  Queue q;
+
+  xp = calloc(sizeof(Expander), 1);
+  xp->pool = pool;
+  xp->debug = debug;
+  xp->ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : 0;
+  xp->ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : 0;
+  xp->userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : 0;
+  xp->usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : 0;
+  xp->dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : 0;
+  xp->dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : 0;
+
+  queue_init(&xp->preferposq);
+  for (i = 0; i < preferpos->count; i++)
+    {
+      id = preferpos->elements[i];
+      queue_push(&xp->preferposq, id);
+      MAPEXP(&xp->preferpos, id);
+      MAPSET(&xp->preferpos, id);
+      if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
+        {
+          id = str2id_dup(pool, str + 1);
+         MAPEXP(&xp->preferposx, id);
+         MAPSET(&xp->preferposx, id);
+        }
+    }
+  for (i = 0; i < preferneg->count; i++)
+    {
+      id = preferneg->elements[i];
+      MAPEXP(&xp->preferneg, id);
+      MAPSET(&xp->preferneg, id);
+      if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
+        {
+          id = str2id_dup(pool, str + 1);
+         MAPEXP(&xp->prefernegx, id);
+         MAPSET(&xp->prefernegx, id);
+        }
+    }
+
+  for (i = 0; i < ignore->count; i++)
+    {
+      id = ignore->elements[i];
+      MAPEXP(&xp->ignored, id);
+      MAPSET(&xp->ignored, id);
+      if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
+        {
+          id = str2id_dup(pool, str + 1);
+         MAPEXP(&xp->ignoredx, id);
+         MAPSET(&xp->ignoredx, id);
+        }
+    }
+
+  queue_init(&xp->conflictsq);
+  for (i = 0; i < conflict->count; i += 2)
+    {
+      id = conflict->elements[i];
+      id2 = conflict->elements[i + 1];
+      queue_push2(&xp->conflictsq, id, id2);
+      MAPEXP(&xp->conflicts, id);
+      MAPSET(&xp->conflicts, id);
+      MAPEXP(&xp->conflicts, id2);
+      MAPSET(&xp->conflicts, id2);
+    }
+
+  if (fileprovides->count)
+    xp->havefileprovides = 1;
+  queue_init(&q);
+  for (i = 0; i < fileprovides->count; i++)
+    {
+      Id p, pp;
+      id = fileprovides->elements[i];
+      int havenew = 0;
+
+      /* XXX: this modifies the pool, which is somewhat unclean! */
+      /* get old providers */
+      queue_empty(&q);
+      FOR_PROVIDES(p, pp, id)
+        queue_push(&q, p);
+      for (j = i + 1; j < fileprovides->count && (id2 = fileprovides->elements[j]) != 0; j++)
        {
-         queue_push(out, cerrors.elements[i]);
-         queue_push(out, cerrors.elements[i + 1]);
-         queue_push(out, cerrors.elements[i + 2]);
-         i += 3;
-         while (cerrors.elements[i])
+         FOR_PROVIDES(p, pp, id2)
            {
-             queue_push(out, cerrors.elements[i]);
-             i++;
+             int k;
+             if (pool->solvables[p].name != id2)
+               continue;               /* match name only */
+             /* insert sorted */
+             for (k = 0; ; k++)
+               {
+                 if (k == q.count || q.elements[k] > p)
+                   {
+                     queue_insert(&q, k, p);
+                     havenew = 1;
+                     break;
+                   }
+                 if (q.elements[k] == p)
+                   break;
+               }
            }
-         queue_push(out, 0);
-         i++;
-         nerrors++;
        }
+      if (havenew)
+        pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
+      i = j;
     }
-  else
+  queue_free(&q);
+  return xp;
+}
+
+static void
+expander_free(Expander *xp)
+{
+  map_free(&xp->ignored);
+  map_free(&xp->ignoredx);
+  queue_free(&xp->preferposq);
+  map_free(&xp->preferpos);
+  map_free(&xp->preferposx);
+  map_free(&xp->preferneg);
+  map_free(&xp->prefernegx);
+  queue_free(&xp->conflictsq);
+  map_free(&xp->conflicts);
+  solv_free(xp->debugstr);
+  solv_free(xp);
+}
+
+
+
+static void
+set_disttype(Pool *pool, int disttype)
+{
+  pool_setdisttype(pool, disttype);
+#ifdef POOL_FLAG_HAVEDISTEPOCH
+  /* make newer mandriva work, hopefully there are no ill effects... */
+  pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0);
+#endif
+}
+
+static void
+set_disttype_from_location(Pool *pool, Solvable *so)
+{
+  unsigned int medianr;
+  const char *s = solvable_get_location(so, &medianr);
+  int disttype = -1;
+  int sl;
+  if (!s)
+    return;
+  sl = strlen(s);
+  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
+    disttype = DISTTYPE_RPM;
+#ifdef DISTTYPE_DEB
+  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb"))
+    disttype = DISTTYPE_DEB;
+#endif
+#ifdef DISTTYPE_ARCH
+  if (disttype < 0 && sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst")))
+    disttype = DISTTYPE_ARCH;
+#endif
+  if (disttype >= 0 && pool->disttype != disttype)
+    set_disttype(pool, disttype);
+}
+
+static inline const char *
+solvid2name(Pool *pool, Id p)
+{
+  return pool_id2str(pool, pool->solvables[p].name);
+}
+
+#define ISNOARCH(arch) (arch == ARCH_NOARCH || arch == ARCH_ALL || arch == ARCH_ANY)
+
+static int
+has_keyname(Repo *repo, Id keyname)
+{
+  Repodata *data;
+  int rdid;
+  FOR_REPODATAS(repo, rdid, data)
+    if (repodata_has_keyname(data, keyname))
+      return 1;
+  return 0;
+}
+
+static inline int
+match_modules_req(Pool *pool, Id id)
+{
+  const char *dep = pool_id2str(pool, id);
+  Id *modules;
+  if (strncmp(dep, "platform", 8) == 0 && (dep[8] == 0 || dep[8] == '-'))
+    return 1;
+  for (modules = pool->appdata; *modules; modules++)
+    {
+      const char *name, *rname;
+      if (*modules == id)
+       return 1;
+      name = pool_id2str(pool, *modules);
+      if ((rname = strrchr(name, '-')) == 0 || rname == name)
+       continue;
+      if (!strncmp(dep, rname, rname - name) && dep[rname - name] == 0)
+       return 1;
+    }
+  return 0;
+}
+
+static void
+create_module_map(Repo *repo, Map *modulemap, Queue *modulemapq)
+{
+  Pool *pool = repo->pool;
+  Id *modules = pool->appdata;
+  int i, have_moduleinfo = 0;
+  Id id, p, *pp;
+  Solvable *s;
+
+  if (!modulemap->size)
+    map_grow(modulemap, pool->ss.nstrings);
+  if (!modules)
+    return;
+  if (!*modules)
+    {
+      map_setall(modulemap);
+      return;
+    }
+  /* clear old bits */
+  if (modulemapq->count)
+    {
+      for (i = 0; i < modulemapq->count; i++)
+       MAPCLR(modulemap, modulemapq->elements[i]);
+      queue_empty(modulemapq);
+    }
+  for (modules = pool->appdata; *modules; modules++)
+    MAPSET(modulemap, *modules);
+  /* look for module information stored in "buildservice:modules" solvables */
+  FOR_REPO_SOLVABLES(repo, p, s)
+    {
+      if (s->name != buildservice_modules || s->arch != ARCH_SRC)
+       continue;
+      have_moduleinfo = 1;
+      if (s->evr >= 1 && s->evr < pool->ss.nstrings && MAPTST(modulemap, s->evr))
+       {
+         queue_push(modulemapq, s->evr);       /* directly addressed */
+         continue;
+       }
+      id = s->repo->idarraydata[s->provides];
+      if (id < 1 || id >= pool->ss.nstrings || !MAPTST(modulemap, id))
+       continue;       /* not what we're looking for */
+      for (pp = s->repo->idarraydata + s->requires; (id = *pp) != 0; pp++)
+        {
+          /* check if the dep is fulfilled by any module in the list */
+          if (id < 1 || id >= pool->ss.nstrings)
+           break;      /* hey! */
+          if (!MAPTST(modulemap, id) && !match_modules_req(pool, id))
+           break;      /* could not fulfil requires */
+        }
+      if (id)
+       continue;       /* could not fulfil one of the requires, ignore module */
+      queue_push(modulemapq, s->evr);
+    }
+  if (!have_moduleinfo)
     {
-      if (todo.count)
-       {
-         fprintf(stderr, "Internal expansion error!\n");
-         queue_empty(out);
-         queue_push(out, ERROR_NOPROVIDER);
-         queue_push(out, 0);
-         queue_push(out, 0);
-       }
+      /* old style repo with no moduleinfo at all. simple use the unexpanded ids */
+      for (modules = pool->appdata; *modules; modules++)
+        queue_push(modulemapq, *modules);
+      return;
     }
-  queue_free(&todo);
-  queue_free(&qq);
-  queue_free(&errors);
-  queue_free(&cerrors);
-  queue_free(&posfoundq);
-  return nerrors;
+  for (modules = pool->appdata; *modules; modules++)
+    MAPCLR(modulemap, *modules);
+  for (i = 0; i < modulemapq->count; i++)
+    MAPSET(modulemap, modulemapq->elements[i]);
 }
 
-static void
-set_disttype(Pool *pool, int disttype)
+static int
+in_module_map(Pool *pool, Map *modulemap, Queue *modules)
 {
-  pool_setdisttype(pool, disttype);
-#ifdef POOL_FLAG_HAVEDISTEPOCH
-  /* make newer mandriva work, hopefully there are no ill effects... */
-  pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0);
-#endif
+  int i;
+  for (i = 0; i < modules->count; i++)
+    { 
+      Id id = modules->elements[i];
+      if (id > 1 && id < pool->ss.nstrings && MAPTST(modulemap, id))
+       return 1;
+    }
+  return 0;
 }
 
-static void
-set_disttype_from_location(Pool *pool, Solvable *so)
-{
-  unsigned int medianr;
-  const char *s = solvable_get_location(so, &medianr);
-  int disttype = -1;
-  int sl;
-  if (!s)
-    return;
-  sl = strlen(s);
-  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
-    disttype = DISTTYPE_RPM;
-#ifdef DISTTYPE_DEB
-  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb"))
-    disttype = DISTTYPE_DEB;
-#endif
-#ifdef DISTTYPE_ARCH
-  if (disttype < 0 && sl >= 11 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz")))
-    disttype = DISTTYPE_ARCH;
-#endif
-  if (disttype >= 0 && pool->disttype != disttype)
-    set_disttype(pool, disttype);
-}
 
-void
-create_considered(Pool *pool, Repo *repoonly, Map *considered)
+static void
+create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepos)
 {
   Id p, pb,*best;
   Solvable *s, *sb;
@@ -1278,41 +2887,70 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered)
   Repo *repo;
   int olddisttype = -1;
   int dodrepo;
+  int mayhave_modules;
+  Queue modules;
+  Map modulemap;
+  Queue modulemapq;
+  int modulemap_uptodate;
 
   map_init(considered, pool->nsolvables);
   best = solv_calloc(sizeof(Id), pool->ss.nstrings);
   
+  queue_init(&modules);
+  map_init(&modulemap, 0);
+  queue_init(&modulemapq);
   FOR_REPOS(ridx, repo)
     {
       if (repoonly && repo != repoonly)
        continue;
       dodrepo = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl) != 0;
+      mayhave_modules = has_keyname(repo, buildservice_modules) ? 1 : 0;
+      modulemap_uptodate = 0;
       FOR_REPO_SOLVABLES(repo, p, s)
        {
+         int inmodule = 0;
          if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
            continue;
          pb = best[s->name];
-         if (pb)
+         sb = pb ? pool->solvables + pb : 0;
+         if (mayhave_modules)
            {
-             sb = pool->solvables + pb;
-             if (s->repo != sb->repo)
-               continue;       /* first repo wins */
-             if (s->arch != sb->arch)
+             solvable_lookup_idarray(s, buildservice_modules, &modules);
+             inmodule = modules.count ? 1 : 0;
+             if (inmodule)
                {
-                 int r;
-                 if (s->arch == ARCH_NOARCH || s->arch == ARCH_ALL || s->arch == ARCH_ANY)
-                   continue;
-                 if (sb->arch != ARCH_NOARCH && sb->arch != ARCH_ALL && sb->arch != ARCH_ANY)
+                 if (!modulemap_uptodate)
                    {
-                     /* the strcmp is kind of silly, but works for most archs */
-                     r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
-                     if (r >= 0)
-                       continue;
+                     create_module_map(repo, &modulemap, &modulemapq);
+                     modulemap_uptodate = 1;
                    }
+                 if (!in_module_map(pool, &modulemap, &modules))
+                   continue;           /* nope, ignore package */
+               }
+           }
+         if (unorderedrepos && sb && s->repo->priority != sb->repo->priority)
+           {
+             if (s->repo->priority < sb->repo->priority)
+               continue;       /* lower prio, ignore */
+           }
+         else if (sb)
+           {
+             int sbinmodule = 0;
+             /* we already have that name. decide which one to take */
+             if (!unorderedrepos && s->repo != sb->repo)
+               continue;       /* first repo wins */
+
+             if (s->repo == sb->repo && mayhave_modules)
+               sbinmodule = solvable_lookup_type(sb, buildservice_modules) ? 1 : 0;
+
+             if (inmodule != sbinmodule)
+               {
+                 if (inmodule < sbinmodule)
+                   continue;
                }
              else if (s->evr != sb->evr)
                {
-                 /* same repo, check versions */
+                 /* check versions */
                  int r;
                  if (olddisttype < 0)
                    {
@@ -1320,16 +2958,27 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered)
                      set_disttype_from_location(pool, s);
                    }
                  r = pool_evrcmp(pool, sb->evr, s->evr, EVRCMP_COMPARE);
-                 if (r > 0)
+                 if (r == 0)
+                   r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
+                 if (r >= 0)
+                   continue;
+               }
+             else if (s->arch != sb->arch)
+               {
+                 /* same versions, check arch */
+                 if (ISNOARCH(sb->arch) && !ISNOARCH(s->arch))
                    continue;
-                 else if (r == 0)
+                 if (ISNOARCH(sb->arch) || !ISNOARCH(s->arch))
                    {
-                     r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
+                     int r;
+                     /* the strcmp is kind of silly, but works for most archs */
+                     r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
                      if (r >= 0)
                        continue;
                    }
                }
            }
+
           if (dodrepo)
            {
              /* we only consider dod packages */
@@ -1342,7 +2991,7 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered)
          best[s->name] = p;
          MAPSET(considered, p);
        }
-      /* dodrepos have a second pass: replace dod entries with downloaded ones */
+      /* dodrepos have a second pass: replace dod entries with identical downloaded ones */
       if (dodrepo)
        {
          const char *bsid;
@@ -1366,15 +3015,18 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered)
        }
     }
   solv_free(best);
+  queue_free(&modules);
+  map_free(&modulemap);
+  queue_free(&modulemapq);
   if (olddisttype >= 0 && pool->disttype != olddisttype)
     set_disttype(pool, olddisttype);
 }
 
 struct metaline {
-  char *l;
-  int lastoff;
-  int nslash;
-  int killed;
+  char *l;             /* pointer to line */
+  int lastoff;         /* line offset of last path element */
+  int nslash;          /* number of slashes */
+  int killed;          /* 1: line has been killed. 2: because of a cycle package */
 };
 
 static int metacmp(const void *ap, const void *bp)
@@ -1396,6 +3048,87 @@ static int metacmp(const void *ap, const void *bp)
   return a - b;
 }
 
+static char *
+slurp(FILE *fp, int *lenp)
+{
+  int l, ll;
+  char *buf = 0; 
+  int bufl = 0; 
+
+  for (l = 0; ; l += ll)
+    {    
+      if (bufl - l < 4096)
+        {
+          bufl += 4096;
+         if (bufl < 0)
+           {
+             buf = solv_free(buf);
+             l = 0;
+             break;
+           }
+          buf = solv_realloc(buf, bufl);
+        }
+      ll = fread(buf + l, 1, bufl - l, fp); 
+      if (ll < 0) 
+        {
+          buf = solv_free(buf);
+          l = 0; 
+          break;
+        }
+      if (ll == 0)
+        {
+          buf[l] = 0;   /* always zero-terminate */
+          break;
+        }
+    }    
+  if (lenp)
+    *lenp = l; 
+  return buf; 
+}
+
+
+Id
+repo_add_obsbinlnk(Repo *repo, const char *path, int flags)
+{
+  Repodata *data;
+  FILE *fp;
+  char *buf;
+  int len;
+  SV *sv;
+  unsigned char *src;
+  STRLEN srcl;
+  Id p;
+
+  if ((fp = fopen(path, "r")) == 0)
+    return 0;
+  buf = slurp(fp, &len);
+  fclose(fp);
+  if (!buf || len <= 0)
+    return 0;
+  src = (unsigned char *)buf;
+  srcl = len;
+  sv = 0;
+  if (srcl >= 7 && src[0] == 'p' && src[1] == 's' && src[2] == 't' && src[3] == '0' && (src[4] & 1) == 1 && src[4] >= 5) {
+    src += 6;
+    srcl -= 6;
+    sv = retrieve(&src, &srcl, 0);
+  }
+  free(buf);
+  if (!sv)
+    return 0;
+  if (SvTYPE(sv) != SVt_PVHV)
+    {
+      SvREFCNT_dec(sv);
+      return 0;
+    }
+  data = repo_add_repodata(repo, flags);
+  p = data2pkg(repo, data, (HV *)sv, 0);
+  SvREFCNT_dec(sv);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return p;
+}
+
 #ifndef REPO_NO_LOCATION
 # define REPO_NO_LOCATION 0
 #endif
@@ -1412,10 +3145,21 @@ repodata_addbin(Repodata *data, char *prefix, char *s, int sl, char *sid)
   path = solv_dupjoin(prefix, "/", s);
   if (sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
     p = repo_add_rpm(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|RPM_ADD_WITH_PKGID|RPM_ADD_NO_FILELIST|RPM_ADD_NO_RPMLIBREQS);
+#if defined(LIBSOLVEXT_FEATURE_DEBIAN)
   else if (sl >= 4 && !strcmp(s + sl - 4, ".deb"))
     p = repo_add_deb(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|DEBS_ADD_WITH_PKGID);
-#ifdef ARCH_ADD_WITH_PKGID
-  else if (sl >= 11 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz")))
+#endif
+  else if (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk"))
+    {
+      p = repo_add_obsbinlnk(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION);
+      /* do not overwrite location from obsbinlnk file */
+      solv_free(path);
+      if (p)
+        repodata_set_str(data, p, buildservice_id, sid);
+      return p;
+    }
+#if defined(LIBSOLVEXT_FEATURE_ARCHREPO) && defined(ARCH_ADD_WITH_PKGID)
+  else if (sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst")))
     p = repo_add_arch_pkg(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|ARCH_ADD_WITH_PKGID);
 #endif
   solv_free(path);
@@ -3485,38 +5229,173 @@ printobscpioinstr(FILE *fp, int fdstore, int withmeta)
   printf("stats file_size %lld\n", (unsigned long long)ftell(fp));
 }
 
+static int
+unifymodules_cmp(const void *ap, const void *bp, void *dp)
+{
+  return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+missingmodules_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap;
+  const Id *b = bp;
+  if (a[0] != b[0])
+    return a[0] - b[0];
+  if (!a[1] && b[1])
+    return -1;
+  if (!b[1] && a[1])
+    return 1;
+  return a[1] - b[1];
+}
+
+static int
+is_dod_package(Solvable *s)
+{
+  const char *str = solvable_lookup_str(s, buildservice_id);
+  return str && !strcmp(str, "dod") ? 1 : 0;
+}
+
+static Solvable *
+find_corresponding_dod(Solvable *s)
+{
+  Repo *repo = s->repo;
+  Id p2;
+  Solvable *s2;
+
+  if (!repo)
+    return 0;
+  FOR_REPO_SOLVABLES(repo, p2, s2)
+    {
+      if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch && s != s2 && is_dod_package(s2))
+       return s2;
+    }
+  return 0;
+}
+
+struct scc_data {
+  Id *edata;
+  Id *vedge;
+  Queue *sccs;
+  int *stack;
+  int nstack;
+  int *low;
+  int idx;
+};
+
+static void
+scc_collect(struct scc_data *scc, int node)
+{
+  int *low = scc->low;
+  Id *e;
+  queue_push(scc->sccs, node);
+  low[node] = -1;
+  for (e = scc->edata + scc->vedge[node]; *e; e++)
+    if (*e != -1 && low[*e] > 0)
+      scc_collect(scc, *e);
+}
+
+/* Tarjan's SCC algorithm */
+static int
+scc_visit(struct scc_data *scc, int node)
+{
+  int l, myidx, *low = scc->low, nontrivial = 0;
+  Id *e;
+  low[node] = myidx = scc->idx++;
+  for (e = scc->edata + scc->vedge[node]; *e; e++)
+    {
+      if (*e == -1 || *e == node)
+       continue;
+      if (!(l = low[*e]))
+       l = scc_visit(scc, *e);
+      if (l > 0)
+       nontrivial = 1;
+      if (l > 0 && l < low[node])
+       low[node] = l;
+    }
+  if (low[node] != myidx)
+    return low[node];
+  low[node] = -1;
+  if (nontrivial)
+    {
+      scc_collect(scc, node);
+      queue_push(scc->sccs, 0);
+    }
+  return -1;
+}
+
+static void
+find_sccs(Queue *edata, Queue *vedge, Queue *sccs)
+{
+  struct scc_data scc;
+  int i;
+  scc.edata = edata->elements;
+  scc.vedge = vedge->elements;
+  scc.sccs = sccs;
+  scc.low = solv_calloc(vedge->count, sizeof(int));
+  scc.idx = 1;
+  for (i = 1; i < vedge->count; i++)
+    if (!scc.edata[vedge->elements[i]])
+      scc.low[i] = -1;
+  for (i = 1; i < vedge->count; i++)
+    if (!scc.low[i])
+      scc_visit(&scc, i);
+  solv_free(scc.low);
+}
+
+
 MODULE = BSSolv                PACKAGE = BSSolv
 
 void
 depsort(HV *deps, SV *mapp, SV *cycp, ...)
+    ALIAS:
+       depsort2 = 1
     PPCODE:
        {
            int i, j, k, cy, cycstart, nv;
+           int pkgstart = 3;
            SV *sv, **svp;
+           SV *pkg2srcp = 0;
            Id id, *e;
            Id *mark;
            char **names;
+           char **depnames;
            Hashtable ht;
            Hashval h, hh, hm;
            HV *mhv = 0;
+           HV *pkg2srchv = 0;
 
            Queue edata;
            Queue vedge;
            Queue todo;
            Queue cycles;
+           Map edgeunifymap;
+           int didsccs = 0;
 
-           if (items == 3)
+           if (ix)
+             {
+               /* called as depsort2 */
+               if (items < 4)
+                 XSRETURN_EMPTY; /* nothing to sort */
+               pkgstart = 4;
+               pkg2srcp = cycp;
+               cycp = ST(3);
+             }
+           if (items == pkgstart)
              XSRETURN_EMPTY; /* nothing to sort */
-           if (items == 4)
+           if (items == pkgstart + 1)
              {
                /* only one item */
-               char *s = SvPV_nolen(ST(3));
+               char *s = SvPV_nolen(ST(pkgstart));
                EXTEND(SP, 1);
                sv = newSVpv(s, 0);
                PUSHs(sv_2mortal(sv));
                XSRETURN(1); /* nothing to sort */
              }
 
+           if (pkg2srcp && SvROK(pkg2srcp) && SvTYPE(SvRV(pkg2srcp)) == SVt_PVHV)
+             pkg2srchv = (HV *)SvRV(pkg2srcp);
+
            if (mapp && SvROK(mapp) && SvTYPE(SvRV(mapp)) == SVt_PVHV)
              mhv = (HV *)SvRV(mapp);
 
@@ -3527,9 +5406,11 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
 
            hm = mkmask(items);
            ht = solv_calloc(hm + 1, sizeof(*ht));
-           names = solv_calloc(items, sizeof(char *));
+           names = depnames = solv_calloc(items, sizeof(char *));
+
+           /* create pkgname -> edge hash, store edge -> pkgname data */
            nv = 1;
-           for (i = 3; i < items; i++)
+           for (i = pkgstart; i < items; i++)
              {
                char *s = SvPV_nolen(ST(i));
                h = strhash(s) & hm;
@@ -3547,14 +5428,40 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                names[id] = s;
              }
 
+           if (pkg2srchv)
+             {
+               /* redo the hash with src names instead of pkg names */
+               depnames = solv_calloc(nv, sizeof(char *));
+               memset(ht, 0, (hm + 1) * sizeof(*ht));
+               for (i = 1; i < nv; i++)
+                 {
+                   char *s = names[i];
+                   svp = hv_fetch(pkg2srchv, s, strlen(s), 0);
+                   if (svp)
+                     {
+                       char *ns = SvPV_nolen(*svp);
+                       if (ns)
+                         s = ns;
+                     }
+                   depnames[i] = s;
+                   h = strhash(s) & hm;
+                   hh = HASHCHAIN_START;
+                   while ((id = ht[h]) != 0)
+                     h = HASHCHAIN_NEXT(h, hh, hm);
+                   ht[h] = i;
+                 }
+             }
+
            /* we now know all vertices, create edges */
            queue_push(&vedge, 0);
            queue_push(&edata, 0);
+           map_init(&edgeunifymap, nv);
            for (i = 1; i < nv; i++)
              {
+               int edgestart = edata.count;
                svp = hv_fetch(deps, names[i], strlen(names[i]), 0);
                sv = svp ? *svp : 0;
-               queue_push(&vedge, edata.count);
+               queue_push(&vedge, edgestart);
                if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
                  {
                    AV *av = (AV *)SvRV(sv);
@@ -3586,20 +5493,35 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                        hh = HASHCHAIN_START;
                        while ((id = ht[h]) != 0)
                          {
-                           if (!strcmp(names[id], s))
-                             break;
+                           if (!strcmp(depnames[id], s))
+                             {
+                               if (id != i && !MAPTST(&edgeunifymap, id))
+                                 {
+                                   MAPSET(&edgeunifymap, id);
+                                   queue_push(&edata, id);
+                                 }
+                               if (names == depnames)
+                                 break;        /* no other entry with same name */
+                             }
                            h = HASHCHAIN_NEXT(h, hh, hm);
                          }
-                       if (!id)
-                         continue;     /* not known, ignore */
-                       if (id == i)
-                         continue;     /* no self edge */
-                       queue_push(&edata, id);
                      }
                  }
-               queue_push(&edata, 0);
+               for (j = edgestart; j < edata.count; j++)
+                 {
+#ifdef MAPCLR_AT
+                   MAPCLR_AT(&edgeunifymap, edata.elements[j]);
+#else
+                   MAPCLR(&edgeunifymap, edata.elements[j]);
+#endif
+                 }
+               queue_push(&edata, 0);  /* terminate edge array */
              }
+           /* free no longer needed stuff */
+           map_free(&edgeunifymap);
            solv_free(ht);
+           if (depnames != names)
+             depnames = solv_free(depnames);
 
            if (0)
              {
@@ -3659,6 +5581,13 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                    continue;
                  }
                /* oh no, we found a cycle, record and break it */
+               if (depsortsccs && !didsccs && cycp)
+                 {
+                   /* use Tarjan's SCC algorithm */
+                   find_sccs(&edata, &vedge, &cycles);
+                   queue_push(&cycles, 0);
+                   didsccs = cycles.count;
+                 }
                cy = cycles.count;
                for (j = todo.count - 1; j >= 0; j--)
                  if (todo.elements[j] == -i)
@@ -3694,7 +5623,10 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                todo.count = cycstart + 1;
              }
 
-           /* recored cycles */
+           if (didsccs && depsortsccs != 2)
+             queue_truncate(&cycles, didsccs - 1);
+
+           /* record cycles */
            if (cycles.count && cycp && SvROK(cycp) && SvTYPE(SvRV(cycp)) == SVt_PVAV)
              {
                AV *av = (AV *)SvRV(cycp);
@@ -3719,6 +5651,27 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
            solv_free(names);
        }
 
+int
+setdepsortsccs(int flag)
+    CODE:
+       depsortsccs = flag;
+       RETVAL = flag;
+    OUTPUT:
+       RETVAL
+
+int
+setgenmetaalgo(int algo)
+    CODE:
+       if (algo < 0)
+           algo = 1;
+       if (algo > 1)
+           croak("BSSolv::setgenmetaalgo: unsupported algo %d\n", algo);
+       genmetaalgo = algo;
+       RETVAL = algo;
+    OUTPUT:
+       RETVAL
+
+
 void
 gen_meta(AV *subp, ...)
     PPCODE:
@@ -3804,7 +5757,7 @@ gen_meta(AV *subp, ...)
                  }
                if (cycle)
                  {
-                   lp->killed = 1;
+                   lp->killed = 1;     /* killed because line includes a subpackage */
                    if (cycle > 1)      /* ignore self cycles */
                      queue_push(&cycles, i);
                  }
@@ -3820,9 +5773,9 @@ gen_meta(AV *subp, ...)
                char *cycledata = 0;
                int cycledatalen = 0;
 
+               /* create hash of cycle packages */
                cycledata = solv_extend(cycledata, cycledatalen, 1, 1, 255);
-               cycledata[0] = 0;
-               cycledatalen += 1;
+               cycledata[cycledatalen++] = 0;
                hm = mkmask(cycles.count);
                ht = solv_calloc(hm + 1, sizeof(*ht));
                for (i = 0; i < cycles.count; i++)
@@ -3840,18 +5793,23 @@ gen_meta(AV *subp, ...)
                          break;
                        h = HASHCHAIN_NEXT(h, hh, hm);
                      }
-                   if (id)
-                     continue;
-                   cycledata = solv_extend(cycledata, cycledatalen, strlen(s) + 1, 1, 255);
-                   ht[h] = cycledatalen;
-                   strcpy(cycledata + cycledatalen, s);
-                   cycledatalen += strlen(s) + 1;
+                   if (!id)
+                     {
+                       int l = strlen(s);
+                       cycledata = solv_extend(cycledata, cycledatalen, l + 1, 1, 255);
+                       ht[h] = cycledatalen;   /* point to name */
+                       strcpy(cycledata + cycledatalen, s);
+                       cycledatalen += l + 1;
+                     }
                    if (se)
                      *se = '/';
                  }
+
                for (i = 0, lp = lines; i < nlines; i++, lp++)
                  {
-                   if (lp->killed || !lp->nslash)
+                   if (!lp->nslash)
+                     continue;
+                   if (lp->killed && genmetaalgo == 0)
                      continue;
                    lo = strchr(lp->l + 34, '/') + 1;
                    for (s2 = lo; *s2; s2++)
@@ -3869,12 +5827,12 @@ gen_meta(AV *subp, ...)
                          *s2 = '/';
                          if (id)
                            {
-                             lp->killed = 1;
+                             lp->killed = 2;   /* killed because it containes a cycle package */
                              break;
                            }
                          lo = s2 + 1;
                        }
-                   if (lp->killed)
+                   if (lp->killed == 2)
                      continue;
                    h = strhash(lo) & hm;
                    hh = HASHCHAIN_START;
@@ -3885,14 +5843,12 @@ gen_meta(AV *subp, ...)
                        h = HASHCHAIN_NEXT(h, hh, hm);
                      }
                    if (id)
-                     {
-                       lp->killed = 1;
-                     }
+                     lp->killed = 2;   /* killed because it containes a cycle package */
                  }
                solv_free(ht);
                cycledata = solv_free(cycledata);
-               queue_free(&cycles);
              }
+           queue_free(&cycles);
 
            /* cycles are pruned, now sort array */
            if (nlines > 1)
@@ -3903,7 +5859,10 @@ gen_meta(AV *subp, ...)
            for (i = 0, lp = lines; i < nlines; i++, lp++)
              {
                if (lp->killed)
-                 continue;
+                 {
+                   if (genmetaalgo == 0 || lp->killed != 2)
+                     continue;
+                 }
                s = lp->l;
                h = strnhash(s, 10);
                h = strhash_cont(s + lp->lastoff, h) & hm;
@@ -3915,6 +5874,13 @@ gen_meta(AV *subp, ...)
                      break;
                    h = HASHCHAIN_NEXT(h, hh, hm);
                  }
+               if (id && genmetaalgo == 1 && lp->killed == 2)
+                 {
+                   /* also kill old line of same level */
+                   struct metaline *lp2 = lines + (id - 1);
+                   if (!lp2->killed && lp2->nslash == lp->nslash)
+                     lp2->killed = 1;
+                 }
                if (id)
                  lp->killed = 1;
                else
@@ -3937,6 +5903,66 @@ gen_meta(AV *subp, ...)
            solv_free(lines);
        }
 
+void
+add_meta(AV *new_meta, SV *sv, const char *bin, const char *packid = 0)
+    PPCODE:
+       {
+           const char *p, *np;
+           char *buf;
+           size_t l, bufl, binl, packidl;
+           int first = 1;
+           if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
+               AV *av = (AV *)SvRV(sv);
+               SV **svp = av_fetch(av, 0, 0);
+               sv = svp ? *svp : 0;
+           }
+           if (!sv)
+               XSRETURN_EMPTY;
+           p = SvPV_nolen(sv);
+           binl = strlen(bin);
+           bufl = binl + 256;
+           buf = malloc(bufl);
+           if (!buf) {
+               croak("out of mem\n");
+               XSRETURN_EMPTY;
+           }
+           packidl = packid ? strlen(packid) : 0;
+           for (;;) {
+               np = strchr(p, '\n');
+               l = np ? np - p : strlen(p);
+               if (l > 34) {
+                   if (l + binl + 1 + 1 > bufl) {
+                       bufl = l + binl + 256;
+                       buf = realloc(buf, bufl);
+                       if (!buf) {
+                           croak("out of mem\n");
+                           XSRETURN_EMPTY;
+                       }
+                   }
+                   strncpy(buf, p, 34);
+                   strcpy(buf + 34, bin);
+                   buf[34 + binl] = '/';
+                   strncpy(buf + 34 + binl + 1, p + 34, l - 34);
+                   l += binl + 1;
+                   buf[l] = 0;
+                   if (first) {
+                       if (packidl && l > packidl + 1 && buf[l - packidl - 1] == '/' && !strcmp(buf + l - packidl, packid)) {
+                           free(buf);
+                           XSRETURN_EMPTY;
+                       }
+                       l = 34 + binl;
+                       buf[l] = 0;
+                       first = 0;
+                   }
+                   av_push(new_meta, newSVpvn(buf, l));
+               }
+               if (!np)
+                   break;
+               p = np + 1;
+           }
+           free(buf);
+       }
+
 SV *
 thawcache(SV *sv)
     CODE:
@@ -4266,6 +6292,9 @@ new(char *packname = "BSSolv::pool")
            buildservice_dodurl = pool_str2id(pool, "buildservice:dodurl", 1);
            expander_directdepsend = pool_str2id(pool, "-directdepsend--", 1);
            buildservice_dodcookie = pool_str2id(pool, "buildservice:dodcookie", 1);
+           buildservice_dodresources = pool_str2id(pool, "buildservice:dodresources", 1);
+           buildservice_annotation = pool_str2id(pool, "buildservice:annotation", 1);
+           buildservice_modules = pool_str2id(pool, "buildservice:modules", 1);
            pool_freeidhashes(pool);
            RETVAL = pool;
        }
@@ -4342,9 +6371,11 @@ repofrombins(BSSolv::pool pool, char *name, char *dir, ...)
                  continue;
                if (strcmp(s + sl - 4, ".rpm")
                     && strcmp(s + sl - 4, ".deb")
+                    && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk"))
 #ifdef ARCH_ADD_WITH_PKGID
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
+                    && (sl < 12 || strcmp(s + sl - 12, ".pkg.tar.zst"))
 #endif
                   )
                  continue;
@@ -4364,14 +6395,16 @@ repofrombins(BSSolv::pool pool, char *name, char *dir, ...)
        RETVAL
 
 BSSolv::repo
-repofromdata(BSSolv::pool pool, char *name, HV *rhv)
+repofromdata(BSSolv::pool pool, char *name, SV *rv)
     CODE:
        {
            Repo *repo;
            Repodata *data;
+           if (!SvROK(rv) || (SvTYPE(SvRV(rv)) != SVt_PVHV && SvTYPE(SvRV(rv)) != SVt_PVAV))
+               croak("BSSolv::pool::repofromdata: rv is not a HASH or ARRAY reference");
            repo = repo_create(pool, name);
            data = repo_add_repodata(repo, 0);
-           data2solvables(repo, data, rhv);
+           data2solvables(repo, data, SvRV(rv), 0);
            if (name && !strcmp(name, "/external/"))
              repodata_set_void(data, SOLVID_META, buildservice_external);
            repo_internalize(repo);
@@ -4381,7 +6414,7 @@ repofromdata(BSSolv::pool pool, char *name, HV *rhv)
        RETVAL
 
 void
-createwhatprovides(BSSolv::pool pool)
+createwhatprovides(BSSolv::pool pool, int unorderedrepos = 0)
     CODE:
        if (pool->considered)
          {
@@ -4389,7 +6422,7 @@ createwhatprovides(BSSolv::pool pool)
            solv_free(pool->considered);
          }
        pool->considered = solv_calloc(sizeof(Map), 1);
-       create_considered(pool, 0, pool->considered);
+       create_considered(pool, 0, pool->considered, unorderedrepos);
        pool_createwhatprovides(pool);
 
 void
@@ -4402,7 +6435,7 @@ whatprovides(BSSolv::pool pool, char *str)
     PPCODE:
        {
            Id p, pp, id;
-           id = dep2id(pool, str);
+           id = testcase_str2dep(pool, str);
            if (id)
              FOR_PROVIDES(p, pp, id)
                XPUSHs(sv_2mortal(newSViv((IV)p)));
@@ -4415,7 +6448,7 @@ whatrequires(BSSolv::pool pool, char *str)
            Id p, id;
            Id *pp;
            Solvable *s;
-           id = dep2id(pool, str);
+           id = testcase_str2dep(pool, str);
            if (id)
              {
                for (p = 2; p < pool->nsolvables; p++)
@@ -4469,6 +6502,20 @@ pkg2name(BSSolv::pool pool, int p)
     OUTPUT:
        RETVAL
 
+const char *
+pkg2evr(BSSolv::pool pool, int p)
+    CODE:
+       RETVAL = pool_id2str(pool, pool->solvables[p].evr);
+    OUTPUT:
+       RETVAL
+
+const char *
+pkg2arch(BSSolv::pool pool, int p)
+    CODE:
+       RETVAL = pool_id2str(pool, pool->solvables[p].arch);
+    OUTPUT:
+       RETVAL
+
 const char *
 pkg2srcname(BSSolv::pool pool, int p)
     CODE:
@@ -4554,6 +6601,33 @@ pkg2checksum(BSSolv::pool pool, int p)
     OUTPUT:
        RETVAL
 
+int
+pkg2inmodule(BSSolv::pool pool, int p)
+    CODE:
+       RETVAL = solvable_lookup_type(pool->solvables + p, buildservice_modules) != 0;
+    OUTPUT:
+       RETVAL
+
+void
+pkg2modules(BSSolv::pool pool, int p)
+    PPCODE:
+       {
+         Solvable *s = pool->solvables + p;
+         Queue modules;
+         int i;
+         queue_init(&modules);
+         solvable_lookup_idarray(s, buildservice_modules, &modules);
+         if (!modules.count && !is_dod_package(s))
+           {
+             Solvable *s2 = find_corresponding_dod(s);
+             if (s2)
+               solvable_lookup_idarray(s2, buildservice_modules, &modules);
+           }
+         for (i = 0; i < modules.count; i++)
+           XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules.elements[i]), 0)));
+         queue_free(&modules);
+       }
+
 int
 verifypkgchecksum(BSSolv::pool pool, int p, char *path)
     CODE:
@@ -4639,10 +6713,34 @@ pkg2data(BSSolv::pool pool, int p)
            ss = solvable_lookup_str(s, buildservice_id);
            if (ss)
              (void)hv_store(RETVAL, "id", 2, newSVpv(ss, 0), 0);
+           ss = solvable_lookup_str(s, buildservice_annotation);
+           if (ss)
+             (void)hv_store(RETVAL, "annotation", 10, newSVpv(ss, 0), 0);
+           if (solvable_lookup_type(s, buildservice_modules))
+             {
+               Queue modules;
+               int i;
+               queue_init(&modules);
+               solvable_lookup_idarray(s, buildservice_modules, &modules);
+               if (modules.count)
+                 {
+                   AV *av = newAV();
+                   for (i = 0; i < modules.count; i++)
+                     av_push(av, newSVpv(pool_id2str(pool, modules.elements[i]), 0));
+                   (void)hv_store(RETVAL, "modules", 7, newRV_noinc((SV*)av), 0);
+                 }
+             }
        }
     OUTPUT:
        RETVAL
 
+const char *
+pkg2annotation(BSSolv::pool pool, int p)
+    CODE:
+       RETVAL = solvable_lookup_str(pool->solvables + p, buildservice_annotation);
+    OUTPUT:
+       RETVAL
+
 void
 repos(BSSolv::pool pool)
     PPCODE:
@@ -4760,6 +6858,32 @@ preparehashes(BSSolv::pool pool, char *prp, SV *gctxprpnotreadysv = 0)
            PUSHs(sv_2mortal(sv));
        }
 
+void
+setmodules(BSSolv::pool pool, AV *modulesav)
+    CODE:
+       {
+         SSize_t i, n = av_len(modulesav);
+         pool->appdata = solv_free(pool->appdata);
+         if (n >= 0 && n < 1000000)
+           {
+             Id *modules = pool->appdata = solv_calloc(n + 2, sizeof(Id));
+             for (i = 0; i <= n; i++)
+               modules[i] = pool_str2id(pool, avlookupstr(modulesav, i), 1);
+             modules[i] = 0;
+           }
+       }
+
+void
+getmodules(BSSolv::pool pool)
+    PPCODE:
+       if (pool->appdata)
+         {
+           Id *modules = pool->appdata;
+           int i;
+           for (i = 0; modules[i]; i++)
+             XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules[i]), 0)));
+         }
+
 void
 DESTROY(BSSolv::pool pool)
     CODE:
@@ -4768,6 +6892,7 @@ DESTROY(BSSolv::pool pool)
            map_free(pool->considered);
            pool->considered = solv_free(pool->considered);
          }
+       pool->appdata = solv_free(pool->appdata);
        pool_free(pool);
 
 
@@ -4775,6 +6900,24 @@ DESTROY(BSSolv::pool pool)
 
 MODULE = BSSolv                PACKAGE = BSSolv::repo          PREFIX = repo
 
+void
+freerepo(BSSolv::repo repo)
+    CODE:
+       {
+         repo_free(repo, 1);
+       }
+
+void
+allpackages(BSSolv::repo repo)
+    PPCODE:
+       {
+           Id p;
+           Solvable *s;
+           EXTEND(SP, repo->nsolvables);
+           FOR_REPO_SOLVABLES(repo, p, s)
+             PUSHs(sv_2mortal(newSViv(p)));
+       }
+
 void
 pkgnames(BSSolv::repo repo)
     PPCODE:
@@ -4783,8 +6926,8 @@ pkgnames(BSSolv::repo repo)
            Id p;
            Solvable *s;
            Map c;
-       
-           create_considered(pool, repo, &c);
+
+           create_considered(pool, repo, &c, 0);
            EXTEND(SP, 2 * repo->nsolvables);
            FOR_REPO_SOLVABLES(repo, p, s)
              {
@@ -4807,7 +6950,7 @@ pkgpaths(BSSolv::repo repo)
            const char *str;
            unsigned int medianr;
        
-           create_considered(pool, repo, &c);
+           create_considered(pool, repo, &c, 0);
            EXTEND(SP, 2 * repo->nsolvables);
            FOR_REPO_SOLVABLES(repo, p, s)
              {
@@ -4923,7 +7066,7 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
                      continue;
                    h = strhash(str) & hm;
                    hh = HASHCHAIN_START;
-                   while ((id = ht[h]) != 0)
+                   while (ht[h])
                      h = HASHCHAIN_NEXT(h, hh, hm);
                    ht[h] = p;
                  }
@@ -4939,11 +7082,14 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
                  continue;
                if (strcmp(s + sl - 4, ".rpm")
                     && strcmp(s + sl - 4, ".deb")
+                    && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk"))
 #ifdef ARCH_ADD_WITH_PKGID
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
+                    && (sl < 12 || strcmp(s + sl - 12, ".pkg.tar.zst"))
 #endif
                   )
+                 continue;
                if (sl > 10 && !strcmp(s + sl - 10, ".patch.rpm"))
                  continue;
                if (sl > 10 && !strcmp(s + sl - 10, ".nosrc.rpm"))
@@ -4957,12 +7103,12 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
                    const char *str = solvable_lookup_str(pool->solvables + id, buildservice_id);
                    if (!strcmp(str, sid))
                      {
-                       /* check location */
+                       /* check location (unless it's a obsbinlnk where the location comes from the content) */
                        unsigned int medianr;
                        str = solvable_get_location(pool->solvables + id, &medianr);
                        if (str[0] == '.' && str[1] == '/')
                          str += 2;
-                       if (!strcmp(str, s))
+                       if (!strcmp(str, s) || (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk")))
                          break;
                      }
                    h = HASHCHAIN_NEXT(h, hh, hm);
@@ -5020,6 +7166,139 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
     OUTPUT:
        RETVAL
 
+void
+modulesfrombins(BSSolv::repo repo, ...)
+    PPCODE:
+       {
+           Pool *pool = repo->pool;
+           Hashtable ht;
+           Hashval h, hh, hm;
+           Queue modules;
+           Queue collectedmodules;
+            Id p, lastid;
+           Solvable *s;
+           int i, j;
+
+           queue_init(&collectedmodules);
+           queue_init(&modules);
+           hm = mkmask(2 * repo->nsolvables + 1);
+           ht = solv_calloc(hm + 1, sizeof(*ht));
+           FOR_REPO_SOLVABLES(repo, p, s)
+             {
+               const char *bsid = solvable_lookup_str(s, buildservice_id);
+               if (!bsid)
+                 continue;
+               if (!strcmp(bsid, "dod"))
+                 h = s->name + s->evr * 37 + s->arch * 129;
+               else
+                 h = strhash(bsid);
+               h &= hm;
+               hh = HASHCHAIN_START;
+               while (ht[h])
+                 h = HASHCHAIN_NEXT(h, hh, hm);
+               ht[h] = p;
+             }
+
+           for (i = 1; i + 1 < items; i += 2)
+             {
+               const char *bsid = SvPV_nolen(ST(i + 1));
+               h = strhash(bsid) & hm;
+               hh = HASHCHAIN_START;
+               while ((p = ht[h]) != 0)
+                 {
+                   const char *bsid2 = solvable_lookup_str(pool->solvables + p, buildservice_id);
+                   if (!strcmp(bsid, bsid2))
+                     break;
+                   h = HASHCHAIN_NEXT(h, hh, hm);
+                 }
+               if (!p)
+                 continue;
+               s = pool->solvables + p;
+               h = (s->name + s->evr * 37 + s->arch * 129) & hm;
+               hh = HASHCHAIN_START;
+               while ((p = ht[h]) != 0)
+                 {
+                   Solvable *s2 = pool->solvables + p;
+                   if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch)
+                     {
+                       lastid = collectedmodules.count ? collectedmodules.elements[collectedmodules.count - 1] : 0;
+                       solvable_lookup_idarray(s2, buildservice_modules, &modules);
+                       for (j = 0; j < modules.count; j++)
+                         if (modules.elements[j] != lastid)
+                           queue_push(&collectedmodules, modules.elements[j]);
+                     }
+                   h = HASHCHAIN_NEXT(h, hh, hm);
+                 }
+             }
+           solv_free(ht);
+           queue_free(&modules);
+           /* sort and unify */
+           solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0);
+           lastid = -1;
+           for (i = 0; i < collectedmodules.count; i++)
+             {
+               if (collectedmodules.elements[i] == lastid)
+                 continue;
+               lastid = collectedmodules.elements[i];
+               XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0)));
+             }
+           queue_free(&collectedmodules);
+       }
+
+void
+missingmodules(BSSolv::repo repo, ...)
+    PPCODE:
+       {
+           Pool *pool = repo->pool;
+            Id p, *pp, *modules, id, req, lastid1, lastid2;
+           Solvable *s;
+           Queue missingq;
+           int i, missing;
+
+           queue_init(&missingq);
+           if (pool->appdata && ((Id *)pool->appdata)[0] && has_keyname(repo, buildservice_modules))
+             {
+               FOR_REPO_SOLVABLES(repo, p, s)
+                 {
+                   if (s->name != buildservice_modules || s->arch != ARCH_SRC || !s->requires)
+                     continue;
+                   id = s->repo->idarraydata[s->provides];
+                   for (modules = pool->appdata; *modules; modules++)
+                     if (id == *modules)
+                       break;
+                   if (!*modules)
+                     continue;
+                   missing = 0;
+                   for (pp = s->repo->idarraydata + s->requires; (req = *pp) != 0; pp++)
+                     if (!match_modules_req(pool, req))
+                       {
+                         missing = 1;
+                         queue_push2(&missingq, id, req);
+                       }
+                   if (!missing)       /* we're good */
+                     queue_push2(&missingq, id, 0);
+                 }
+               /* sort and unify */
+               solv_sort(missingq.elements, missingq.count / 2, sizeof(Id) * 2, missingmodules_cmp, 0);
+               lastid1 = lastid2 = -1;
+               for (i = 0; i < missingq.count; i += 2)
+                 {
+                   if (missingq.elements[i] == lastid1 && missingq.elements[i + 1] == lastid2)
+                     continue;
+                   if (missingq.elements[i] != lastid1)
+                     {
+                       lastid1 = missingq.elements[i];
+                       lastid2 = missingq.elements[i + 1];
+                     }
+                   if (!lastid2)
+                     continue;
+                   lastid2 = missingq.elements[i + 1];
+                   XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid1), 0)));
+                   XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid2), 0)));
+                 }
+               queue_free(&missingq);
+             }
+       }
 
 void
 getpathid(BSSolv::repo repo)
@@ -5033,6 +7312,11 @@ getpathid(BSSolv::repo repo)
                unsigned int medianr;
                const char *str;
                str = solvable_get_location(s, &medianr);
+               /* We need to special case .obsbinlink here where the location
+                * points back into the package. We currently assume that
+                * the name in the full tree is always <name>.obsbinlnk */
+               if (!strncmp(str, "../", 3))
+                 str = pool_tmpjoin(repo->pool, pool_id2str(repo->pool, s->name), ".obsbinlnk", 0);
                PUSHs(sv_2mortal(newSVpv(str, 0)));
                str = solvable_lookup_str(s, buildservice_id);
                PUSHs(sv_2mortal(newSVpv(str, 0)));
@@ -5067,6 +7351,21 @@ dodcookie(BSSolv::repo repo)
     OUTPUT:
        RETVAL
 
+void
+dodresources(BSSolv::repo repo)
+    PPCODE:
+       {
+         Pool *pool = repo->pool;
+         Queue dodresources;
+         int i;
+
+         queue_init(&dodresources);
+         repo_lookup_idarray(repo, SOLVID_META, buildservice_dodresources, &dodresources);
+         for (i = 0; i < dodresources.count; i++)
+           XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, dodresources.elements[i]), 0)));
+         queue_free(&dodresources);
+       }
+
 void
 updatedoddata(BSSolv::repo repo, HV *rhv = 0)
     CODE:
@@ -5084,28 +7383,131 @@ updatedoddata(BSSolv::repo repo, HV *rhv = 0)
            data = repo_add_repodata(repo, REPO_REUSE_REPODATA);
            repodata_unset(data, SOLVID_META, buildservice_dodurl);
            repodata_unset(data, SOLVID_META, buildservice_dodcookie);
+           repodata_unset(data, SOLVID_META, buildservice_dodresources);
            /* add new data */
            if (rhv)
-               data2solvables(repo, data, rhv);
+               data2solvables(repo, data, (SV *)rhv, 1);
            repo_internalize(repo);
        }
 
+void
+setpriority(BSSolv::repo repo, int priority)
+    PPCODE:
+       repo->priority = priority;
+
+int
+mayhavemodules(BSSolv::repo repo)
+    CODE:
+       RETVAL = has_keyname(repo, buildservice_modules);
+    OUTPUT:
+       RETVAL
+
+void
+getmodules(BSSolv::repo repo)
+    PPCODE:
+       if (has_keyname(repo, buildservice_modules))
+         {
+           Pool *pool = repo->pool;
+           Id p, lastid = -1;
+           Solvable *s;
+           Queue collectedmodules;
+           int i;
+
+           queue_init(&collectedmodules);
+           FOR_REPO_SOLVABLES(repo, p, s)
+             if (s->name == buildservice_modules && s->arch == ARCH_SRC && s->repo->idarraydata[s->provides])
+               queue_push(&collectedmodules, s->repo->idarraydata[s->provides]);
+           if (!collectedmodules.count)
+             {
+               Queue modules;
+               queue_init(&modules);
+               FOR_REPO_SOLVABLES(repo, p, s)
+                 {
+                   solvable_lookup_idarray(pool->solvables + p, buildservice_modules, &modules);
+                   for (i = 0; i < modules.count; i++)
+                     {
+                       if (modules.elements[i] == lastid)
+                         continue;
+                       lastid = modules.elements[i];
+                       queue_push(&collectedmodules, modules.elements[i]);
+                     }
+                 }
+               queue_free(&modules);
+             }
+           /* sort and unify */
+           solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0);
+           lastid = -1;
+           for (i = 0; i < collectedmodules.count; i++)
+             {
+               if (collectedmodules.elements[i] == lastid)
+                 continue;
+               lastid = collectedmodules.elements[i];
+               XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0)));
+             }
+           queue_free(&collectedmodules);
+         }
+
+void
+getdodblobs(BSSolv::repo repo)
+    PPCODE:
+       {
+           Pool *pool = repo->pool;
+           int i;
+           Id p;
+           Solvable *s;
+           Stringpool ss;
+           stringpool_init_empty(&ss);
+           FOR_REPO_SOLVABLES(repo, p, s)
+             {
+               const char *str = solvable_lookup_str(s, buildservice_id);
+               unsigned int medianr;
+               const char *s, *se;
+               if (!str || strcmp(str, "dod") != 0)
+                 continue;
+               s = solvable_get_location(pool->solvables + p, &medianr);
+               if ((s = strrchr(s, '?')) == 0)
+                 continue;
+               for (++s; s; s = se ? se + 1 : 0)
+                 {
+                   se = strchr(s, ',');
+                   if (se)
+                     stringpool_strn2id(&ss, s, se - s, 1);
+                   else
+                     stringpool_str2id(&ss, s, 1);
+                 }
+             }
+           for (i = 2; i < ss.nstrings; i++)
+             {
+               XPUSHs(sv_2mortal(newSVpv(stringpool_id2str(&ss, i), 0)));
+             }
+           stringpool_free(&ss);
+       }
 
-MODULE = BSSolv                PACKAGE = BSSolv::expander      PREFIX = expander
 
+MODULE = BSSolv                PACKAGE = BSSolv::expander      PREFIX = expander
 
 BSSolv::expander
 new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
     CODE:
        {
            SV *sv, **svp;
-           char *str;
-           int i, neg;
-           Id id, id2;
+           char *str, *p;
+           int i;
+           Id id;
            Expander *xp;
-
-           xp = calloc(sizeof(Expander), 1);
-           xp->pool = pool;
+           Queue preferpos;
+           Queue preferneg;
+           Queue ignore;
+           Queue conflict;
+           Queue fileprovides;
+           int debug = 0;
+           int options = 0;
+
+           queue_init(&preferpos);
+           queue_init(&preferneg);
+           queue_init(&ignore);
+           queue_init(&conflict);
+           queue_init(&fileprovides);
            svp = hv_fetch(config, "prefer", 6, 0);
            sv = svp ? *svp : 0;
            if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
@@ -5120,37 +7522,10 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                    str = SvPV_nolen(sv);
                    if (!str)
                      continue;
-                   neg = 0;
                    if (*str == '-')
-                     {
-                       neg = 1;
-                       str++;
-                     }
-                   id = pool_str2id(pool, str, 1);
-                   id2 = 0;
-                   if ((str = strchr(str, ':')) != 0)
-                     id2 = pool_str2id(pool, str + 1, 1);
-                   if (neg)
-                     {
-                       MAPEXP(&xp->preferneg, id);
-                       MAPSET(&xp->preferneg, id);
-                       if (id2)
-                         {
-                           MAPEXP(&xp->prefernegx, id2);
-                           MAPSET(&xp->prefernegx, id2);
-                         }
-                     }
+                     queue_push(&preferneg, pool_str2id(pool, str + 1, 1));
                    else
-                     {
-                       queue_push(&xp->preferposq, id);
-                       MAPEXP(&xp->preferpos, id);
-                       MAPSET(&xp->preferpos, id);
-                       if (id2)
-                         {
-                           MAPEXP(&xp->preferposx, id2);
-                           MAPSET(&xp->preferposx, id2);
-                         }
-                     }
+                     queue_push(&preferpos, pool_str2id(pool, str, 1));
                  }
              }
            svp = hv_fetch(config, "ignoreh", 7, 0);
@@ -5159,7 +7534,6 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
              {
                HV *hv = (HV *)SvRV(sv);
                HE *he;
-
                hv_iterinit(hv);
                while ((he = hv_iternext(hv)) != 0)
                  {
@@ -5167,18 +7541,7 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                    str = hv_iterkey(he, &strl);
                    if (!str)
                      continue;
-                
-                   id = pool_str2id(pool, str, 1);
-                   id2 = 0;
-                   if ((str = strchr(str, ':')) != 0)
-                     id2 = pool_str2id(pool, str + 1, 1);
-                   MAPEXP(&xp->ignored, id);
-                   MAPSET(&xp->ignored, id);
-                   if (id2)
-                     {
-                       MAPEXP(&xp->ignoredx, id2);
-                       MAPSET(&xp->ignoredx, id2);
-                     }
+                   queue_push(&ignore, pool_str2id(pool, str, 1));
                  }
              }
            svp = hv_fetch(config, "conflict", 8, 0);
@@ -5188,9 +7551,6 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                AV *av = (AV *)SvRV(sv);
                for (i = 0; i <= av_len(av); i++)
                  {
-                   char *p;
-                   Id id2;
-
                    svp = av_fetch(av, i, 0);
                    if (!svp)
                      continue;
@@ -5205,46 +7565,28 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                    str = p + 1;
                    while ((p = strchr(str, ',')) != 0)
                      {
-                       id2 = pool_strn2id(pool, str, p - str, 1);
-                       queue_push2(&xp->conflictsq, id, id2);
-                       MAPEXP(&xp->conflicts, id);
-                       MAPSET(&xp->conflicts, id);
-                       MAPEXP(&xp->conflicts, id2);
-                       MAPSET(&xp->conflicts, id2);
+                       queue_push2(&conflict, id, pool_strn2id(pool, str, p - str, 1));
                        str = p + 1;
                      }
-                   id2 = pool_str2id(pool, str, 1);
-                   queue_push2(&xp->conflictsq, id, id2);
-                   MAPEXP(&xp->conflicts, id);
-                   MAPSET(&xp->conflicts, id);
-                   MAPEXP(&xp->conflicts, id2);
-                   MAPSET(&xp->conflicts, id2);
+                   queue_push2(&conflict, id, pool_str2id(pool, str, 1));
                  }
              }
-           /* XXX: this modifies the pool, which is a bit unclean! */
            svp = hv_fetch(config, "fileprovides", 12, 0);
            sv = svp ? *svp : 0;
            if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)
              {
                HV *hv = (HV *)SvRV(sv);
                I32 strl;
-               Queue q;
 
-               xp->havefileprovides = 1;
                hv_iterinit(hv);
-               queue_init(&q);
                while ((sv = hv_iternextsv(hv, &str, &strl)) != 0)
                  {
                    AV *av;
-                   Id p, pp;
-                   int havenew = 0;
+                   Id id2;
 
                    if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV)
                      continue;
                    id = pool_str2id(pool, str, 1);
-                   queue_empty(&q);
-                   FOR_PROVIDES(p, pp, id)
-                     queue_push(&q, p);
                    av = (AV *)SvRV(sv);
                    for (i = 0; i <= av_len(av); i++)
                      {
@@ -5256,44 +7598,48 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                        if (!str)
                          continue;
                        id2 = pool_str2id(pool, str, 0);
-                       FOR_PROVIDES(p, pp, id2)
+                       if (!id2)
+                         continue;
+                       if (id)
                          {
-                           int j;
-                           for (j = 0; j < q.count; j++)
-                             {
-                               if (q.elements[j] == p)
-                                 break;
-                               if (q.elements[j] > p)
-                                 {
-                                   queue_insert(&q, j, p);
-                                   havenew = 1;
-                                   break;
-                                 }
-                             }
-                           if (j == q.count)
-                             {
-                               queue_push(&q, p);
-                               havenew = 1;
-                             }
+                           queue_push(&fileprovides, id);      /* start name block */
+                           id = 0;
                          }
+                       queue_push(&fileprovides, id2);
                      }
-                   if (havenew)
-                     pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
+                   if (id == 0)
+                     queue_push(&fileprovides, 0);     /* had at least one entry, finish name block */
                  }
-               queue_free(&q);
              }
+           options |= EXPANDER_OPTION_USERECOMMENDSFORCHOICES;
            svp = hv_fetch(config, "expandflags:ignoreconflicts", 27, 0);
            sv = svp ? *svp : 0;
            if (sv && SvTRUE(sv))
-             xp->ignoreconflicts = 1;
-           svp = hv_fetch(config, "expand_dbg", 10, 0);
+             options |= EXPANDER_OPTION_IGNORECONFLICTS;
+           svp = hv_fetch(config, "expandflags:dorecommends", 24, 0);
            sv = svp ? *svp : 0;
            if (sv && SvTRUE(sv))
-             xp->debug = 1;
-           sv = get_sv("Build::expand_dbg", FALSE);
+             options |= EXPANDER_OPTION_DORECOMMENDS;
+           svp = hv_fetch(config, "expandflags:dosupplements", 25, 0);
+           sv = svp ? *svp : 0;
            if (sv && SvTRUE(sv))
-             xp->debug = 1;
-        xp->userecommendsforchoices = 1;
+             options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES;
+           svp = hv_fetch(config, "expand_dbg", 10, 0);
+           sv = svp ? *svp : 0;
+           if (sv && SvOK(sv))
+             debug = SvIV(sv);
+           else
+             {
+               sv = get_sv("Build::expand_dbg", FALSE);
+               if (sv && SvOK(sv))
+                 debug = SvIV(sv);
+             }
+           xp = expander_create(pool, &preferpos, &preferneg, &ignore, &conflict, &fileprovides, debug, options);
+           queue_free(&preferpos);
+           queue_free(&preferneg);
+           queue_free(&ignore);
+           queue_free(&conflict);
+           queue_free(&fileprovides);
            RETVAL = xp;
        }
     OUTPUT:
@@ -5306,131 +7652,71 @@ expand(BSSolv::expander xp, ...)
        {
            Pool *pool;
            int i, nerrors;
-           Id id, who, conflbuf[16];
-           Queue revertignore, in, out, confl;
-           int oldignoreignore = xp->ignoreignore;
-           int ignoreignore = 0;
-           Map oldignored, oldignoredx;
-           int ignoremapssaved = 0;
-
-           queue_init(&revertignore);
+           Id id, who, indepbuf[64];
+           Queue ignoreq, in, out, indep;
+           int directdepsend = 0;
+           int options = 0;
+
+           queue_init(&ignoreq);
            queue_init(&in);
            queue_init(&out);
-           queue_init_buffer(&confl, conflbuf, sizeof(conflbuf)/sizeof(*conflbuf));
+           queue_init_buffer(&indep, indepbuf, sizeof(indepbuf)/sizeof(*indepbuf));
            pool = xp->pool;
            if (xp->debug)
              expander_dbg(xp, "expand args:");
            for (i = 1; i < items; i++)
              {
                char *s = SvPV_nolen(ST(i));
+               int deptype = DEPTYPE_REQUIRES;
+
                if (xp->debug)
                  expander_dbg(xp, " %s", s);
+               if (*s == '-' && s[1] == '-')
+                 {
+                   /* expand option */
+                   if (!strcmp(s, "--ignoreignore--"))
+                     options |= EXPANDER_OPTION_IGNOREIGNORE;
+                   else if (!strcmp(s, "--directdepsend--"))
+                     directdepsend = 1;
+                   else if (!strcmp(s, "--dorecommends--"))
+                     options |= EXPANDER_OPTION_DORECOMMENDS;
+                   else if (!strcmp(s, "--dosupplements--"))
+                     options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES;
+                   else if (!strcmp(s, "--ignoreconflicts--"))
+                     options |= EXPANDER_OPTION_IGNORECONFLICTS;
+                   continue;
+                 }
                if (*s == '-')
                  {
-                   Id id;
-                   if (s[1] == '-' && !strcmp(s, "--ignoreignore--"))
-                     {
-                       ignoreignore = 1;
-                       continue;
-                     }
+                   /* ignore dependency */
                    id = pool_str2id(pool, s + 1, 1);
-                   if (id == expander_directdepsend)
-                     {
-                       queue_push(&in, id);
-                       continue;
-                     }
-                   queue_push(&revertignore, id);
+                   queue_push(&ignoreq, id);
+                   continue;
                  }
-               else if (*s == '!')
+               if (*s == '!')
                  {
-                   Id id = dep2id(pool, s + (s[1] == '!' ? 2 : 1));
-                   queue_push2(&confl, id, s[1] == '!' ? 1 : 0);
+                   deptype = DEPTYPE_CONFLICTS;
+                   s++;
+                   if (*s == '!')
+                     {
+                       deptype = DEPTYPE_OBSOLETES;
+                       s++;
+                     }
                  }
+               id = dep2id(pool, s);
+               if (deptype == DEPTYPE_REQUIRES && !directdepsend)
+                 queue_push(&in, id);
                else
-                 {
-                   Id id = dep2id(pool, s);
-                   queue_push(&in, id);
-                 }
+                 queue_push2(&indep, deptype, id);
              }
            if (xp->debug)
              expander_dbg(xp, "\n");
 
-           if (ignoreignore && revertignore.count)
-             {
-               /* bad: have direct ignores and project config ignores */
-               oldignored = xp->ignored;
-               oldignoredx = xp->ignoredx;
-               ignoremapssaved = 1;
-               /* clear project config maps */
-               memset(&xp->ignored, 0, sizeof(xp->ignored));
-               memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
-             }
-
-           if (revertignore.count)
-             {
-               /* mix direct ignores with ignores from project config */
-               int revertcnt = revertignore.count;
-               for (i = 0; i < revertcnt; i++)
-                 {
-                   const char *ss;
-                   id = revertignore.elements[i];
-                   MAPEXP(&xp->ignored, id);
-                   if (MAPTST(&xp->ignored, id))
-                     continue;
-                   MAPSET(&xp->ignored, id);
-                   queue_push(&revertignore, id);
-                   if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
-                     {
-                       id = pool_str2id(pool, ss + 1, 1);
-                       MAPEXP(&xp->ignoredx, id);
-                       if (MAPTST(&xp->ignoredx, id))
-                         continue;
-                       MAPSET(&xp->ignoredx, id);
-                       queue_push(&revertignore, -id);
-                     }
-                 }
-               queue_deleten(&revertignore, 0, revertcnt);
-             }
-           else if (ignoreignore)
-             {
-               /* no direct ignores, disable ignore processing */
-               xp->ignoreignore = 1;
-             }
-
-           MAPEXP(&xp->ignored, pool->ss.nstrings);
-           MAPEXP(&xp->ignoredx, pool->ss.nstrings);
-           MAPEXP(&xp->preferpos, pool->ss.nstrings);
-           MAPEXP(&xp->preferposx, pool->ss.nstrings);
-           MAPEXP(&xp->preferneg, pool->ss.nstrings);
-           MAPEXP(&xp->prefernegx, pool->ss.nstrings);
-           MAPEXP(&xp->conflicts, pool->ss.nstrings);
-
-           nerrors = expander_expand(xp, &in, &out, &confl);
-
-           /* revert ignores */
-           xp->ignoreignore = oldignoreignore;
-           if (ignoremapssaved)
-             {
-               map_free(&xp->ignored);
-               map_free(&xp->ignoredx);
-               xp->ignored = oldignored;
-               xp->ignoredx = oldignoredx;
-             }
-           else
-             {
-               for (i = 0; i < revertignore.count; i++)
-                 {
-                   id = revertignore.elements[i];
-                   if (id > 0)
-                     MAPCLR(&xp->ignored, id);
-                   else
-                     MAPCLR(&xp->ignoredx, -id);
-                 }
-             }
-           queue_free(&revertignore);
+           nerrors = expander_expand(xp, &in, &indep, &out, &ignoreq, options);
 
            queue_free(&in);
-           queue_free(&confl);
+           queue_free(&indep);
+           queue_free(&ignoreq);
 
            if (nerrors)
              {
@@ -5445,19 +7731,43 @@ expand(BSSolv::expander xp, ...)
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
+                         sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who));
                        else
                          sv = newSVpvf("nothing provides %s", pool_dep2str(pool, id));
                        i += 3;
                      }
-                   else if (type == ERROR_CONFLICTINGPROVIDER)
+                   else if (type == ERROR_ALLCONFLICT)
                      {
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("conflict for provider of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
+                         sv = newSVpvf("%s conflicts with always true %s", solvid2name(pool, who), pool_dep2str(pool, id));
+                       else
+                         sv = newSVpvf("conflict with always true %s", pool_dep2str(pool, id));
+                       i += 3;
+                     }
+                   else if (type == ERROR_CONFLICT)
+                     {
+                       Id who2 = out.elements[i + 2];
+                       who = out.elements[i + 1];
+                       if (!who && who2 >= 0)
+                         sv = newSVpvf("conflicts with %s", solvid2name(pool, who2));
+                       else if (who2 < 0)
+                         sv = newSVpvf("%s obsoletes %s", solvid2name(pool, who), solvid2name(pool, -who2));
+                       else
+                         sv = newSVpvf("%s conflicts with %s", solvid2name(pool, who), solvid2name(pool, who2));
+                       i += 3;
+                     }
+                   else if (type == ERROR_CONFLICT2)
+                     {
+                       Id who2 = out.elements[i + 2];
+                       who = out.elements[i + 1];
+                       if (who2 < 0)
+                         sv = newSVpvf("%s is obsoleted by %s", solvid2name(pool, who), solvid2name(pool, -who2));
+                       else if (who2 > 0)
+                         sv = newSVpvf("%s is in conflict with %s", solvid2name(pool, who), solvid2name(pool, who2));
                        else
-                         sv = newSVpvf("conflict for provider of %s", pool_dep2str(pool, id));
+                         sv = newSVpvf("%s is in conflict", solvid2name(pool, who));
                        i += 3;
                      }
                    else if (type == ERROR_CONFLICTINGPROVIDERS)
@@ -5465,9 +7775,9 @@ expand(BSSolv::expander xp, ...)
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("conflict for all providers of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
+                         sv = newSVpvf("conflict for providers of %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who));
                        else
-                         sv = newSVpvf("conflict for all providers of %s", pool_dep2str(pool, id));
+                         sv = newSVpvf("conflict for providers of %s", pool_dep2str(pool, id));
                        i += 3;
                      }
                    else if (type == ERROR_PROVIDERINFO)
@@ -5475,9 +7785,9 @@ expand(BSSolv::expander xp, ...)
                        Id who2 = out.elements[i + 2];
                        who = out.elements[i + 1];
                        if (who2 < 0)
-                         sv = newSVpvf("(provider %s obsoletes installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
+                         sv = newSVpvf("(provider %s obsoletes %s)", solvid2name(pool, who), solvid2name(pool, -who2));
                        else
-                         sv = newSVpvf("(provider %s conflicts with installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
+                         sv = newSVpvf("(provider %s conflicts with %s)", solvid2name(pool, who), solvid2name(pool, who2));
                        i += 3;
                      }
                    else if (type == ERROR_PROVIDERINFO2)
@@ -5485,17 +7795,20 @@ expand(BSSolv::expander xp, ...)
                        Id who2 = out.elements[i + 2];
                        who = out.elements[i + 1];
                        if (who2 < 0)
-                         sv = newSVpvf("(provider %s is obsoleted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
+                         sv = newSVpvf("(provider %s is obsoleted by %s)", solvid2name(pool, who), solvid2name(pool, -who2));
                        else if (who2 > 0)
-                         sv = newSVpvf("(provider %s is conflicted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
+                         sv = newSVpvf("(provider %s is in conflict with %s)", solvid2name(pool, who), solvid2name(pool, who2));
                        else
-                         sv = newSVpvf("(provider %s is conflicted by the build config)", pool_id2str(pool, pool->solvables[who].name));
+                         sv = newSVpvf("(provider %s is in conflict)", solvid2name(pool, who));
                        i += 3;
                      }
                    else if (type == ERROR_CHOICE)
                      {
                        int j;
                        char *str = "";
+                       for (j = i + 3; out.elements[j]; j++)
+                         ;
+                       solv_sort(out.elements + i + 3, j - (i + 3), sizeof(Id), pkgname_sort_cmp, pool);
                        for (j = i + 3; out.elements[j]; j++)
                          {
                            Solvable *s = pool->solvables + out.elements[j];
@@ -5506,11 +7819,31 @@ expand(BSSolv::expander xp, ...)
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name), str);
+                         sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), solvid2name(pool, who), str);
                        else
                          sv = newSVpvf("have choice for %s: %s", pool_dep2str(pool, id), str);
                        i = j + 1;
                      }
+                   else if (type == ERROR_BADDEPENDENCY)
+                     {
+                       id = out.elements[i + 1];
+                       who = out.elements[i + 2];
+                       if (who)
+                         sv = newSVpvf("cannot parse dependency %s from %s", pool_dep2str(pool, id), solvid2name(pool, who));
+                       else
+                         sv = newSVpvf("cannot parse dependency %s", pool_dep2str(pool, id));
+                       i += 3;
+                     }
+                   else if (type == ERROR_NOPROVIDERINFO)
+                     {
+                       id = out.elements[i + 1];
+                       who = out.elements[i + 2];
+                       if (who)
+                         sv = newSVpvf("(got version %s provided by %s)", pool_id2str(pool, id), solvid2name(pool, who));
+                       else
+                         sv = newSVpvf("(got version %s)", pool_id2str(pool, id));
+                       i += 3;
+                     }
                    else
                      croak("expander: bad error type\n");
                    PUSHs(sv_2mortal(sv));
@@ -5529,27 +7862,31 @@ expand(BSSolv::expander xp, ...)
            queue_free(&out);
        }
 
+void
+debug(BSSolv::expander xp, const char *str)
+    CODE:
+       expander_dbg(xp, "%s", str);
+
+
 const char *
 debugstr(BSSolv::expander xp)
     CODE:
-       if (!xp->debugstr)
-         xp->debugstr = calloc(1, 1);
-       RETVAL = xp->debugstr;
+       RETVAL = xp->debugstr ? xp->debugstr : "";
     OUTPUT:
        RETVAL
 
+const char *
+debugstrclr(BSSolv::expander xp)
+       
+    CODE:
+       RETVAL = xp->debugstr ? xp->debugstr : "";
+    OUTPUT:
+       RETVAL
+    CLEANUP:
+       expander_clrdbg(xp);
 
 void
 DESTROY(BSSolv::expander xp)
     CODE:
-       map_free(&xp->ignored);
-       map_free(&xp->ignoredx);
-       queue_free(&xp->preferposq);
-       map_free(&xp->preferpos);
-       map_free(&xp->preferposx);
-       map_free(&xp->preferneg);
-       map_free(&xp->prefernegx);
-       queue_free(&xp->conflictsq);
-       map_free(&xp->conflicts);
-       solv_free(xp->debugstr);
-       solv_free(xp);
+       expander_free(xp);
+
index ea70fa25182e267dc9c0ddd6683ec13464ac9354..f2194775a19cb96c4fc424b5c977709df3049ffd 100644 (file)
@@ -3,15 +3,16 @@ use ExtUtils::MakeMaker;
 my $solvprefix = '/usr';
 
 my $inc = "-I$solvprefix/include/solv";
-my $lib = '';
+my $lib;
 
 if (grep {$_ eq '--bundled-libsolv'} @ARGV) {
   my $builddir = 'libsolv';
   $inc = "-I$builddir/src -I$builddir/ext";
-  $lib = "-L$builddir/src -L$builddir/ext";
+  $lib = "-L$builddir/src -L$builddir/ext -lsolvext -lsolv -lz -llzma -lzstd";
+} else {
+  $lib = '-lsolvext -lsolv';
 }
 
-$lib = ($lib ? "$lib " : '') . '-lsolvext -lsolv -lz -llzma';
 
 WriteMakefile(
     NAME         => 'BSSolv',
index 787479d56e4ae28ae35f1b96362fa1b0bcb3d369..e66c082b086688c4020d04d323f227d8eaf5d8b7 100644 (file)
@@ -2,7 +2,7 @@ Source: perl-bssolv
 Section: devel
 Priority: extra
 Maintainer: Shuai Fu <shuai01.fu@samsung.com>
-Build-Depends: debhelper (>= 7.0.15), cdbs, libpython2.7, python-dev, dh-python, python-docutils, cmake, dpatch, libbz2-dev, librpm-dev, liblzma-dev, libcurl3 | libcurl4, libcurl4-openssl-dev, libmagic-dev, libexpat1, doxygen, pkg-config, libglib2.0-dev, libssl-dev
+Build-Depends: debhelper (>= 7.0.15), cdbs, libpython2.7, python-dev, dh-python, python-docutils, cmake, dpatch, libbz2-dev, librpm-dev, liblzma-dev, libcurl3 | libcurl4, libcurl4-openssl-dev, libmagic-dev, libexpat1, doxygen, pkg-config, libglib2.0-dev, libssl-dev, libzstd-devel
 Standards-Version: 0.28.0
 Homepage: http://www.tizen.org
 
diff --git a/libsolv-0.6.15/.emacs-dirvars b/libsolv-0.6.15/.emacs-dirvars
deleted file mode 100644 (file)
index e224534..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-;; -*- emacs-lisp -*-
-;;
-;; This file is processed by the dirvars emacs package.  Each variable
-;; setting below is performed when this dirvars file is loaded.
-;;
-c-file-style: "gnu"; 
-fill-column: 78
-indent-tabs-mode: nil
-tab-width: 8
diff --git a/libsolv-0.6.15/.gitignore b/libsolv-0.6.15/.gitignore
deleted file mode 100644 (file)
index 08fac49..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-*~
-build
-doc/*.xml
-tests/solver/data.libzypp/*/*.result
-src/solvversion.h
diff --git a/libsolv-0.6.15/.travis.yml b/libsolv-0.6.15/.travis.yml
deleted file mode 100644 (file)
index 8d7dda5..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-language: C
-before_script: sudo apt-get install cmake
-script: mkdir build && cd build && cmake -DDEBIAN=1 -DMULTI_SEMANTICS=1 .. && make && make test
-
-
diff --git a/libsolv-0.6.15/BUGS b/libsolv-0.6.15/BUGS
deleted file mode 100644 (file)
index 0e33eb5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-Having the same key in multiple repodatas of a repo does not work
-- searching will return both entries
-- repo_write will write a broken solv file
-Fixing the search so that it only returns the last entry will also
-fix repo_write.
-
diff --git a/libsolv-0.6.15/CMakeLists.txt b/libsolv-0.6.15/CMakeLists.txt
deleted file mode 100644 (file)
index fd1426b..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-PROJECT (libsolv)
-
-CMAKE_MINIMUM_REQUIRED (VERSION 2.4)
-
-OPTION (ENABLE_STATIC "Build a static version of the libraries?" OFF)
-OPTION (DISABLE_SHARED "Do not build a shared version of the libraries?" OFF)
-
-OPTION (ENABLE_PERL "Build the perl bindings?" OFF)
-OPTION (ENABLE_PYTHON "Build the python bindings?" OFF)
-OPTION (ENABLE_RUBY "Build the ruby bindings?" OFF)
-OPTION (ENABLE_TCL "Build the Tcl bindings?" OFF)
-
-OPTION (USE_VENDORDIRS "Install the bindings in vendor directories?" OFF)
-
-OPTION (ENABLE_RPMDB "Build with rpm database support?" OFF)
-OPTION (ENABLE_PUBKEY "Build with pubkey support?" OFF)
-OPTION (ENABLE_RPMDB_BYRPMHEADER "Build with rpmdb Header support?" OFF)
-OPTION (ENABLE_RPMMD "Build with rpmmd repository support?" OFF)
-OPTION (ENABLE_SUSEREPO "Build with suse repository support?" OFF)
-OPTION (ENABLE_COMPS "Build with fedora comps support?" OFF)
-OPTION (ENABLE_HELIXREPO "Build with helix repository support?" OFF)
-OPTION (ENABLE_DEBIAN "Build with debian database/repository support?" OFF)
-OPTION (ENABLE_MDKREPO "Build with mandriva/mageia repository support?" OFF)
-OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF)
-OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF)
-OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF)
-OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF)
-
-OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF)
-
-OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF)
-OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF)
-
-#IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4)
-#ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4)
-
-IF (COMMAND cmake_policy)
-  # escape preprocessor, see -DVERSION below
-  CMAKE_POLICY (SET CMP0005 OLD)
-ENDIF (COMMAND cmake_policy)
-
-# Library
-IF (DEFINED LIB)
-  SET (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB}")
-ELSE (DEFINED  LIB)
-  IF (CMAKE_SIZEOF_VOID_P MATCHES "8")
-    SET (LIB_SUFFIX "64")
-  ENDIF (CMAKE_SIZEOF_VOID_P MATCHES "8")
-  SET (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}")
-ENDIF (DEFINED  LIB)
-MESSAGE (STATUS "Libraries will be installed in ${LIB_INSTALL_DIR}")
-# Library
-IF (DEFINED INCLUDE)
-  SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${INCLUDE}")
-else (DEFINED INCLUDE)
-  SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include")
-ENDIF (DEFINED  INCLUDE)
-MESSAGE (STATUS "Header files will be installed in ${INCLUDE_INSTALL_DIR}")
-SET (BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin")
-SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/man")
-IF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man"  AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man")
-  SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man")
-ENDIF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man"  AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man")
-MESSAGE(STATUS "Man pages will be installed in ${MAN_INSTALL_DIR}")
-
-####################################################################
-# CONFIGURATION                                                    #
-####################################################################
-
-# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
-SET (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
-INSTALL( FILES ${CMAKE_MODULE_PATH}/FindLibSolv.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cmake/Modules )
-
-INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake)
-
-SET (have_system x)
-
-IF (FEDORA)
-MESSAGE(STATUS "Building for Fedora")
-ADD_DEFINITIONS (-DFEDORA)
-SET (ENABLE_RPMDB ON)
-SET (ENABLE_RPMMD ON)
-SET (have_system ${have_system}x)
-ENDIF (FEDORA)
-
-IF (DEBIAN)
-MESSAGE (STATUS "Building for Debian")
-ADD_DEFINITIONS (-DDEBIAN)
-SET (ENABLE_DEBIAN ON)
-SET (have_system ${have_system}x)
-ENDIF (DEBIAN)
-
-IF (SUSE)
-MESSAGE (STATUS "Building for SUSE")
-ADD_DEFINITIONS (-DSUSE)
-SET (ENABLE_RPMDB ON)
-SET (ENABLE_PUBKEY ON)
-SET (ENABLE_RPMDB_BYRPMHEADER ON)
-SET (ENABLE_RPMMD ON)
-SET (ENABLE_SUSEREPO ON)
-SET (ENABLE_HELIXREPO ON)
-SET (ENABLE_LINKED_PKGS ON)
-SET (have_system ${have_system}x)
-ENDIF (SUSE)
-
-IF (ARCHLINUX)
-MESSAGE (STATUS "Building for Archlinux")
-ADD_DEFINITIONS (-DARCHLINUX)
-SET (ENABLE_ARCHREPO ON)
-SET (have_system ${have_system}x)
-ENDIF (ARCHLINUX)
-
-IF (MANDRIVA)
-MESSAGE (STATUS "Building for Mandriva")
-ADD_DEFINITIONS (-DMANDRIVA)
-SET (ENABLE_MDKREPO ON)
-SET (ENABLE_RPMDB ON)
-SET (have_system ${have_system}x)
-ENDIF (MANDRIVA)
-
-IF (MAGEIA)
-MESSAGE (STATUS "Building for Mageia")
-ADD_DEFINITIONS (-DMAGEIA)
-SET (ENABLE_MDKREPO ON)
-SET (ENABLE_RPMDB ON)
-SET (ENABLE_RPMMD ON)
-SET (ENABLE_LZMA_COMPRESSION ON)
-SET (have_system ${have_system}x)
-ENDIF (MAGEIA)
-
-IF (HAIKU)
-MESSAGE(STATUS "Building for Haiku")
-FIND_LIBRARY(HAIKU_BE_LIBRARY NAMES be)
-FIND_LIBRARY(HAIKU_NETWORK_LIBRARY NAMES network)
-FIND_LIBRARY(HAIKU_PACKAGE_LIBRARY NAMES package)
-SET (HAIKU_SYSTEM_LIBRARIES
-    ${HAIKU_BE_LIBRARY} ${HAIKU_NETWORK_LIBRARY} ${HAIKU_PACKAGE_LIBRARY})
-ADD_DEFINITIONS (-DHAIKU)
-SET (ENABLE_HAIKU ON)
-SET (have_system ${have_system}x)
-ENDIF (HAIKU)
-
-IF (${have_system} STREQUAL x)
-    MESSAGE (STATUS "Building for no system")
-ENDIF (${have_system} STREQUAL x)
-IF (${have_system} STRGREATER xx)
-    MESSAGE (FATAL_ERROR "Can only compile for one system type.")
-ENDIF (${have_system} STRGREATER xx)
-
-IF (ENABLE_ARCHREPO)
-SET (ENABLE_LZMA_COMPRESSION ON)
-ENDIF (ENABLE_ARCHREPO)
-
-FIND_PACKAGE (EXPAT REQUIRED)
-FIND_PACKAGE (ZLIB REQUIRED)
-IF (ENABLE_LZMA_COMPRESSION)
-FIND_PACKAGE (LZMA REQUIRED)
-ENDIF (ENABLE_LZMA_COMPRESSION)
-IF (ENABLE_BZIP2_COMPRESSION)
-FIND_PACKAGE (BZip2 REQUIRED)
-ENDIF (ENABLE_BZIP2_COMPRESSION)
-
-IF (RPM5)
-MESSAGE (STATUS "Enabling RPM 5 support")
-ADD_DEFINITIONS (-DRPM5)
-SET (ENABLE_RPMDB ON)
-SET (ENABLE_RPMMD ON)
-FIND_PACKAGE (PkgConfig REQUIRED)
-PKG_CHECK_MODULES (RPM REQUIRED rpm)
-INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIRS})
-ENDIF (RPM5)
-
-IF (MULTI_SEMANTICS)
-MESSAGE (STATUS "Enabling multi dist support")
-ADD_DEFINITIONS (-DMULTI_SEMANTICS)
-ENDIF (MULTI_SEMANTICS)
-
-INCLUDE (CheckIncludeFile)
-IF (ENABLE_RPMDB)
-  FIND_LIBRARY (RPMDB_LIBRARY NAMES rpmdb)
-
-  IF (NOT RPMDB_LIBRARY)
-    FIND_LIBRARY (RPMDB_LIBRARY NAMES rpm)
-  ENDIF (NOT RPMDB_LIBRARY)
-
-  FIND_LIBRARY (RPMIO_LIBRARY NAMES rpmio)
-  IF (RPMIO_LIBRARY)
-    SET(RPMDB_LIBRARY ${RPMIO_LIBRARY} ${RPMDB_LIBRARY})
-  ENDIF (RPMIO_LIBRARY)
-
-  IF (RPM5)
-    FIND_LIBRARY (RPMMISC_LIBRARY NAMES rpmmisc)
-    IF (RPMMISC_LIBRARY)
-      SET (RPMDB_LIBRARY ${RPMMISC_LIBRARY} ${RPMDB_LIBRARY})
-    ENDIF (RPMMISC_LIBRARY)
-  ENDIF (RPM5)
-
-  # check if rpm contains a bundled berkeley db
-  CHECK_INCLUDE_FILE(rpm/db.h HAVE_RPM_DB_H)
-  IF (NOT HAVE_RPM_DB_H)
-    FIND_LIBRARY (DB_LIBRARY NAMES db)
-    IF (DB_LIBRARY)
-      SET (RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY})
-    ENDIF (DB_LIBRARY)
-  ENDIF (NOT HAVE_RPM_DB_H)
-  INCLUDE (CheckLibraryExists)
-  CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS)
-ENDIF (ENABLE_RPMDB)
-
-IF (ENABLE_PUBKEY)
-  SET (ENABLE_PGPVRFY ON)
-ENDIF (ENABLE_PUBKEY)
-
-INCLUDE (CheckFunctionExists)
-INCLUDE (TestBigEndian)
-
-CHECK_FUNCTION_EXISTS (strchrnul HAVE_STRCHRNUL)
-CHECK_FUNCTION_EXISTS (fopencookie HAVE_FOPENCOOKIE)
-CHECK_FUNCTION_EXISTS (funopen HAVE_FUNOPEN)
-TEST_BIG_ENDIAN (WORDS_BIGENDIAN)
-
-IF (${CMAKE_MAJOR_VERSION} GREATER 2)
-INCLUDE (CMakePushCheckState)
-INCLUDE (CheckCCompilerFlag)
-MACRO (check_linker_flag FLAG VAR)
-       CMAKE_PUSH_CHECK_STATE (RESET)
-       SET (CMAKE_REQUIRED_FLAGS "${FLAG}")
-       CHECK_C_COMPILER_FLAG ("" "${VAR}")
-       CMAKE_POP_CHECK_STATE ()
-ENDMACRO (check_linker_flag)
-check_linker_flag("-Wl,--as-needed" HAVE_LINKER_AS_NEEDED)
-check_linker_flag("-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver" HAVE_LINKER_VERSION_SCRIPT)
-ELSE (${CMAKE_MAJOR_VERSION} GREATER 2)
-SET (HAVE_LINKER_AS_NEEDED 1)
-SET (HAVE_LINKER_VERSION_SCRIPT 1)
-ENDIF (${CMAKE_MAJOR_VERSION} GREATER 2)
-
-# should create config.h with #cmakedefine instead...
-FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN
-  HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS
-  ENABLE_RPMDB ENABLE_PUBKEY ENABLE_RPMMD ENABLE_RPMDB_BYRPMHEADER ENABLE_SUSEREPO ENABLE_COMPS
-  ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU
-  ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA
-  ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS)
-  IF(${VAR})
-    ADD_DEFINITIONS (-D${VAR}=1)
-    SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
-  ENDIF (${VAR})
-ENDFOREACH (VAR)
-
-SET (PACKAGE "libsolv")
-SET (VERSION "${LIBSOLV_MAJOR}.${LIBSOLV_MINOR}.${LIBSOLV_PATCH}")
-
-ADD_DEFINITIONS (-D_FILE_OFFSET_BITS=64)
-ADD_DEFINITIONS (-DVERSION=\\\"${VERSION}\\\")
-CONFIGURE_FILE (src/solvversion.h.in src/solvversion.h)
-
-SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Package dependency solver library")
-SET (CPACK_PACKAGE_VENDOR "SUSE")
-SET (CPACK_PACKAGE_VERSION_MAJOR ${LIBSOLV_MAJOR})
-SET (CPACK_PACKAGE_VERSION_MINOR ${LIBSOLV_MINOR})
-SET (CPACK_PACKAGE_VERSION_PATCH ${LIBSOLV_PATCH})
-SET (CPACK_GENERATOR "TBZ2")
-SET (CPACK_SOURCE_GENERATOR "TBZ2")
-SET (CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE}-${VERSION}")
-SET (CPACK_SOURCE_TOPLEVEL_TAG "Linux-Source:")
-SET (CPACK_TOPLEVEL_TAG "Linux-Source:")
-
-# The following components are regex's to match anywhere (unless anchored)
-# in absolute path + filename to find files or directories to be excluded
-# from source tarball.
-SET (CPACK_SOURCE_IGNORE_FILES
-# temporary files
-"\\\\.swp$"
-# backup files
-"~$"
-# eclipse files
-"\\\\.cdtproject$"
-"\\\\.cproject$"
-"\\\\.project$"
-"\\\\.settings/"
-# others
-"\\\\.#"
-"/#"
-"/build/"
-"/_build/"
-"/\\\\.git/"
-# used before
-"/\\\\.libs/"
-"/\\\\.deps/"
-"\\\\.o$"
-"\\\\.lo$"
-"\\\\.la$"
-"Makefile$"
-"Makefile\\\\.in$"
-# cmake cache files
-"DartConfiguration.tcl$"
-"CMakeCache.txt"
-"CMakeFiles"
-"cmake_install.cmake$"
-"CMakeLists.txt.auto$"
-"CTestTestfile.cmake"
-"CPackConfig.cmake$"
-"CPackSourceConfig.cmake$"
-"libsolv.spec$"
-)
-
-INCLUDE(CPack)
-
-####################################################################
-# INCLUDES                                                         #
-####################################################################
-
-#SET (CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
-INCLUDE_DIRECTORIES (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/ext ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}/src SYSTEM )
-
-####################################################################
-
-MESSAGE (STATUS "Looking for modules in ${CMAKE_MODULE_PATH}")
-
-set (CMAKE_C_FLAGS     "${CMAKE_C_FLAGS} -Wall")
-set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3")
-set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O3")
-set (CMAKE_C_FLAGS_DEBUG     "${CMAKE_C_FLAGS} -g3 -O0")
-
-SET (SYSTEM_LIBRARIES ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
-IF (ENABLE_LZMA_COMPRESSION)
-SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LZMA_LIBRARY})
-ENDIF (ENABLE_LZMA_COMPRESSION)
-IF (ENABLE_BZIP2_COMPRESSION)
-SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${BZIP2_LIBRARIES})
-ENDIF (ENABLE_BZIP2_COMPRESSION)
-IF (ENABLE_RPMDB)
-SET (SYSTEM_LIBRARIES ${RPMDB_LIBRARY} ${SYSTEM_LIBRARIES})
-ENDIF (ENABLE_RPMDB)
-IF (ENABLE_HAIKU)
-SET (SYSTEM_LIBRARIES ${HAIKU_SYSTEM_LIBRARIES} ${SYSTEM_LIBRARIES})
-ENDIF (ENABLE_HAIKU)
-IF (HAVE_LINKER_AS_NEEDED)
-SET (SYSTEM_LIBRARIES "-Wl,--as-needed" ${SYSTEM_LIBRARIES})
-ENDIF (HAVE_LINKER_AS_NEEDED)
-
-ADD_SUBDIRECTORY (src)
-ADD_SUBDIRECTORY (ext)
-ADD_SUBDIRECTORY (tools)
-IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL)
-    ADD_SUBDIRECTORY (bindings)
-ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL)
-ADD_SUBDIRECTORY (examples)
-ADD_SUBDIRECTORY (doc)
-
-MESSAGE (STATUS "Version: ${VERSION}")
-
-####################################################################
-# RPM SPEC                                                         #
-####################################################################
-
-MACRO (SPECFILE)
-  MESSAGE (STATUS "Writing spec file...")
-  CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/package/libsolv.spec.in ${CMAKE_BINARY_DIR}/package/libsolv.spec @ONLY)
-ENDMACRO (SPECFILE)
-
-MACRO (PCFILE)
-  MESSAGE (STATUS "Writing pkg-config file...")
-  CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/libsolv.pc.in ${CMAKE_BINARY_DIR}/libsolv.pc @ONLY)
-  INSTALL( FILES ${CMAKE_BINARY_DIR}/libsolv.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig )
-ENDMACRO (PCFILE)
-
-SPECFILE ()
-PCFILE ()
-
-SET (AUTOBUILD_COMMAND
-  COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/package/*.tar.bz2
-  COMMAND mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}
-  COMMAND ${CMAKE_MAKE_PROGRAM} package_source
-  COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 ${CMAKE_BINARY_DIR}/package
-  COMMAND ${CMAKE_COMMAND} -E remove ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2
-  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/package/libsolv.changes" "${CMAKE_BINARY_DIR}/package/libsolv.changes"
-)
-
-ADD_CUSTOM_TARGET (srcpackage
-  ${AUTOBUILD_COMMAND}
-)
-
-ADD_CUSTOM_TARGET (srcpackage_local
-  ${AUTOBUILD_COMMAND}
-)
-
-ENABLE_TESTING()
-ADD_SUBDIRECTORY (test)
diff --git a/libsolv-0.6.15/CREDITS b/libsolv-0.6.15/CREDITS
deleted file mode 100644 (file)
index 049bcae..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-Klaus Kaempf
-  - old language bindings
-
-Duncan Mac-Vicar Prett
-  - cmake support
-  - old ruby bindings
-  - many of the xml parsers
-
-Michael Matz
-  - repodata storage
-  - repopage compression
-  - dataiterator code
-
-Michael Schroeder
-  - overall design
-  - pool & solver implementation
-  - new language
-  - debian support
-  - mandriva/mageia support
-  - archlinux support
-
-Ingo Weinhold
-  - haiku support
-
diff --git a/libsolv-0.6.15/INSTALL b/libsolv-0.6.15/INSTALL
deleted file mode 100644 (file)
index 5b1df67..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Compiling and installing the software
-
-Requirements:
-
-- C compiler
-- cmake
-- make
-- expat
-
-Steps to compile/install:
-
-1. mkdir build
-2. cd build
-3. cmake ..
-4. make
-
-5. make install
-
diff --git a/libsolv-0.6.15/LICENSE.BSD b/libsolv-0.6.15/LICENSE.BSD
deleted file mode 100644 (file)
index 79c9f2d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the name of Novell nor the names of its contributors may
-   be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
-INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/libsolv-0.6.15/NEWS b/libsolv-0.6.15/NEWS
deleted file mode 100644 (file)
index a265cc4..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-
-This file contains the major changes between
-libsolv versions:
-
-Version 0.6.12:
-- new features:
-  * tcl bindings
-- new functions:
-  * solv_chksum_cmp
-
-Version 0.6.11:
-- new functions:
-  * pool_ids2whatprovides
-
-Version 0.6.9:
-- new features:
-  * much improved package choosing code
-  * new testcase dependency format
-  * alternatives introspection
-- new functions:
-  * pool_deb_get_autoinstalled
-  * solver_alternative2str
-  * solver_alternatives_count
-  * solver_get_alternative
-  * solver_rule2pkgrule
-  * testcase_dep2str
-
-Version 0.6.5:
-- new features:
-  * support yum style obsolete handling
-
-Version 0.6.1:
-- API change:
-  repodata_stringify() now returns the string
-- new features:
-  * add BREAK_ORPHANS and KEEP_ORPHANS solver flags
-
-Version 0.6.0:
-- ABI change: cleaned up and reordered knownid.h
-- added support for sha224/sha384/sha512
-- API change in the bindings:
-  * dropped solvid arg from most Dataiterator
-    constructors
-  * changed Datamatch results from methods to
-    attributes
-  * automatically delete the pool if the owner
-    object is freed (use the disown method to
-    get the old behavior).
-- new functions:
-  * pool_add_userinstalled_jobs
-  * solver_get_userinstalled
-
diff --git a/libsolv-0.6.15/README b/libsolv-0.6.15/README
deleted file mode 100644 (file)
index 243486a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-This is libsolv, a free package dependency solver using a satisfiability
-algorithm.
-
-This code is based on two major, but independent, blocks:
-
- 1. Using a dictionary approach to store and retrieve package
-    and dependency information.
-
- 2. Using satisfiability, a well known and researched topic, for
-    resolving package dependencies.
-
-The sat-solver code has been written to aim for the newest packages,
-record the decision tree to provide introspection, and also allows to
-provide the user with suggestions on how to deal with unsolvable
-problems. It also takes advantage of the repository storage to
-minimize memory usage.
-
-Supported package formats:
-  - rpm/rpm5
-  - deb
-  - arch linux
-  - haiku
-
-Supported repository formats:
-  - rpmmd (primary, filelists, comps, deltainfo/presto, updateinfo)
-  - susetags, suse product formats
-  - mandriva/mageia (synthesis, info, files)
-  - arch linux
-  - red carpet helix format
-  - haiku
-
-Requires: cmake 2.4.x
-
-mkdir build
-cd build
-cmake ..
-make
-
-To create a package:
-make srcpackage
-see package/
diff --git a/libsolv-0.6.15/VERSION.cmake b/libsolv-0.6.15/VERSION.cmake
deleted file mode 100644 (file)
index 7ba4cb6..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-# ==================================================
-# Versioning
-# ==========
-#
-# MAJOR Major number for this branch.
-#
-# MINOR The most recent interface number this
-#     library implements.
-#
-# COMPATMINOR The latest binary compatible minor number
-#     this library implements.
-#
-# PATCH The implementation number of the current interface.
-#
-#
-# - The package VERSION will be MAJOR.MINOR.PATCH.
-#
-# - Libtool's -version-info will be derived from MAJOR, MINOR, PATCH
-#   and COMPATMINOR (see configure.ac).
-#
-# - Changing MAJOR always breaks binary compatibility.
-#
-# - Changing MINOR doesn't break binary compatibility by default.
-#   Only if COMPATMINOR is changed as well.
-#
-#
-# 1) After branching from TRUNK increment TRUNKs MAJOR and
-#    start with version `MAJOR.0.0' and also set COMPATMINOR to 0.
-#
-# 2) Update the version information only immediately before a public release
-#    of your software. More frequent updates are unnecessary, and only guarantee
-#    that the current interface number gets larger faster.
-#
-# 3) If the library source code has changed at all since the last update,
-#    then increment PATCH.
-#
-# 4) If any interfaces have been added, removed, or changed since the last
-#    update, increment MINOR, and set PATCH to 0.
-#
-# 5) If any interfaces have been added since the last public release, then
-#    leave COMPATMINOR unchanged. (binary compatible change)
-#
-# 6) If any interfaces have been removed since the last public release, then
-#    set COMPATMINOR to MINOR. (binary incompatible change)
-#
-
-SET(LIBSOLV_SOVERSION "0")
-SET(LIBSOLVEXT_SOVERSION "0")
-
-SET(LIBSOLV_MAJOR "0")
-SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "15")
-
diff --git a/libsolv-0.6.15/bindings/CMakeLists.txt b/libsolv-0.6.15/bindings/CMakeLists.txt
deleted file mode 100644 (file)
index 34b0784..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
-
-FIND_PACKAGE (SWIG)
-
-MESSAGE (STATUS "Found SWIG version ${SWIG_VERSION}")
-SET (SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/solv.i")
-
-IF (ENABLE_PYTHON)
-    ADD_SUBDIRECTORY (python)
-ENDIF (ENABLE_PYTHON)
-IF (ENABLE_PERL)
-    ADD_SUBDIRECTORY (perl)
-ENDIF (ENABLE_PERL)
-IF (ENABLE_RUBY)
-    ADD_SUBDIRECTORY (ruby)
-ENDIF (ENABLE_RUBY)
-IF (ENABLE_TCL)
-    ADD_SUBDIRECTORY (tcl)
-ENDIF (ENABLE_TCL)
diff --git a/libsolv-0.6.15/bindings/perl/CMakeLists.txt b/libsolv-0.6.15/bindings/perl/CMakeLists.txt
deleted file mode 100644 (file)
index 49a3902..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-FIND_PACKAGE (Perl)
-
-EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{ccflags}" OUTPUT_VARIABLE PERL_CCFLAGS)
-EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{archlib}.\"/CORE\"" OUTPUT_VARIABLE PERL_CORE_DIR)
-EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{ccldflags}" OUTPUT_VARIABLE PERL_CCLDFLAGS)
-EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{installsitearch}" OUTPUT_VARIABLE PERL_SITEARCHDIR)
-EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{installvendorarch}" OUTPUT_VARIABLE PERL_VENDORARCHDIR)
-
-IF (USE_VENDORDIRS)
-    SET (PERL_INSTALL_DIR ${PERL_VENDORARCHDIR})
-ELSE (USE_VENDORDIRS)
-    SET (PERL_INSTALL_DIR ${PERL_SITEARCHDIR})
-ENDIF (USE_VENDORDIRS)
-
-MESSAGE (STATUS "Perl executable: ${PERL_EXECUTABLE}")
-MESSAGE (STATUS "Perl installation dir: ${PERL_INSTALL_DIR}")
-
-ADD_CUSTOM_COMMAND (
-    OUTPUT solv_perl.c
-    COMMAND ${SWIG_EXECUTABLE} -perl ${SWIG_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_perl.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
-    COMMAND sed -i -e "s/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/" solv_perl.c
-    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
-    VERBATIM
-)
-
-ADD_DEFINITIONS(${PERL_CCFLAGS} -Wno-unused -Wno-nonnull)
-LINK_DIRECTORIES (${PERL_CORE_DIR})
-INCLUDE_DIRECTORIES (${PERL_INCLUDE_PATH} ${PERL_CORE_DIR})
-
-ADD_LIBRARY (bindings_perl MODULE solv_perl.c)
-SET_TARGET_PROPERTIES (bindings_perl PROPERTIES PREFIX "" OUTPUT_NAME "solv")
-SET_TARGET_PROPERTIES (bindings_perl PROPERTIES LINK_FLAGS "${PERL_CCLDFLAGS}")
-TARGET_LINK_LIBRARIES (bindings_perl libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-INSTALL (TARGETS bindings_perl LIBRARY DESTINATION ${PERL_INSTALL_DIR})
-INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.pm DESTINATION ${PERL_INSTALL_DIR})
diff --git a/libsolv-0.6.15/bindings/python/CMakeLists.txt b/libsolv-0.6.15/bindings/python/CMakeLists.txt
deleted file mode 100644 (file)
index 73f2dca..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#SET (PythonLibs_FIND_VERSION 3)
-
-FIND_PACKAGE (PythonLibs)
-FIND_PACKAGE (PythonInterp ${PYTHONLIBS_VERSION_STRING} REQUIRED)
-EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON_INSTALL_DIR)
-
-IF (NOT DEFINED PYTHON_VERSION_MAJOR)
-    SET (PYTHON_VERSION_MAJOR 2)
-ENDIF (NOT DEFINED PYTHON_VERSION_MAJOR)
-IF (${PYTHON_VERSION_MAJOR} GREATER 2)
-    SET (SWIG_PY_FLAGS -DPYTHON3=1)
-ENDIF (${PYTHON_VERSION_MAJOR} GREATER 2)
-
-MESSAGE (STATUS "Python executable: ${PYTHON_EXECUTABLE}")
-MESSAGE (STATUS "Python installation dir: ${PYTHON_INSTALL_DIR}")
-
-ADD_CUSTOM_COMMAND (
-    OUTPUT solv_python.c
-    COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -python ${SWIG_PY_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_python.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
-    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
-)
-
-ADD_DEFINITIONS(-Wno-unused)
-INCLUDE_DIRECTORIES (${PYTHON_INCLUDE_PATH})
-
-ADD_LIBRARY (bindings_python MODULE solv_python.c)
-SET_TARGET_PROPERTIES (bindings_python PROPERTIES PREFIX "" OUTPUT_NAME "_solv")
-TARGET_LINK_LIBRARIES (bindings_python libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-INSTALL (TARGETS bindings_python LIBRARY DESTINATION ${PYTHON_INSTALL_DIR})
-INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.py DESTINATION ${PYTHON_INSTALL_DIR})
-
diff --git a/libsolv-0.6.15/bindings/ruby/CMakeLists.txt b/libsolv-0.6.15/bindings/ruby/CMakeLists.txt
deleted file mode 100644 (file)
index 6c3bd50..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-FIND_PACKAGE (Ruby)
-
-IF (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR)
-    SET (RUBY_INSTALL_DIR ${RUBY_VENDORARCH_DIR})
-ELSE (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR)
-    SET (RUBY_INSTALL_DIR ${RUBY_SITEARCH_DIR})
-ENDIF (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR)
-
-MESSAGE (STATUS "Ruby executable: ${RUBY_EXECUTABLE}")
-MESSAGE (STATUS "Ruby installation dir: ${RUBY_INSTALL_DIR}")
-
-ADD_CUSTOM_COMMAND (
-    OUTPUT solv_ruby.c
-    COMMAND ${SWIG_EXECUTABLE} -ruby ${SWIG_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_ruby.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
-    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
-)
-
-ADD_DEFINITIONS(-Wno-unused)
-INCLUDE_DIRECTORIES (${RUBY_INCLUDE_PATH})
-
-ADD_LIBRARY (bindings_ruby MODULE solv_ruby.c)
-SET_TARGET_PROPERTIES (bindings_ruby PROPERTIES PREFIX "" OUTPUT_NAME "solv")
-TARGET_LINK_LIBRARIES (bindings_ruby libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-INSTALL (TARGETS bindings_ruby LIBRARY DESTINATION ${RUBY_INSTALL_DIR})
diff --git a/libsolv-0.6.15/bindings/solv.i b/libsolv-0.6.15/bindings/solv.i
deleted file mode 100644 (file)
index 823deda..0000000
+++ /dev/null
@@ -1,3867 +0,0 @@
-/*
- * WARNING: for perl iterator/array support you need to run
- *   sed -i -e 's/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/'
- * on the generated c code
- */
-
-%module solv
-
-#ifdef SWIGRUBY
-%markfunc Pool "mark_Pool";
-#endif
-
-/**
- ** binaryblob handling
- **/
-
-%{
-typedef struct {
-  const void *data;
-  size_t len;
-} BinaryBlob;
-%}
-
-%typemap(in,noblock=1,fragment="SWIG_AsCharPtrAndSize") (const unsigned char *str, size_t len) (int res, char *buf = 0, size_t size = 0, int alloc = 0) {
-#if defined(SWIGTCL)
-  {
-    int bal;
-    unsigned char *ba;
-    res = SWIG_TypeError;
-    ba = Tcl_GetByteArrayFromObj($input, &bal);
-    if (ba) {
-      buf = (char *)ba;
-      size = bal;
-      res = SWIG_OK;
-      alloc = SWIG_OLDOBJ;
-    }
-  }
-#else
-  res = SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc);
-  if (buf && size)
-    size--;
-#endif
-  if (!SWIG_IsOK(res)) {
-#if defined(SWIGPYTHON)
-    const void *pybuf = 0;
-    Py_ssize_t pysize = 0;
-    res = PyObject_AsReadBuffer($input, &pybuf, &pysize);
-    if (res < 0) {
-      %argument_fail(res, "BinaryBlob", $symname, $argnum);
-    } else {
-      buf = (void *)pybuf;
-      size = pysize;
-    }
-#else
-    %argument_fail(res, "const char *", $symname, $argnum);
-#endif
-  }
-  $1 = (unsigned char *)buf;
-  $2 = size;
-}
-
-%typemap(freearg,noblock=1,match="in") (const unsigned char *str, int len) {
-  if (alloc$argnum == SWIG_NEWOBJ) %delete_array(buf$argnum);
-}
-
-%typemap(out,noblock=1,fragment="SWIG_FromCharPtrAndSize") BinaryBlob {
-#if defined(SWIGPYTHON) && defined(PYTHON3)
-  $result = $1.data ? Py_BuildValue("y#", $1.data, $1.len) : SWIG_Py_Void();
-#elif defined(SWIGTCL)
-  Tcl_SetObjResult(interp, $1.data ? Tcl_NewByteArrayObj($1.data, $1.len) : NULL);
-#else
-  $result = SWIG_FromCharPtrAndSize($1.data, $1.len);
-#if defined(SWIGPERL)
-  argvi++;
-#endif
-#endif
-}
-
-/**
- ** Queue handling
- **/
-
-%typemap(arginit) Queue {
-  queue_init(&$1);
-}
-%typemap(freearg) Queue {
-  queue_free(&$1);
-}
-
-#if defined(SWIGPYTHON)
-%typemap(in) Queue {
-  /* Check if is a list */
-  if (PyList_Check($input)) {
-    int size = PyList_Size($input);
-    int i = 0;
-    for (i = 0; i < size; i++) {
-      PyObject *o = PyList_GetItem($input,i);
-      int v;
-      int e = SWIG_AsVal_int(o, &v);
-      if (!SWIG_IsOK(e))
-        SWIG_exception_fail(SWIG_ArgError(e), "list must contain only integers");
-      queue_push(&$1, v);
-    }
-  } else {
-    SWIG_exception_fail(SWIG_TypeError, "list must contain only integers");
-  }
-}
-
-%typemap(out) Queue {
-  int i;
-  PyObject *o = PyList_New($1.count);
-  for (i = 0; i < $1.count; i++)
-    PyList_SetItem(o, i, SWIG_From_int($1.elements[i]));
-  queue_free(&$1);
-  $result = o;
-}
-
-%define Queue2Array(type, step, con) %{
-  int i;
-  int cnt = $1.count / step;
-  Id *idp = $1.elements;
-  PyObject *o = PyList_New(cnt);
-  for (i = 0; i < cnt; i++, idp += step)
-    {
-      Id id = *idp;
-#define result resultx
-      type result = con;
-      $typemap(out, type)
-      PyList_SetItem(o, i, $result);
-#undef result
-    }
-  queue_free(&$1);
-  $result = o;
-%}
-
-%enddef
-
-#endif  /* SWIGPYTHON */
-
-#if defined(SWIGPERL)
-%typemap(in) Queue {
-  AV *av;
-  int i, size;
-  if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV)
-    SWIG_croak("Argument $argnum is not an array reference.");
-  av = (AV*)SvRV($input);
-  size = av_len(av);
-  for (i = 0; i <= size; i++) {
-    SV **sv = av_fetch(av, i, 0);
-    int v;
-    int e = SWIG_AsVal_int(*sv, &v);
-    if (!SWIG_IsOK(e)) {
-      SWIG_croak("list must contain only integers");
-    }
-    queue_push(&$1, v);
-  }
-}
-/* AV *o = newAV();
- * av_push(o, SvREFCNT_inc(SWIG_From_int($1.elements[i])));
- * $result = newRV_noinc((SV*)o); argvi++;
- */
-%typemap(out) Queue {
-  int i;
-  if (argvi + $1.count + 1 >= items) {
-    EXTEND(sp, (argvi + $1.count + 1) - items + 1);
-  }
-  for (i = 0; i < $1.count; i++)
-    ST(argvi++) = SvREFCNT_inc(SWIG_From_int($1.elements[i]));
-  queue_free(&$1);
-  $result = 0;
-}
-
-%define Queue2Array(type, step, con) %{
-  int i;
-  int cnt = $1.count / step;
-  Id *idp = $1.elements;
-  if (argvi + cnt + 1 >= items) {
-    EXTEND(sp, (argvi + cnt + 1) - items + 1);
-  }
-  for (i = 0; i < cnt; i++, idp += step)
-    {
-      Id id = *idp;
-#define result resultx
-      type result = con;
-      $typemap(out, type)
-      SvREFCNT_inc(ST(argvi - 1));
-#undef result
-    }
-  queue_free(&$1);
-  $result = 0;
-%}
-%enddef
-
-#endif  /* SWIGPERL */
-
-
-#if defined(SWIGRUBY)
-%typemap(in) Queue {
-  int size, i;
-  VALUE *o, ary;
-  ary = rb_Array($input);
-  size = RARRAY_LEN(ary);
-  i = 0;
-  o = RARRAY_PTR(ary);
-  for (i = 0; i < size; i++, o++) {
-    int v;
-    int e = SWIG_AsVal_int(*o, &v);
-    if (!SWIG_IsOK(e))
-      SWIG_exception_fail(SWIG_TypeError, "list must contain only integers");
-    queue_push(&$1, v);
-  }
-}
-%typemap(out) Queue {
-  int i;
-  VALUE o = rb_ary_new2($1.count);
-  for (i = 0; i < $1.count; i++)
-    rb_ary_store(o, i, SWIG_From_int($1.elements[i]));
-  queue_free(&$1);
-  $result = o;
-}
-%typemap(arginit) Queue {
-  queue_init(&$1);
-}
-%typemap(freearg) Queue {
-  queue_free(&$1);
-}
-%define Queue2Array(type, step, con) %{
-  int i;
-  int cnt = $1.count / step;
-  Id *idp = $1.elements;
-  VALUE o = rb_ary_new2(cnt);
-  for (i = 0; i < cnt; i++, idp += step)
-    {
-      Id id = *idp;
-#define result resultx
-      type result = con;
-      $typemap(out, type)
-      rb_ary_store(o, i, $result);
-#undef result
-    }
-  queue_free(&$1);
-  $result = o;
-%}
-%enddef
-
-#endif  /* SWIGRUBY */
-
-#if defined(SWIGTCL)
-%typemap(in) Queue {
-  /* Check if is a list */
-  int size = 0;
-  int i = 0;
-
-  if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
-    SWIG_exception_fail(SWIG_TypeError, "argument is not a list");
-  for (i = 0; i < size; i++) {
-    Tcl_Obj *o = NULL;
-    int e, v;
-
-    if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
-      SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
-    e = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(o, &v);
-    if (!SWIG_IsOK(e))
-      SWIG_exception_fail(SWIG_ArgError(e), "list must contain only integers");
-    queue_push(&$1, v);
-  }
-}
-
-%typemap(out) Queue {
-  Tcl_Obj *objvx[$1.count];
-  int i;
-
-  for (i = 0; i < $1.count; i++) {
-    objvx[i] = SWIG_From_int($1.elements[i]);
-  }
-  Tcl_SetObjResult(interp, Tcl_NewListObj($1.count, objvx));
-  queue_free(&$1);
-}
-
-%define Queue2Array(type, step, con) %{
-  { /* scope is needed to make the goto of SWIG_exception_fail work */
-    int i;
-    int cnt = $1.count / step;
-    Id *idp = $1.elements;
-    Tcl_Obj *objvx[cnt];
-
-    for (i = 0; i < cnt; i++, idp += step) {
-      Id id = *idp;
-#define result resultx
-#define Tcl_SetObjResult(i, x) resultobj = x
-      type result = con;
-      Tcl_Obj *resultobj;
-      $typemap(out, type)
-      objvx[i] = resultobj;
-#undef Tcl_SetObjResult
-#undef result
-    }
-    queue_free(&$1);
-    Tcl_SetObjResult(interp, Tcl_NewListObj(cnt, objvx));
-  }
-%}
-
-%enddef
-
-%typemap(in) Queue solvejobs {
-  /* Check if is a list */
-  int size = 0;
-  int i = 0;
-
-  if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
-    SWIG_exception_fail(SWIG_TypeError, "argument is not a list");
-  for (i = 0; i < size; i++) {
-    Tcl_Obj *o = NULL;
-    void *jp;
-    Job *j;
-    int e;
-
-    if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
-      SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
-    e = SWIG_ConvertPtr(o, &jp ,SWIGTYPE_p_Job, 0 |  0 );
-    if (!SWIG_IsOK(e))
-      SWIG_exception_fail(SWIG_ArgError(e), "list member is not a Job");
-    j = (Job *)jp;
-    queue_push2(&$1, j->how, j->what);
-  }
-}
-
-#endif  /* SWIGTCL */
-
-
-#if defined(SWIGPERL)
-
-/* work around a swig bug */
-%{
-#undef SWIG_CALLXS
-#ifdef PERL_OBJECT
-#  define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(cv,pPerl)
-#else
-#  ifndef MULTIPLICITY
-#    define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(cv)
-#  else
-#    define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(PERL_GET_THX, cv)
-#  endif
-#endif
-%}
-
-
-%define perliter(class)
-  %perlcode {
-    sub class##::FETCH {
-      my $i = ${##class##::ITERATORS}{$_[0]};
-      if ($i) {
-        $_[1] == $i->[0] - 1 ? $i->[1] : undef;
-      } else {
-        $_[0]->__getitem__($_[1]);
-      }
-    }
-    sub class##::FETCHSIZE {
-      my $i = ${##class##::ITERATORS}{$_[0]};
-      if ($i) {
-        ($i->[1] = $_[0]->__next__()) ? ++$i->[0]  : 0;
-      } else {
-        $_[0]->__len__();
-      }
-    }
-  }
-%enddef
-
-%{
-
-#define SWIG_PERL_ITERATOR      0x80
-
-SWIGRUNTIMEINLINE SV *
-SWIG_Perl_NewArrayObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
-  SV *result = sv_newmortal();
-  if (ptr && (flags & (SWIG_SHADOW | SWIG_POINTER_OWN))) {
-    SV *self;
-    SV *obj=newSV(0);
-    AV *array=newAV();
-    HV *stash;
-    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
-    stash=SvSTASH(SvRV(obj));
-    if (flags & SWIG_POINTER_OWN) {
-      HV *hv;
-      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
-      if (!isGV(gv))
-        gv_init(gv, stash, "OWNER", 5, FALSE);
-      hv=GvHVn(gv);
-      hv_store_ent(hv, obj, newSViv(1), 0);
-    }
-    if (flags & SWIG_PERL_ITERATOR) {
-      HV *hv;
-      GV *gv=*(GV**)hv_fetch(stash, "ITERATORS", 9, TRUE);
-      AV *av=newAV();
-      if (!isGV(gv))
-        gv_init(gv, stash, "ITERATORS", 9, FALSE);
-      hv=GvHVn(gv);
-      hv_store_ent(hv, obj, newRV_inc((SV *)av), 0);
-    }
-    sv_magic((SV *)array, (SV *)obj, 'P', Nullch, 0);
-    SvREFCNT_dec(obj);
-    self=newRV_noinc((SV *)array);
-    sv_setsv(result, self);
-    SvREFCNT_dec((SV *)self);
-    sv_bless(result, stash);
-  } else {
-    sv_setref_pv(result, (char *) SWIG_Perl_TypeProxyName(t), ptr);
-  }
-  return result;
-}
-
-%}
-
-%typemap(out) Perlarray {
-  ST(argvi) = SWIG_Perl_NewArrayObj(SWIG_PERL_OBJECT_CALL SWIG_as_voidptr(result), $1_descriptor, $owner | $shadow); argvi++;
-}
-%typemap(out) Perliterator {
-  ST(argvi) = SWIG_Perl_NewArrayObj(SWIG_PERL_OBJECT_CALL SWIG_as_voidptr(result), $1_descriptor, $owner | $shadow | SWIG_PERL_ITERATOR); argvi++;
-}
-
-%typemap(out) Pool_solvable_iterator * = Perlarray;
-%typemap(out) Pool_solvable_iterator * solvables_iter = Perliterator;
-%typemap(out) Pool_repo_iterator * = Perlarray;
-%typemap(out) Pool_repo_iterator * repos_iter = Perliterator;
-%typemap(out) Repo_solvable_iterator * = Perlarray;
-%typemap(out) Repo_solvable_iterator * solvables_iter = Perliterator;
-%typemap(out) Dataiterator * = Perliterator;
-
-#endif  /* SWIGPERL */
-
-
-/**
- ** appdata handling
- **/
-
-#if defined(SWIGPYTHON)
-typedef PyObject *AppObjectPtr;
-%typemap(in) AppObjectPtr {
-  if ($input)
-    Py_INCREF($input);
-  $1 = $input;
-}
-%typemap(out) AppObjectPtr {
-  $result = $1 ? $1 : Py_None;
-  Py_INCREF($result);
-}
-#elif defined(SWIGPERL)
-typedef SV *AppObjectPtr;
-%typemap(in) AppObjectPtr {
-  if ($input) {
-    $1 = newSV(0);
-    sv_setsv((SV *)$1, $input);
-  } else
-    $1 = (void *)0;
-}
-%typemap(out) AppObjectPtr {
-  $result = sv_2mortal($1 ? SvREFCNT_inc($1) : newSV(0));
-  argvi++;
-}
-#elif defined(SWIGRUBY)
-typedef VALUE AppObjectPtr;
-%typemap(in) AppObjectPtr {
-  $1 = (void *)$input;
-}
-%typemap(out) AppObjectPtr {
-  $result = (VALUE)$1;
-}
-#elif defined(SWIGTCL)
-typedef Tcl_Obj *AppObjectPtr;
-%typemap(in) AppObjectPtr {
-  if ($input)
-    Tcl_IncrRefCount($input);
-  $1 = (void *)$input;
-}
-%typemap(out) AppObjectPtr {
-  Tcl_SetObjResult(interp, $1 ? $1 : Tcl_NewObj());
-}
-#else
-#warning AppObjectPtr not defined for this language!
-#endif
-
-/**
- ** FILE handling
- **/
-
-#ifdef SWIGPYTHON
-%include "file.i"
-#else
-%fragment("SWIG_AsValFilePtr","header") {}
-#endif
-
-
-%fragment("SWIG_AsValSolvFpPtr","header", fragment="SWIG_AsValFilePtr") {
-
-SWIGINTERN int
-#ifdef SWIGRUBY
-SWIG_AsValSolvFpPtr(VALUE obj, FILE **val) {
-#elif defined(SWIGTCL)
-SWIG_AsValSolvFpPtr SWIG_TCL_DECL_ARGS_2(void *obj, FILE **val) {
-#else
-SWIG_AsValSolvFpPtr(void *obj, FILE **val) {
-#endif
-  static swig_type_info* desc = 0;
-  void *vptr = 0;
-  int ecode;
-
-  if (!desc) desc = SWIG_TypeQuery("SolvFp *");
-  if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) {
-    if (val)
-      *val = vptr ? ((SolvFp *)vptr)->fp : 0;
-    return SWIG_OK;
-  }
-#ifdef SWIGPYTHON
-  ecode = SWIG_AsValFilePtr(obj, val);
-  if (ecode == SWIG_OK)
-    return ecode;
-#endif
-  return SWIG_TypeError;
-}
-
-#if defined(SWIGTCL)
-#define SWIG_AsValSolvFpPtr(x, y) SWIG_AsValSolvFpPtr SWIG_TCL_CALL_ARGS_2(x, y)
-#endif
-
-}
-
-
-/**
- ** DepId handling
- **/
-
-%fragment("SWIG_AsValDepId","header") {
-
-SWIGINTERN int
-#ifdef SWIGRUBY
-SWIG_AsValDepId(VALUE obj, int *val) {
-#elif defined(SWIGTCL)
-SWIG_AsValDepId SWIG_TCL_DECL_ARGS_2(void *obj, int *val) {
-#else
-SWIG_AsValDepId(void *obj, int *val) {
-#endif
-  static swig_type_info* desc = 0;
-  void *vptr = 0;
-  int ecode;
-  if (!desc) desc = SWIG_TypeQuery("Dep *");
-#ifdef SWIGTCL
-  ecode = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(obj, val);
-#else
-  ecode = SWIG_AsVal_int(obj, val);
-#endif
-  if (SWIG_IsOK(ecode))
-    return ecode;
-  if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) {
-    if (val)
-      *val = vptr ? ((Dep *)vptr)->id : 0;
-    return SWIG_OK;
-  }
-  return SWIG_TypeError;
-}
-
-#ifdef SWIGTCL
-#define SWIG_AsValDepId(x, y) SWIG_AsValDepId SWIG_TCL_CALL_ARGS_2(x, y)
-#endif
-}
-
-/**
- ** Pool disown helper
- **/
-
-%typemap(out) disown_helper {
-#if defined(SWIGRUBY)
-  SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
-#elif defined(SWIGPYTHON)
-  SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
-#elif defined(SWIGPERL)
-  SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
-#elif defined(SWIGTCL)
-  SWIG_ConvertPtr(objv[1], &argp1, SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0);
-#else
-#warning disown_helper not implemented for this language, this is likely going to leak memory
-#endif
-
-#ifdef SWIGTCL
-  Tcl_SetObjResult(interp, SWIG_From_int((int)(0)));
-#else
-  $result = SWIG_From_int((int)(0));
-#endif
-}
-
-
-/**
- ** misc stuff
- **/
-
-%include "typemaps.i"
-
-%typemap(in,numinputs=0,noblock=1) XRule **OUTPUT ($*1_ltype temp) {
-  $1 = &temp;
-}
-%typemap(argout,noblock=1) XRule **OUTPUT {
-  %append_output(SWIG_NewPointerObj((void*)(*$1), SWIGTYPE_p_XRule, SWIG_POINTER_OWN | %newpointer_flags));
-}
-
-%typemaps_asval(%checkcode(POINTER), SWIG_AsValSolvFpPtr, "SWIG_AsValSolvFpPtr", FILE*);
-%typemaps_asval(%checkcode(INT32), SWIG_AsValDepId, "SWIG_AsValDepId", DepId);
-
-
-/**
- ** the C declarations
- **/
-
-%{
-#include <stdbool.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* argh, swig undefs bool for perl */
-#ifndef bool
-typedef int bool;
-#endif
-
-#include "pool.h"
-#include "poolarch.h"
-#include "evr.h"
-#include "solver.h"
-#include "policy.h"
-#include "solverdebug.h"
-#include "repo_solv.h"
-#include "chksum.h"
-#include "selection.h"
-
-#include "repo_write.h"
-#ifdef ENABLE_RPMDB
-#include "repo_rpmdb.h"
-#endif
-#ifdef ENABLE_PUBKEY
-#include "repo_pubkey.h"
-#endif
-#ifdef ENABLE_DEBIAN
-#include "repo_deb.h"
-#endif
-#ifdef ENABLE_RPMMD
-#include "repo_rpmmd.h"
-#include "repo_updateinfoxml.h"
-#include "repo_deltainfoxml.h"
-#include "repo_repomdxml.h"
-#endif
-#ifdef ENABLE_SUSEREPO
-#include "repo_products.h"
-#include "repo_susetags.h"
-#include "repo_content.h"
-#endif
-#ifdef ENABLE_MDKREPO
-#include "repo_mdk.h"
-#endif
-#ifdef ENABLE_ARCHREPO
-#include "repo_arch.h"
-#endif
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-#include "solv_xfopen.h"
-#include "testcase.h"
-
-/* for old ruby versions */
-#ifndef RARRAY_PTR
-#define RARRAY_PTR(ary) (RARRAY(ary)->ptr)
-#endif
-#ifndef RARRAY_LEN
-#define RARRAY_LEN(ary) (RARRAY(ary)->len)
-#endif
-
-#define SOLVER_SOLUTION_ERASE                   -100
-#define SOLVER_SOLUTION_REPLACE                 -101
-#define SOLVER_SOLUTION_REPLACE_DOWNGRADE       -102
-#define SOLVER_SOLUTION_REPLACE_ARCHCHANGE      -103
-#define SOLVER_SOLUTION_REPLACE_VENDORCHANGE    -104
-#define SOLVER_SOLUTION_REPLACE_NAMECHANGE      -105
-
-typedef void *AppObjectPtr;
-typedef Id DepId;
-
-typedef struct {
-  Pool *pool;
-  Id id;
-} Dep;
-
-typedef struct {
-  Pool *pool;
-  Id id;
-} XSolvable;
-
-typedef struct {
-  Solver *solv;
-  Id id;
-} XRule;
-
-typedef struct {
-  Repo *repo;
-  Id id;
-} XRepodata;
-
-typedef struct {
-  Pool *pool;
-  Id id;
-} Pool_solvable_iterator;
-
-typedef struct {
-  Pool *pool;
-  Id id;
-} Pool_repo_iterator;
-
-typedef struct {
-  Repo *repo;
-  Id id;
-} Repo_solvable_iterator;
-
-typedef struct {
-  Pool *pool;
-  int how;
-  Id what;
-} Job;
-
-typedef struct {
-  Solver *solv;
-  Id id;
-} Problem;
-
-typedef struct {
-  Solver *solv;
-  Id problemid;
-  Id id;
-} Solution;
-
-typedef struct {
-  Solver *solv;
-  Id problemid;
-  Id solutionid;
-  Id id;
-
-  Id type;
-  Id p;
-  Id rp;
-} Solutionelement;
-
-typedef struct {
-  Solver *solv;
-  Id rid;
-  Id type;
-  Id source;
-  Id target;
-  Id dep_id;
-} Ruleinfo;
-
-typedef struct {
-  Solver *solv;
-  Id type;
-  Id rid;
-  Id from_id;
-  Id dep_id;
-  Id chosen_id;
-  Queue choices;
-  int level;
-} Alternative;
-
-typedef struct {
-  Transaction *transaction;
-  int mode;
-  Id type;
-  int count;
-  Id fromid;
-  Id toid;
-} TransactionClass;
-
-typedef struct {
-  Pool *pool;
-  Queue q;
-  int flags;
-} Selection;
-
-typedef struct {
-  FILE *fp;
-} SolvFp;
-
-typedef Dataiterator Datamatch;
-
-typedef int disown_helper;
-
-struct myappdata {
-  void *appdata;
-  int disowned;
-};
-
-
-%}
-
-/**
- ** appdata helpers
- **/
-
-#ifdef SWIGRUBY
-
-%{
-SWIGINTERN void appdata_disown_helper(void *appdata) {
-}
-SWIGINTERN void appdata_clr_helper(void **appdatap) {
-  *appdatap = 0;
-}
-SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
-  *appdatap = appdata;
-}
-SWIGINTERN void *appdata_get_helper(void *appdata) {
-  return appdata;
-}
-%}
-
-#elif defined(SWIGTCL)
-
-%{
-SWIGINTERN void appdata_disown_helper(void *appdata) {
-}
-SWIGINTERN void appdata_clr_helper(void **appdatap) {
-  if (*appdatap)
-    Tcl_DecrRefCount((Tcl_Obj *)(*appdatap));
-  *appdatap = 0;
-}
-SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
-  appdata_clr_helper(appdatap);
-  *appdatap = appdata;
-}
-SWIGINTERN void *appdata_get_helper(void *appdata) {
-  return appdata;
-}
-%}
-
-#elif defined(SWIGPYTHON)
-
-%{
-SWIGINTERN void appdata_disown_helper(void *appdata) {
-  struct myappdata *myappdata = appdata;
-  if (!myappdata || !myappdata->appdata || myappdata->disowned)
-    return;
-  myappdata->disowned = 1;
-  Py_DECREF((PyObject *)myappdata->appdata);
-}
-SWIGINTERN void appdata_clr_helper(void **appdatap) {
-  struct myappdata *myappdata = *(struct myappdata **)appdatap;
-  if (myappdata && myappdata->appdata && !myappdata->disowned) {
-    Py_DECREF((PyObject *)myappdata->appdata);
-  }
-  *appdatap = solv_free(myappdata);
-}
-SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
-  appdata_clr_helper(appdatap);
-  if (appdata) {
-    struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1);
-    myappdata->appdata = appdata;
-  }
-}
-SWIGINTERN void *appdata_get_helper(void *appdata) {
-  return appdata ? ((struct myappdata *)appdata)->appdata : 0;
-}
-
-%}
-
-#elif defined(SWIGPERL)
-
-%{
-SWIGINTERN void appdata_disown_helper(void *appdata) {
-  struct myappdata *myappdata = appdata;
-  SV *rsv;
-  if (!myappdata || !myappdata->appdata || myappdata->disowned)
-    return;
-  rsv = myappdata->appdata;
-  if (!SvROK(rsv))
-    return;
-  myappdata->appdata = SvRV(rsv);
-  myappdata->disowned = 1;
-  SvREFCNT_dec(rsv);
-}
-SWIGINTERN void appdata_clr_helper(void **appdatap) {
-  struct myappdata *myappdata = *(struct myappdata **)appdatap;
-  if (myappdata && myappdata->appdata && !myappdata->disowned) {
-    SvREFCNT_dec((SV *)myappdata->appdata);
-  }
-  *appdatap = solv_free(myappdata);
-}
-SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
-  appdata_clr_helper(appdatap);
-  if (appdata) {
-    struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1);
-    myappdata->appdata = appdata;
-  }
-}
-SWIGINTERN void *appdata_get_helper(void *appdata) {
-  struct myappdata *myappdata = appdata;
-  if (!myappdata || !myappdata->appdata)
-    return 0;
-  return myappdata->disowned ? newRV_noinc((SV *)myappdata->appdata) : myappdata->appdata;
-}
-
-%}
-
-#else
-#warning appdata helpers not implemented for this language
-#endif
-
-
-/**
- ** the SWIG declarations defining the API
- **/
-
-#ifdef SWIGRUBY
-%mixin Dataiterator "Enumerable";
-%mixin Pool_solvable_iterator "Enumerable";
-%mixin Pool_repo_iterator "Enumerable";
-%mixin Repo_solvable_iterator "Enumerable";
-#endif
-
-typedef int Id;
-
-%include "knownid.h"
-
-/* from repodata.h */
-%constant Id SOLVID_META;
-%constant Id SOLVID_POS;
-
-%constant int REL_EQ;
-%constant int REL_GT;
-%constant int REL_LT;
-%constant int REL_ARCH;
-%constant int REL_AND;
-%constant int REL_OR;
-%constant int REL_WITH;
-%constant int REL_COND;
-%constant int REL_ELSE;
-
-typedef struct {
-  Pool* const pool;
-} Selection;
-
-typedef struct {
-  Pool* const pool;
-  Id const id;
-} Dep;
-
-/* put before pool/repo so we can access the constructor */
-%nodefaultdtor Dataiterator;
-typedef struct {} Dataiterator;
-
-typedef struct {
-  Pool* const pool;
-  Id const id;
-} XSolvable;
-
-typedef struct {
-  Solver* const solv;
-  Id const type;
-  Id const dep_id;
-} Ruleinfo;
-
-typedef struct {
-  Solver* const solv;
-  Id const id;
-} XRule;
-
-typedef struct {
-  Repo* const repo;
-  Id const id;
-} XRepodata;
-
-typedef struct {} Pool_solvable_iterator;
-typedef struct {} Pool_repo_iterator;
-typedef struct {} Repo_solvable_iterator;
-
-%nodefaultctor Datamatch;
-%nodefaultdtor Datamatch;
-typedef struct {
-  Pool * const pool;
-  Repo * const repo;
-  Id const solvid;
-} Datamatch;
-
-%nodefaultctor Datapos;
-typedef struct {
-  Repo * const repo;
-} Datapos;
-
-typedef struct {
-  Pool * const pool;
-  int how;
-  Id what;
-} Job;
-
-%nodefaultctor Pool;
-%nodefaultdtor Pool;
-typedef struct {
-} Pool;
-
-%nodefaultctor Repo;
-%nodefaultdtor Repo;
-typedef struct {
-  Pool * const pool;
-  const char * const name;
-  int priority;
-  int subpriority;
-  int const nsolvables;
-} Repo;
-
-%nodefaultctor Solver;
-%nodefaultdtor Solver;
-typedef struct {
-  Pool * const pool;
-} Solver;
-
-typedef struct {
-} Chksum;
-
-#ifdef ENABLE_PUBKEY
-typedef struct {
-  Id const htype;
-  unsigned int const created;
-  unsigned int const expires;
-  const char * const keyid;
-} Solvsig;
-#endif
-
-%rename(xfopen) solvfp_xfopen;
-%rename(xfopen_fd) solvfp_xfopen_fd;
-
-%nodefaultctor SolvFp;
-typedef struct {
-} SolvFp;
-
-%newobject solvfp_xfopen;
-%newobject solvfp_xfopen_fd;
-
-SolvFp *solvfp_xfopen(const char *fn, const char *mode = 0);
-SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode = 0);
-
-%{
-  SWIGINTERN SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode) {
-    SolvFp *sfp;
-    FILE *fp;
-    fd = dup(fd);
-    if (fd == -1)
-      return 0;
-    fcntl(fd, F_SETFD, FD_CLOEXEC);
-    fp = solv_xfopen_fd(fn, fd, mode);
-    if (!fp) {
-      close(fd);
-      return 0;
-    }
-    sfp = solv_calloc(1, sizeof(SolvFp));
-    sfp->fp = fp;
-    return sfp;
-  }
-  SWIGINTERN SolvFp *solvfp_xfopen(const char *fn, const char *mode) {
-    SolvFp *sfp;
-    FILE *fp;
-    fp = solv_xfopen(fn, mode);
-    if (!fp)
-      return 0;
-    if (fileno(fp) != -1)
-      fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
-    sfp = solv_calloc(1, sizeof(SolvFp));
-    sfp->fp = fp;
-    return sfp;
-  }
-%}
-
-typedef struct {
-  Solver * const solv;
-  Id const id;
-} Problem;
-
-typedef struct {
-  Solver * const solv;
-  Id const problemid;
-  Id const id;
-} Solution;
-
-typedef struct {
-  Solver *const solv;
-  Id const problemid;
-  Id const solutionid;
-  Id const id;
-  Id const type;
-} Solutionelement;
-
-%nodefaultctor Alternative;
-typedef struct {
-  Solver *const solv;
-  Id const type;
-  Id const rid;
-  Id const from_id;
-  Id const dep_id;
-  Id const chosen_id;
-  int level;
-} Alternative;
-
-%nodefaultctor Transaction;
-%nodefaultdtor Transaction;
-typedef struct {
-  Pool * const pool;
-} Transaction;
-
-typedef struct {
-  Transaction * const transaction;
-  Id const type;
-  Id const fromid;
-  Id const toid;
-  int const count;
-} TransactionClass;
-
-%extend SolvFp {
-  ~SolvFp() {
-    if ($self->fp)
-      fclose($self->fp);
-    free($self);
-  }
-  int fileno() {
-    return $self->fp ? fileno($self->fp) : -1;
-  }
-  int dup() {
-    return $self->fp ? dup(fileno($self->fp)) : -1;
-  }
-  bool write(const unsigned char *str, size_t len) {
-    return fwrite(str, len, 1, $self->fp) == 1;
-  }
-  bool flush() {
-    if (!$self->fp)
-      return 1;
-    return fflush($self->fp) == 0;
-  }
-  bool close() {
-    bool ret;
-    if (!$self->fp)
-      return 1;
-    ret = fclose($self->fp) == 0;
-    $self->fp = 0;
-    return ret;
-  }
-  void cloexec(bool state) {
-    if (!$self->fp || fileno($self->fp) == -1)
-      return;
-    fcntl(fileno($self->fp), F_SETFD, state ? FD_CLOEXEC : 0);
-  }
-}
-
-%extend Job {
-  static const Id SOLVER_SOLVABLE = SOLVER_SOLVABLE;
-  static const Id SOLVER_SOLVABLE_NAME = SOLVER_SOLVABLE_NAME;
-  static const Id SOLVER_SOLVABLE_PROVIDES = SOLVER_SOLVABLE_PROVIDES;
-  static const Id SOLVER_SOLVABLE_ONE_OF = SOLVER_SOLVABLE_ONE_OF;
-  static const Id SOLVER_SOLVABLE_REPO = SOLVER_SOLVABLE_REPO;
-  static const Id SOLVER_SOLVABLE_ALL = SOLVER_SOLVABLE_ALL;
-  static const Id SOLVER_SELECTMASK = SOLVER_SELECTMASK;
-  static const Id SOLVER_NOOP = SOLVER_NOOP;
-  static const Id SOLVER_INSTALL = SOLVER_INSTALL;
-  static const Id SOLVER_ERASE = SOLVER_ERASE;
-  static const Id SOLVER_UPDATE = SOLVER_UPDATE;
-  static const Id SOLVER_WEAKENDEPS = SOLVER_WEAKENDEPS;
-  static const Id SOLVER_MULTIVERSION = SOLVER_MULTIVERSION;
-  static const Id SOLVER_LOCK = SOLVER_LOCK;
-  static const Id SOLVER_DISTUPGRADE = SOLVER_DISTUPGRADE;
-  static const Id SOLVER_VERIFY = SOLVER_VERIFY;
-  static const Id SOLVER_DROP_ORPHANED = SOLVER_DROP_ORPHANED;
-  static const Id SOLVER_USERINSTALLED = SOLVER_USERINSTALLED;
-  static const Id SOLVER_ALLOWUNINSTALL = SOLVER_ALLOWUNINSTALL;
-  static const Id SOLVER_JOBMASK = SOLVER_JOBMASK;
-  static const Id SOLVER_WEAK = SOLVER_WEAK;
-  static const Id SOLVER_ESSENTIAL = SOLVER_ESSENTIAL;
-  static const Id SOLVER_CLEANDEPS = SOLVER_CLEANDEPS;
-  static const Id SOLVER_FORCEBEST = SOLVER_FORCEBEST;
-  static const Id SOLVER_TARGETED = SOLVER_TARGETED;
-  static const Id SOLVER_NOTBYUSER = SOLVER_NOTBYUSER;
-  static const Id SOLVER_SETEV = SOLVER_SETEV;
-  static const Id SOLVER_SETEVR = SOLVER_SETEVR;
-  static const Id SOLVER_SETARCH = SOLVER_SETARCH;
-  static const Id SOLVER_SETVENDOR = SOLVER_SETVENDOR;
-  static const Id SOLVER_SETREPO = SOLVER_SETREPO;
-  static const Id SOLVER_SETNAME = SOLVER_SETNAME;
-  static const Id SOLVER_NOAUTOSET = SOLVER_NOAUTOSET;
-  static const Id SOLVER_SETMASK = SOLVER_SETMASK;
-
-  Job(Pool *pool, int how, Id what) {
-    Job *job = solv_calloc(1, sizeof(*job));
-    job->pool = pool;
-    job->how = how;
-    job->what = what;
-    return job;
-  }
-
-  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject solvables;
-  Queue solvables() {
-    Queue q;
-    queue_init(&q);
-    pool_job2solvables($self->pool, &q, $self->how, $self->what);
-    return q;
-  }
-#ifdef SWIGRUBY
-  %rename("isemptyupdate?") isemptyupdate;
-#endif
-  bool isemptyupdate() {
-    return pool_isemptyupdatejob($self->pool, $self->how, $self->what);
-  }
-
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(Job *j) {
-    return $self->pool == j->pool && $self->how == j->how && $self->what == j->what;
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(Job *j) {
-    return !Job___eq__($self, j);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  const char *__str__() {
-    return pool_job2str($self->pool, $self->how, $self->what, 0);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  const char *__repr__() {
-    const char *str = pool_job2str($self->pool, $self->how, $self->what, ~0);
-    return pool_tmpjoin($self->pool, "<Job ", str, ">");
-  }
-}
-
-%extend Selection {
-  static const Id SELECTION_NAME = SELECTION_NAME;
-  static const Id SELECTION_PROVIDES = SELECTION_PROVIDES;
-  static const Id SELECTION_FILELIST = SELECTION_FILELIST;
-  static const Id SELECTION_CANON = SELECTION_CANON;
-  static const Id SELECTION_DOTARCH = SELECTION_DOTARCH;
-  static const Id SELECTION_REL = SELECTION_REL;
-  static const Id SELECTION_INSTALLED_ONLY = SELECTION_INSTALLED_ONLY;
-  static const Id SELECTION_GLOB = SELECTION_GLOB;
-  static const Id SELECTION_FLAT = SELECTION_FLAT;
-  static const Id SELECTION_NOCASE = SELECTION_NOCASE;
-  static const Id SELECTION_SOURCE_ONLY = SELECTION_SOURCE_ONLY;
-  static const Id SELECTION_WITH_SOURCE = SELECTION_WITH_SOURCE;
-
-  Selection(Pool *pool) {
-    Selection *s;
-    s = solv_calloc(1, sizeof(*s));
-    s->pool = pool;
-    return s;
-  }
-
-  ~Selection() {
-    queue_free(&$self->q);
-    solv_free($self);
-  }
-  int flags() {
-    return $self->flags;
-  }
-#ifdef SWIGRUBY
-  %rename("isempty?") isempty;
-#endif
-  bool isempty() {
-    return $self->q.count == 0;
-  }
-  void filter(Selection *lsel) {
-    if ($self->pool != lsel->pool)
-      queue_empty(&$self->q);
-    else
-      selection_filter($self->pool, &$self->q, &lsel->q);
-  }
-  void add(Selection *lsel) {
-    if ($self->pool == lsel->pool)
-      {
-        selection_add($self->pool, &$self->q, &lsel->q);
-        $self->flags |= lsel->flags;
-      }
-  }
-  void add_raw(Id how, Id what) {
-    queue_push2(&$self->q, how, what);
-  }
-  %typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1]));
-  %newobject jobs;
-  Queue jobs(int flags) {
-    Queue q;
-    int i;
-    queue_init_clone(&q, &$self->q);
-    for (i = 0; i < q.count; i += 2)
-      q.elements[i] |= flags;
-    return q;
-  }
-
-  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject solvables;
-  Queue solvables() {
-    Queue q;
-    queue_init(&q);
-    selection_solvables($self->pool, &$self->q, &q);
-    return q;
-  }
-
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  const char *__str__() {
-    return pool_selection2str($self->pool, &$self->q, 0);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  const char *__repr__() {
-    const char *str = pool_selection2str($self->pool, &$self->q, ~0);
-    return pool_tmpjoin($self->pool, "<Selection ", str, ">");
-  }
-}
-
-%extend Chksum {
-  Chksum(Id type) {
-    return solv_chksum_create(type);
-  }
-  Chksum(Id type, const char *hex) {
-    unsigned char buf[64];
-    int l = solv_chksum_len(type);
-    if (!l)
-      return 0;
-    if (solv_hex2bin(&hex, buf, sizeof(buf)) != l || hex[0])
-      return 0;
-    return solv_chksum_create_from_bin(type, buf);
-  }
-  %newobject from_bin;
-  static Chksum *from_bin(Id type, const unsigned char *str, size_t len) {
-    return len == solv_chksum_len(type) ? solv_chksum_create_from_bin(type, str) : 0;
-  }
-#if defined(SWIGPERL)
-  %perlcode {
-    undef *solv::Chksum::from_bin;
-    *solv::Chksum::from_bin = sub {
-      my $pkg = shift;
-      my $self = solvc::Chksum_from_bin(@_);
-      bless $self, $pkg if defined $self;
-    };
-  }
-#endif
-  ~Chksum() {
-    solv_chksum_free($self, 0);
-  }
-  Id const type;
-  %{
-  SWIGINTERN Id Chksum_type_get(Chksum *chk) {
-    return solv_chksum_get_type(chk);
-  }
-  %}
-  void add(const unsigned char *str, size_t len) {
-    solv_chksum_add($self, str, (int)len);
-  }
-  void add_fp(FILE *fp) {
-    char buf[4096];
-    int l;
-    while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
-      solv_chksum_add($self, buf, l);
-    rewind(fp);         /* convenience */
-  }
-  void add_fd(int fd) {
-    char buf[4096];
-    int l;
-    while ((l = read(fd, buf, sizeof(buf))) > 0)
-      solv_chksum_add($self, buf, l);
-    lseek(fd, 0, 0);    /* convenience */
-  }
-  void add_stat(const char *filename) {
-    struct stat stb;
-    if (stat(filename, &stb))
-      memset(&stb, 0, sizeof(stb));
-    solv_chksum_add($self, &stb.st_dev, sizeof(stb.st_dev));
-    solv_chksum_add($self, &stb.st_ino, sizeof(stb.st_ino));
-    solv_chksum_add($self, &stb.st_size, sizeof(stb.st_size));
-    solv_chksum_add($self, &stb.st_mtime, sizeof(stb.st_mtime));
-  }
-  void add_fstat(int fd) {
-    struct stat stb;
-    if (fstat(fd, &stb))
-      memset(&stb, 0, sizeof(stb));
-    solv_chksum_add($self, &stb.st_dev, sizeof(stb.st_dev));
-    solv_chksum_add($self, &stb.st_ino, sizeof(stb.st_ino));
-    solv_chksum_add($self, &stb.st_size, sizeof(stb.st_size));
-    solv_chksum_add($self, &stb.st_mtime, sizeof(stb.st_mtime));
-  }
-  BinaryBlob raw() {
-    BinaryBlob bl;
-    int l;
-    const unsigned char *b;
-    b = solv_chksum_get($self, &l);
-    bl.data = b;
-    bl.len = l;
-    return bl;
-  }
-  %newobject hex;
-  char *hex() {
-    int l;
-    const unsigned char *b;
-    char *ret;
-
-    b = solv_chksum_get($self, &l);
-    ret = solv_malloc(2 * l + 1);
-    solv_bin2hex(b, l, ret);
-    return ret;
-  }
-  const char *typestr() {
-    return solv_chksum_type2str(solv_chksum_get_type($self));
-  }
-
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(Chksum *chk) {
-    return solv_chksum_cmp($self, chk);
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(Chksum *chk) {
-    return !solv_chksum_cmp($self, chk);
-  }
-#if defined(SWIGRUBY)
-  %rename("to_s") __str__;
-#endif
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  %newobject __str__;
-  const char *__str__() {
-    const char *str;
-    const char *h = 0;
-    if (solv_chksum_isfinished($self))
-      h = Chksum_hex($self);
-    str = solv_dupjoin(solv_chksum_type2str(solv_chksum_get_type($self)), ":", h ? h : "unfinished");
-    solv_free((void *)h);
-    return str;
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  %newobject __repr__;
-  const char *__repr__() {
-    const char *h = Chksum___str__($self);
-    const char *str = solv_dupjoin("<Chksum ", h, ">");
-    solv_free((void *)h);
-    return str;
-  }
-}
-
-%extend Pool {
-  static const int POOL_FLAG_PROMOTEEPOCH = POOL_FLAG_PROMOTEEPOCH;
-  static const int POOL_FLAG_FORBIDSELFCONFLICTS = POOL_FLAG_FORBIDSELFCONFLICTS;
-  static const int POOL_FLAG_OBSOLETEUSESPROVIDES = POOL_FLAG_OBSOLETEUSESPROVIDES;
-  static const int POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES = POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES;
-  static const int POOL_FLAG_OBSOLETEUSESCOLORS = POOL_FLAG_OBSOLETEUSESCOLORS;
-  static const int POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS = POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS;
-  static const int POOL_FLAG_NOINSTALLEDOBSOLETES = POOL_FLAG_NOINSTALLEDOBSOLETES;
-  static const int POOL_FLAG_HAVEDISTEPOCH = POOL_FLAG_HAVEDISTEPOCH;
-  static const int POOL_FLAG_NOOBSOLETESMULTIVERSION = POOL_FLAG_NOOBSOLETESMULTIVERSION;
-
-  Pool() {
-    Pool *pool = pool_create();
-    return pool;
-  }
-  void set_debuglevel(int level) {
-    pool_setdebuglevel($self, level);
-  }
-  int set_flag(int flag, int value) {
-    return pool_set_flag($self, flag, value);
-  }
-  int get_flag(int flag) {
-    return pool_get_flag($self, flag);
-  }
-  void set_rootdir(const char *rootdir) {
-    pool_set_rootdir($self, rootdir);
-  }
-  const char *get_rootdir(int flag) {
-    return pool_get_rootdir($self);
-  }
-#if defined(SWIGPYTHON)
-  %{
-  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
-    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
-    PyObject *args = Py_BuildValue("(O)", SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0));
-    PyObject *result = PyEval_CallObject((PyObject *)d, args);
-    int ecode = 0;
-    int vresult = 0;
-    Py_DECREF(args);
-    if (!result)
-      return 0; /* exception */
-    ecode = SWIG_AsVal_int(result, &vresult);
-    Py_DECREF(result);
-    return SWIG_IsOK(ecode) ? vresult : 0;
-  }
-  %}
-  void clr_loadcallback() {
-    if ($self->loadcallback == loadcallback) {
-      PyObject *obj = $self->loadcallbackdata;
-      Py_DECREF(obj);
-      pool_setloadcallback($self, 0, 0);
-    }
-  }
-  void set_loadcallback(PyObject *callable) {
-    Pool_clr_loadcallback($self);
-    if (callable) {
-      Py_INCREF(callable);
-      pool_setloadcallback($self, loadcallback, callable);
-    }
-  }
-#elif defined(SWIGPERL)
-%{
-  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
-    int count;
-    int ret = 0;
-    dSP;
-    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
-
-    ENTER;
-    SAVETMPS;
-    PUSHMARK(SP);
-    XPUSHs(SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_OWNER | SWIG_SHADOW));
-    PUTBACK;
-    count = perl_call_sv((SV *)d, G_EVAL|G_SCALAR);
-    SPAGAIN;
-    if (count)
-      ret = POPi;
-    PUTBACK;
-    FREETMPS;
-    LEAVE;
-    return ret;
-  }
-%}
-  void clr_loadcallback() {
-    if ($self->loadcallback == loadcallback) {
-      SvREFCNT_dec($self->loadcallbackdata);
-      pool_setloadcallback($self, 0, 0);
-    }
-  }
-  void set_loadcallback(SV *callable) {
-    Pool_clr_loadcallback($self);
-    if (callable) {
-      SvREFCNT_inc(callable);
-      pool_setloadcallback($self, loadcallback, callable);
-    }
-  }
-#elif defined(SWIGRUBY)
-%{
-  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
-    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
-    VALUE callable = (VALUE)d;
-    VALUE rd = SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0);
-    VALUE res = rb_funcall(callable, rb_intern("call"), 1, rd);
-    return res == Qtrue;
-  }
-  SWIGINTERN void mark_Pool(void *ptr) {
-    Pool *pool = ptr;
-    if (pool->loadcallback == loadcallback && pool->loadcallbackdata) {
-      VALUE callable = (VALUE)pool->loadcallbackdata;
-      rb_gc_mark(callable);
-    }
-  }
-%}
-  void clr_loadcallback() {
-    pool_setloadcallback($self, 0, 0);
-  }
-  %typemap(in, numinputs=0) VALUE callable {
-    $1 = rb_block_given_p() ? rb_block_proc() : 0;
-  }
-  void set_loadcallback(VALUE callable) {
-    pool_setloadcallback($self, callable ? loadcallback : 0, (void *)callable);
-  }
-#elif defined(SWIGTCL)
-  %{
-  typedef struct {
-    Tcl_Interp *interp;
-    Tcl_Obj *obj;
-  } tcl_callback_t;
-  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
-    tcl_callback_t *callback_var = (tcl_callback_t *)d;
-    Tcl_Interp *interp = callback_var->interp;
-    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
-    int result, ecode = 0, vresult = 0;
-    Tcl_Obj *objvx[2];
-    objvx[0] = callback_var->obj;
-    objvx[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, 0); 
-    Tcl_IncrRefCount(objvx[1]);
-    result = Tcl_EvalObjv(interp, sizeof(objvx)/sizeof(*objvx), objvx, TCL_EVAL_GLOBAL);
-    Tcl_DecrRefCount(objvx[1]);
-    if (result != TCL_OK)
-      return 0; /* exception */
-    ecode = SWIG_AsVal_int(interp, Tcl_GetObjResult(interp), &vresult);
-    return SWIG_IsOK(ecode) ? vresult : 0;
-  }
-  %}
-  void clr_loadcallback() {
-    if ($self->loadcallback == loadcallback) {
-      tcl_callback_t *callback_var = $self->loadcallbackdata;
-      Tcl_DecrRefCount(callback_var->obj);
-      solv_free(callback_var);
-      pool_setloadcallback($self, 0, 0);
-    }
-  }
-  void set_loadcallback(Tcl_Obj *callable, Tcl_Interp *interp) {
-    Pool_clr_loadcallback($self);
-    if (callable) {
-      tcl_callback_t *callback_var = solv_malloc(sizeof(tcl_callback_t));
-      Tcl_IncrRefCount(callable);
-      callback_var->interp = interp;
-      callback_var->obj = callable;
-      pool_setloadcallback($self, loadcallback, callback_var);
-    }
-  }
-#else
-#warning loadcallback not implemented for this language
-#endif
-
-  ~Pool() {
-    Pool *pool = $self;
-    Id repoid;
-    Repo *repo;
-    FOR_REPOS(repoid, repo)
-      appdata_clr_helper(&repo->appdata);
-    Pool_clr_loadcallback(pool);
-    appdata_clr_helper(&pool->appdata);
-    pool_free(pool);
-  }
-  disown_helper free() {
-    Pool *pool = $self;
-    Id repoid;
-    Repo *repo;
-    FOR_REPOS(repoid, repo)
-      appdata_clr_helper(&repo->appdata);
-    Pool_clr_loadcallback(pool);
-    appdata_clr_helper(&pool->appdata);
-    pool_free(pool);
-    return 0;
-  }
-  disown_helper disown() {
-    return 0;
-  }
-  AppObjectPtr appdata;
-  %{
-  SWIGINTERN void Pool_appdata_set(Pool *pool, AppObjectPtr appdata) {
-    appdata_set_helper(&pool->appdata, appdata);
-  }
-  SWIGINTERN AppObjectPtr Pool_appdata_get(Pool *pool) {
-    return appdata_get_helper(pool->appdata);
-  }
-  %}
-  void appdata_disown() {
-    appdata_disown_helper($self->appdata);
-  }
-
-  Id str2id(const char *str, bool create=1) {
-    return pool_str2id($self, str, create);
-  }
-  %newobject Dep;
-  Dep *Dep(const char *str, bool create=1) {
-    Id id = pool_str2id($self, str, create);
-    return new_Dep($self, id);
-  }
-  const char *id2str(Id id) {
-    return pool_id2str($self, id);
-  }
-  const char *dep2str(Id id) {
-    return pool_dep2str($self, id);
-  }
-  Id rel2id(Id name, Id evr, int flags, bool create=1) {
-    return pool_rel2id($self, name, evr, flags, create);
-  }
-  Id id2langid(Id id, const char *lang, bool create=1) {
-    return pool_id2langid($self, id, lang, create);
-  }
-  void setarch(const char *arch = 0) {
-    struct utsname un;
-    if (!arch) {
-      if (uname(&un)) {
-        perror("uname");
-        return;
-      }
-      arch = un.machine;
-    }
-    pool_setarch($self, arch);
-  }
-  Repo *add_repo(const char *name) {
-    return repo_create($self, name);
-  }
-  const char *lookup_str(Id entry, Id keyname) {
-    return pool_lookup_str($self, entry, keyname);
-  }
-  Id lookup_id(Id entry, Id keyname) {
-    return pool_lookup_id($self, entry, keyname);
-  }
-  unsigned long long lookup_num(Id entry, Id keyname, unsigned long long notfound = 0) {
-    return pool_lookup_num($self, entry, keyname, notfound);
-  }
-  bool lookup_void(Id entry, Id keyname) {
-    return pool_lookup_void($self, entry, keyname);
-  }
-  %newobject lookup_checksum;
-  Chksum *lookup_checksum(Id entry, Id keyname) {
-    Id type = 0;
-    const unsigned char *b = pool_lookup_bin_checksum($self, entry, keyname, &type);
-    return solv_chksum_create_from_bin(type, b);
-  }
-
-  %newobject Dataiterator;
-  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
-    return new_Dataiterator($self, 0, 0, key, match, flags);
-  }
-  %newobject Dataiterator_solvid;
-  Dataiterator *Dataiterator_solvid(Id p, Id key, const char *match = 0, int flags = 0) {
-    return new_Dataiterator($self, 0, p, key, match, flags);
-  }
-  const char *solvid2str(Id solvid) {
-    return pool_solvid2str($self, solvid);
-  }
-  void addfileprovides() {
-    pool_addfileprovides($self);
-  }
-  Queue addfileprovides_queue() {
-    Queue r;
-    queue_init(&r);
-    pool_addfileprovides_queue($self, &r, 0);
-    return r;
-  }
-  void createwhatprovides() {
-    pool_createwhatprovides($self);
-  }
-
-  %newobject id2solvable;
-  XSolvable *id2solvable(Id id) {
-    return new_XSolvable($self, id);
-  }
-  %newobject solvables;
-  Pool_solvable_iterator * const solvables;
-  %{
-  SWIGINTERN Pool_solvable_iterator * Pool_solvables_get(Pool *pool) {
-    return new_Pool_solvable_iterator(pool);
-  }
-  %}
-  %newobject solvables_iter;
-  Pool_solvable_iterator * solvables_iter() {
-    return new_Pool_solvable_iterator($self);
-  }
-
-  Repo *id2repo(Id id) {
-    if (id < 1 || id >= $self->nrepos)
-      return 0;
-    return pool_id2repo($self, id);
-  }
-
-  %newobject repos;
-  Pool_repo_iterator * const repos;
-  %{
-  SWIGINTERN Pool_repo_iterator * Pool_repos_get(Pool *pool) {
-    return new_Pool_repo_iterator(pool);
-  }
-  %}
-  %newobject repos_iter;
-  Pool_repo_iterator * repos_iter() {
-    return new_Pool_repo_iterator($self);
-  }
-
-  Repo *installed;
-  const char * const errstr;
-  %{
-  SWIGINTERN void Pool_installed_set(Pool *pool, Repo *installed) {
-    pool_set_installed(pool, installed);
-  }
-  SWIGINTERN Repo *Pool_installed_get(Pool *pool) {
-    return pool->installed;
-  }
-  SWIGINTERN const char *Pool_errstr_get(Pool *pool) {
-    return pool_errstr(pool);
-  }
-  %}
-
-  Queue matchprovidingids(const char *match, int flags) {
-    Pool *pool = $self;
-    Queue q;
-    Id id;
-    queue_init(&q);
-    if (!flags) {
-      for (id = 1; id < pool->ss.nstrings; id++)
-        if (pool->whatprovides[id])
-          queue_push(&q, id);
-    } else {
-      Datamatcher ma;
-      if (!datamatcher_init(&ma, match, flags)) {
-        for (id = 1; id < pool->ss.nstrings; id++)
-          if (pool->whatprovides[id] && datamatcher_match(&ma, pool_id2str(pool, id)))
-            queue_push(&q, id);
-        datamatcher_free(&ma);
-      }
-    }
-    return q;
-  }
-
-  %newobject Job;
-  Job *Job(int how, Id what) {
-    return new_Job($self, how, what);
-  }
-
-  %typemap(out) Queue whatprovides Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
-  %newobject whatprovides;
-  Queue whatprovides(DepId dep) {
-    Pool *pool = $self;
-    Queue q;
-    Id p, pp;
-    queue_init(&q);
-    FOR_PROVIDES(p, pp, dep)
-      queue_push(&q, p);
-    return q;
-  }
-
-  Id towhatprovides(Queue q) {
-    return pool_queuetowhatprovides($self, &q);
-  }
-
-  %typemap(out) Queue whatmatchesdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
-  %newobject whatmatchesdep;
-  Queue whatmatchesdep(Id keyname, DepId dep, Id marker = -1) {
-    Queue q;
-    queue_init(&q);
-    pool_whatmatchesdep($self, keyname, dep, &q, marker);
-    return q;
-  }
-
-#ifdef SWIGRUBY
-  %rename("isknownarch?") isknownarch;
-#endif
-  bool isknownarch(DepId id) {
-    Pool *pool = $self;
-    if (!id || id == ID_EMPTY)
-      return 0;
-    if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
-      return 1;
-    if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
-      return 0;
-    return 1;
-  }
-
-  %newobject Solver;
-  Solver *Solver() {
-    return solver_create($self);
-  }
-
-  %newobject Selection;
-  Selection *Selection() {
-    return new_Selection($self);
-  }
-  %newobject Selection_all;
-  Selection *Selection_all(int setflags=0) {
-    Selection *sel = new_Selection($self);
-    queue_push2(&sel->q, SOLVER_SOLVABLE_ALL | setflags, 0);
-    return sel;
-  }
-  %newobject select;
-  Selection *select(const char *name, int flags) {
-    Selection *sel = new_Selection($self);
-    sel->flags = selection_make($self, &sel->q, name, flags);
-    return sel;
-  }
-
-  void setpooljobs_helper(Queue jobs) {
-    queue_free(&$self->pooljobs);
-    queue_init_clone(&$self->pooljobs, &jobs);
-  }
-  %typemap(out) Queue getpooljobs Queue2Array(Job *, 2, new_Job(arg1, id, idp[1]));
-  %newobject getpooljobs;
-  Queue getpooljobs() {
-    Queue q;
-    queue_init_clone(&q, &$self->pooljobs);
-    return q;
-  }
-
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def setpooljobs(self, jobs):
-      j = []
-      for job in jobs: j += [job.how, job.what]
-      self.setpooljobs_helper(j)
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Solver::setpooljobs {
-      my ($self, $jobs) = @_;
-      my @j = map {($_->{'how'}, $_->{'what'})} @$jobs;
-      return $self->setpooljobs_helper(\@j);
-    }
-  }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Pool\n"
-    "  def setpooljobs(jobs)\n"
-    "    jl = []\n"
-    "    jobs.each do |j| ; jl << j.how << j.what ; end\n"
-    "    setpooljobs_helper(jl)\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
-}
-
-%extend Repo {
-  static const int REPO_REUSE_REPODATA = REPO_REUSE_REPODATA;
-  static const int REPO_NO_INTERNALIZE = REPO_NO_INTERNALIZE;
-  static const int REPO_LOCALPOOL = REPO_LOCALPOOL;
-  static const int REPO_USE_LOADING = REPO_USE_LOADING;
-  static const int REPO_EXTEND_SOLVABLES = REPO_EXTEND_SOLVABLES;
-  static const int REPO_USE_ROOTDIR = REPO_USE_ROOTDIR;
-  static const int REPO_NO_LOCATION = REPO_NO_LOCATION;
-  static const int SOLV_ADD_NO_STUBS = SOLV_ADD_NO_STUBS;       /* repo_solv */
-#ifdef ENABLE_SUSEREPO
-  static const int SUSETAGS_RECORD_SHARES = SUSETAGS_RECORD_SHARES;     /* repo_susetags */
-#endif
-
-  void free(bool reuseids = 0) {
-    appdata_clr_helper(&$self->appdata);
-    repo_free($self, reuseids);
-  }
-  void empty(bool reuseids = 0) {
-    repo_empty($self, reuseids);
-  }
-#ifdef SWIGRUBY
-  %rename("isempty?") isempty;
-#endif
-  bool isempty() {
-    return !$self->nsolvables;
-  }
-
-  AppObjectPtr appdata;
-  %{
-  SWIGINTERN void Repo_appdata_set(Repo *repo, AppObjectPtr appdata) {
-    appdata_set_helper(&repo->appdata, appdata);
-  }
-  SWIGINTERN AppObjectPtr Repo_appdata_get(Repo *repo) {
-    return appdata_get_helper(repo->appdata);
-  }
-  %}
-
-  bool add_solv(const char *name, int flags = 0) {
-    FILE *fp = fopen(name, "r");
-    int r;
-    if (!fp)
-      return 0;
-    r = repo_add_solv($self, fp, flags);
-    fclose(fp);
-    return r == 0;
-  }
-  bool add_solv(FILE *fp, int flags = 0) {
-    return repo_add_solv($self, fp, flags) == 0;
-  }
-
-  %newobject add_solvable;
-  XSolvable *add_solvable() {
-    Id solvid = repo_add_solvable($self);
-    return new_XSolvable($self->pool, solvid);
-  }
-
-#ifdef ENABLE_RPMDB
-  bool add_rpmdb(int flags = 0) {
-    return repo_add_rpmdb($self, 0, flags) == 0;
-  }
-  bool add_rpmdb_reffp(FILE *reffp, int flags = 0) {
-    return repo_add_rpmdb_reffp($self, reffp, flags) == 0;
-  }
-  %newobject add_rpm;
-  XSolvable *add_rpm(const char *name, int flags = 0) {
-    return new_XSolvable($self->pool, repo_add_rpm($self, name, flags));
-  }
-#endif
-#ifdef ENABLE_PUBKEY
-#ifdef ENABLE_RPMDB
-  bool add_rpmdb_pubkeys(int flags = 0) {
-    return repo_add_rpmdb_pubkeys($self, flags) == 0;
-  }
-#endif
-  %newobject add_pubkey;
-  XSolvable *add_pubkey(const char *keyfile, int flags = 0) {
-    return new_XSolvable($self->pool, repo_add_pubkey($self, keyfile, flags));
-  }
-  bool add_keyring(FILE *fp, int flags = 0) {
-    return repo_add_keyring($self, fp, flags);
-  }
-  bool add_keydir(const char *keydir, const char *suffix, int flags = 0) {
-    return repo_add_keydir($self, keydir, suffix, flags);
-  }
-#endif
-#ifdef ENABLE_RPMMD
-  bool add_rpmmd(FILE *fp, const char *language, int flags = 0) {
-    return repo_add_rpmmd($self, fp, language, flags) == 0;
-  }
-  bool add_repomdxml(FILE *fp, int flags = 0) {
-    return repo_add_repomdxml($self, fp, flags) == 0;
-  }
-  bool add_updateinfoxml(FILE *fp, int flags = 0) {
-    return repo_add_updateinfoxml($self, fp, flags) == 0;
-  }
-  bool add_deltainfoxml(FILE *fp, int flags = 0) {
-    return repo_add_deltainfoxml($self, fp, flags) == 0;
-  }
-#endif
-#ifdef ENABLE_DEBIAN
-  bool add_debdb(int flags = 0) {
-    return repo_add_debdb($self, flags) == 0;
-  }
-  bool add_debpackages(FILE *fp, int flags = 0) {
-    return repo_add_debpackages($self, fp, flags) == 0;
-  }
-  %newobject add_deb;
-  XSolvable *add_deb(const char *name, int flags = 0) {
-    return new_XSolvable($self->pool, repo_add_deb($self, name, flags));
-  }
-#endif
-#ifdef ENABLE_SUSEREPO
-  bool add_susetags(FILE *fp, Id defvendor, const char *language, int flags = 0) {
-    return repo_add_susetags($self, fp, defvendor, language, flags) == 0;
-  }
-  bool add_content(FILE *fp, int flags = 0) {
-    return repo_add_content($self, fp, flags) == 0;
-  }
-  bool add_products(const char *proddir, int flags = 0) {
-    return repo_add_products($self, proddir, flags) == 0;
-  }
-#endif
-#ifdef ENABLE_MDKREPO
-  bool add_mdk(FILE *fp, int flags = 0) {
-    return repo_add_mdk($self, fp, flags) == 0;
-  }
-  bool add_mdk_info(FILE *fp, int flags = 0) {
-    return repo_add_mdk_info($self, fp, flags) == 0;
-  }
-#endif
-#ifdef ENABLE_ARCHREPO
-  bool add_arch_repo(FILE *fp, int flags = 0) {
-    return repo_add_arch_repo($self, fp, flags) == 0;
-  }
-  bool add_arch_local(const char *dir, int flags = 0) {
-    return repo_add_arch_local($self, dir, flags) == 0;
-  }
-  %newobject add_arch_pkg;
-  XSolvable *add_arch_pkg(const char *name, int flags = 0) {
-    return new_XSolvable($self->pool, repo_add_arch_pkg($self, name, flags));
-  }
-#endif
-#ifdef SUSE
-  bool add_autopattern(int flags = 0) {
-    return repo_add_autopattern($self, flags) == 0;
-  }
-#endif
-  void internalize() {
-    repo_internalize($self);
-  }
-  bool write(FILE *fp) {
-    return repo_write($self, fp) == 0;
-  }
-  /* HACK, remove if no longer needed! */
-  bool write_first_repodata(FILE *fp) {
-    int oldnrepodata = $self->nrepodata;
-    int res;
-    $self->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata;
-    res = repo_write($self, fp);
-    $self->nrepodata = oldnrepodata;
-    return res == 0;
-  }
-
-  %newobject Dataiterator;
-  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
-    return new_Dataiterator($self->pool, $self, 0, key, match, flags);
-  }
-  %newobject Dataiterator_meta;
-  Dataiterator *Dataiterator_meta(Id key, const char *match = 0, int flags = 0) {
-    return new_Dataiterator($self->pool, $self, SOLVID_META, key, match, flags);
-  }
-
-  Id const id;
-  %{
-  SWIGINTERN Id Repo_id_get(Repo *repo) {
-    return repo->repoid;
-  }
-  %}
-  %newobject solvables;
-  Repo_solvable_iterator * const solvables;
-  %{
-  SWIGINTERN Repo_solvable_iterator * Repo_solvables_get(Repo *repo) {
-    return new_Repo_solvable_iterator(repo);
-  }
-  %}
-  %newobject meta;
-  Datapos * const meta;
-  %{
-  SWIGINTERN Datapos * Repo_meta_get(Repo *repo) {
-    Datapos *pos = solv_calloc(1, sizeof(*pos));
-    pos->solvid = SOLVID_META;
-    pos->repo = repo;
-    return pos;
-  }
-  %}
-
-  %newobject solvables_iter;
-  Repo_solvable_iterator *solvables_iter() {
-    return new_Repo_solvable_iterator($self);
-  }
-
-  %newobject add_repodata;
-  XRepodata *add_repodata(int flags = 0) {
-    Repodata *rd = repo_add_repodata($self, flags);
-    return new_XRepodata($self, rd->repodataid);
-  }
-
-  void create_stubs() {
-    Repodata *data;
-    if (!$self->nrepodata)
-      return;
-    data = repo_id2repodata($self, $self->nrepodata - 1);
-    if (data->state != REPODATA_STUB)
-      (void)repodata_create_stubs(data);
-  }
-#ifdef SWIGRUBY
-  %rename("iscontiguous?") iscontiguous;
-#endif
-  bool iscontiguous() {
-    int i;
-    for (i = $self->start; i < $self->end; i++)
-      if ($self->pool->solvables[i].repo != $self)
-        return 0;
-    return 1;
-  }
-  %newobject first_repodata;
-  XRepodata *first_repodata() {
-    Repodata *data;
-    int i;
-    if ($self->nrepodata < 2)
-      return 0;
-    /* make sure all repodatas but the first are extensions */
-    data = repo_id2repodata($self, 1);
-    if (data->loadcallback)
-       return 0;
-    for (i = 2; i < $self->nrepodata; i++)
-      {
-        data = repo_id2repodata($self, i);
-        if (!data->loadcallback)
-          return 0;       /* oops, not an extension */
-      }
-    return new_XRepodata($self, 1);
-  }
-
-  %newobject Selection;
-  Selection *Selection(int setflags=0) {
-    Selection *sel = new_Selection($self->pool);
-    setflags |= SOLVER_SETREPO;
-    queue_push2(&sel->q, SOLVER_SOLVABLE_REPO | setflags, $self->repoid);
-    return sel;
-  }
-
-#ifdef ENABLE_PUBKEY
-  %newobject find_pubkey;
-  XSolvable *find_pubkey(const char *keyid) {
-    return new_XSolvable($self->pool, repo_find_pubkey($self, keyid));
-  }
-#endif
-
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(Repo *repo) {
-    return $self == repo;
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(Repo *repo) {
-    return $self != repo;
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  %newobject __str__;
-  const char *__str__() {
-    char buf[20];
-    if ($self->name)
-      return solv_strdup($self->name);
-    sprintf(buf, "Repo#%d", $self->repoid);
-    return solv_strdup(buf);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  %newobject __repr__;
-  const char *__repr__() {
-    char buf[20];
-    if ($self->name)
-      {
-        sprintf(buf, "<Repo #%d ", $self->repoid);
-        return solv_dupjoin(buf, $self->name, ">");
-      }
-    sprintf(buf, "<Repo #%d>", $self->repoid);
-    return solv_strdup(buf);
-  }
-}
-
-%extend Dataiterator {
-  static const int SEARCH_STRING = SEARCH_STRING;
-  static const int SEARCH_STRINGSTART = SEARCH_STRINGSTART;
-  static const int SEARCH_STRINGEND = SEARCH_STRINGEND;
-  static const int SEARCH_SUBSTRING = SEARCH_SUBSTRING;
-  static const int SEARCH_GLOB = SEARCH_GLOB;
-  static const int SEARCH_REGEX = SEARCH_REGEX;
-  static const int SEARCH_NOCASE = SEARCH_NOCASE;
-  static const int SEARCH_FILES = SEARCH_FILES;
-  static const int SEARCH_COMPLETE_FILELIST = SEARCH_COMPLETE_FILELIST;
-  static const int SEARCH_CHECKSUMS = SEARCH_CHECKSUMS;
-
-  Dataiterator(Pool *pool, Repo *repo, Id p, Id key, const char *match, int flags) {
-    Dataiterator *di = solv_calloc(1, sizeof(*di));
-    dataiterator_init(di, pool, repo, p, key, match, flags);
-    return di;
-  }
-  ~Dataiterator() {
-    dataiterator_free($self);
-    solv_free($self);
-  }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def __iter__(self): return self
-  }
-#ifndef PYTHON3
-  %rename("next") __next__();
-#endif
-  %exception __next__ {
-    $action
-    if (!result) {
-      PyErr_SetString(PyExc_StopIteration,"no more matches");
-      return NULL;
-    }
-  }
-#endif
-#ifdef SWIGPERL
-  perliter(solv::Dataiterator)
-#endif
-  %newobject __next__;
-  Datamatch *__next__() {
-    Dataiterator *ndi;
-    if (!dataiterator_step($self)) {
-      return 0;
-    }
-    ndi = solv_calloc(1, sizeof(*ndi));
-    dataiterator_init_clone(ndi, $self);
-    dataiterator_strdup(ndi);
-    return ndi;
-  }
-#ifdef SWIGRUBY
-  void each() {
-    Datamatch *d;
-    while ((d = Dataiterator___next__($self)) != 0) {
-      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(d), SWIGTYPE_p_Datamatch, SWIG_POINTER_OWN | 0));
-    }
-  }
-#endif
-  void prepend_keyname(Id key) {
-    dataiterator_prepend_keyname($self, key);
-  }
-  void skip_solvable() {
-    dataiterator_skip_solvable($self);
-  }
-}
-
-%extend Datapos {
-  Id lookup_id(Id keyname) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    Id r;
-    pool->pos = *$self;
-    r = pool_lookup_id(pool, SOLVID_POS, keyname);
-    pool->pos = oldpos;
-    return r;
-  }
-  const char *lookup_str(Id keyname) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    const char *r;
-    pool->pos = *$self;
-    r = pool_lookup_str(pool, SOLVID_POS, keyname);
-    pool->pos = oldpos;
-    return r;
-  }
-  unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    unsigned long long r;
-    pool->pos = *$self;
-    r = pool_lookup_num(pool, SOLVID_POS, keyname, notfound);
-    pool->pos = oldpos;
-    return r;
-  }
-  bool lookup_void(Id keyname) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    int r;
-    pool->pos = *$self;
-    r = pool_lookup_void(pool, SOLVID_POS, keyname);
-    pool->pos = oldpos;
-    return r;
-  }
-  %newobject lookup_checksum;
-  Chksum *lookup_checksum(Id keyname) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    Id type = 0;
-    const unsigned char *b;
-    pool->pos = *$self;
-    b = pool_lookup_bin_checksum(pool, SOLVID_POS, keyname, &type);
-    pool->pos = oldpos;
-    return solv_chksum_create_from_bin(type, b);
-  }
-  const char *lookup_deltaseq() {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    const char *seq;
-    pool->pos = *$self;
-    seq = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME);
-    if (seq) {
-      seq = pool_tmpjoin(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR));
-      seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM));
-    }
-    pool->pos = oldpos;
-    return seq;
-  }
-  const char *lookup_deltalocation(unsigned int *OUTPUT) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    const char *loc;
-    pool->pos = *$self;
-    loc = pool_lookup_deltalocation(pool, SOLVID_POS, OUTPUT);
-    pool->pos = oldpos;
-    return loc;
-  }
-  Queue lookup_idarray(Id keyname) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    Queue r;
-    queue_init(&r);
-    pool->pos = *$self;
-    pool_lookup_idarray(pool, SOLVID_POS, keyname, &r);
-    pool->pos = oldpos;
-    return r;
-  }
-  %newobject Dataiterator;
-  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
-    Pool *pool = $self->repo->pool;
-    Datapos oldpos = pool->pos;
-    Dataiterator *di;
-    pool->pos = *$self;
-    di = new_Dataiterator(pool, 0, SOLVID_POS, key, match, flags);
-    pool->pos = oldpos;
-    return di;
-  }
-}
-
-%extend Datamatch {
-  ~Datamatch() {
-    dataiterator_free($self);
-    solv_free($self);
-  }
-  %newobject solvable;
-  XSolvable * const solvable;
-  Id const key_id;
-  const char * const key_idstr;
-  Id const type_id;
-  const char * const type_idstr;
-  Id const id;
-  const char * const idstr;
-  const char * const str;
-  BinaryBlob const binary;
-  unsigned long long const num;
-  unsigned int const num2;
-  %{
-  SWIGINTERN XSolvable *Datamatch_solvable_get(Dataiterator *di) {
-    return new_XSolvable(di->pool, di->solvid);
-  }
-  SWIGINTERN Id Datamatch_key_id_get(Dataiterator *di) {
-    return di->key->name;
-  }
-  SWIGINTERN const char *Datamatch_key_idstr_get(Dataiterator *di) {
-    return pool_id2str(di->pool, di->key->name);
-  }
-  SWIGINTERN Id Datamatch_type_id_get(Dataiterator *di) {
-    return di->key->type;
-  }
-  SWIGINTERN const char *Datamatch_type_idstr_get(Dataiterator *di) {
-    return pool_id2str(di->pool, di->key->type);
-  }
-  SWIGINTERN Id Datamatch_id_get(Dataiterator *di) {
-    return di->kv.id;
-  }
-  SWIGINTERN const char *Datamatch_idstr_get(Dataiterator *di) {
-   if (di->data && (di->key->type == REPOKEY_TYPE_DIR || di->key->type == REPOKEY_TYPE_DIRSTRARRAY || di->key->type == REPOKEY_TYPE_DIRNUMNUMARRAY))
-      return repodata_dir2str(di->data,  di->kv.id, 0);
-    if (di->data && di->data->localpool)
-      return stringpool_id2str(&di->data->spool, di->kv.id);
-    return pool_id2str(di->pool, di->kv.id);
-  }
-  SWIGINTERN const char * const Datamatch_str_get(Dataiterator *di) {
-    return di->kv.str;
-  }
-  SWIGINTERN BinaryBlob Datamatch_binary_get(Dataiterator *di) {
-    BinaryBlob bl;
-    bl.data = 0;
-    bl.len = 0;
-    if (di->key->type == REPOKEY_TYPE_BINARY)
-      {
-        bl.data = di->kv.str;
-        bl.len = di->kv.num;
-      }
-    else if ((bl.len = solv_chksum_len(di->key->type)) != 0)
-      bl.data = di->kv.str;
-    return bl;
-  }
-  SWIGINTERN unsigned long long Datamatch_num_get(Dataiterator *di) {
-   if (di->key->type == REPOKEY_TYPE_NUM)
-     return SOLV_KV_NUM64(&di->kv);
-   return di->kv.num;
-  }
-  SWIGINTERN unsigned int Datamatch_num2_get(Dataiterator *di) {
-    return di->kv.num2;
-  }
-  %}
-  %newobject pos;
-  Datapos *pos() {
-    Pool *pool = $self->pool;
-    Datapos *pos, oldpos = pool->pos;
-    dataiterator_setpos($self);
-    pos = solv_calloc(1, sizeof(*pos));
-    *pos = pool->pos;
-    pool->pos = oldpos;
-    return pos;
-  }
-  %newobject parentpos;
-  Datapos *parentpos() {
-    Pool *pool = $self->pool;
-    Datapos *pos, oldpos = pool->pos;
-    dataiterator_setpos_parent($self);
-    pos = solv_calloc(1, sizeof(*pos));
-    *pos = pool->pos;
-    pool->pos = oldpos;
-    return pos;
-  }
-#if defined(SWIGPERL)
-  /* cannot use str here because swig reports a bogus conflict... */
-  %rename("stringify") __str__;
-  %perlcode {
-    *solv::Datamatch::str = *solvc::Datamatch_stringify;
-  }
-#endif
-#if defined(SWIGTCL)
-  %rename("stringify") __str__;
-#endif
-  const char *__str__() {
-    KeyValue kv = $self->kv;
-    const char *str = repodata_stringify($self->pool, $self->data, $self->key, &kv, SEARCH_FILES | SEARCH_CHECKSUMS);
-    return str ? str : "";
-  }
-}
-
-%extend Pool_solvable_iterator {
-  Pool_solvable_iterator(Pool *pool) {
-    Pool_solvable_iterator *s;
-    s = solv_calloc(1, sizeof(*s));
-    s->pool = pool;
-    return s;
-  }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def __iter__(self): return self
-  }
-#ifndef PYTHON3
-  %rename("next") __next__();
-#endif
-  %exception __next__ {
-    $action
-    if (!result) {
-      PyErr_SetString(PyExc_StopIteration,"no more matches");
-      return NULL;
-    }
-  }
-#endif
-#ifdef SWIGPERL
-  perliter(solv::Pool_solvable_iterator)
-#endif
-  %newobject __next__;
-  XSolvable *__next__() {
-    Pool *pool = $self->pool;
-    if ($self->id >= pool->nsolvables)
-      return 0;
-    while (++$self->id < pool->nsolvables)
-      if (pool->solvables[$self->id].repo)
-        return new_XSolvable(pool, $self->id);
-    return 0;
-  }
-#ifdef SWIGRUBY
-  void each() {
-    XSolvable *n;
-    while ((n = Pool_solvable_iterator___next__($self)) != 0) {
-      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_XSolvable, SWIG_POINTER_OWN | 0));
-    }
-  }
-#endif
-  %newobject __getitem__;
-  XSolvable *__getitem__(Id key) {
-    Pool *pool = $self->pool;
-    if (key > 0 && key < pool->nsolvables && pool->solvables[key].repo)
-      return new_XSolvable(pool, key);
-    return 0;
-  }
-  int __len__() {
-    return $self->pool->nsolvables;
-  }
-}
-
-%extend Pool_repo_iterator {
-  Pool_repo_iterator(Pool *pool) {
-    Pool_repo_iterator *s;
-    s = solv_calloc(1, sizeof(*s));
-    s->pool = pool;
-    return s;
-  }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def __iter__(self): return self
-  }
-#ifndef PYTHON3
-  %rename("next") __next__();
-#endif
-  %exception __next__ {
-    $action
-    if (!result) {
-      PyErr_SetString(PyExc_StopIteration,"no more matches");
-      return NULL;
-    }
-  }
-#endif
-#ifdef SWIGPERL
-  perliter(solv::Pool_repo_iterator)
-#endif
-  %newobject __next__;
-  Repo *__next__() {
-    Pool *pool = $self->pool;
-    if ($self->id >= pool->nrepos)
-      return 0;
-    while (++$self->id < pool->nrepos) {
-      Repo *r = pool_id2repo(pool, $self->id);
-      if (r)
-        return r;
-    }
-    return 0;
-  }
-#ifdef SWIGRUBY
-  void each() {
-    Repo *n;
-    while ((n = Pool_repo_iterator___next__($self)) != 0) {
-      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, SWIG_POINTER_OWN | 0));
-    }
-  }
-#endif
-  Repo *__getitem__(Id key) {
-    Pool *pool = $self->pool;
-    if (key > 0 && key < pool->nrepos)
-      return pool_id2repo(pool, key);
-    return 0;
-  }
-  int __len__() {
-    return $self->pool->nrepos;
-  }
-}
-
-%extend Repo_solvable_iterator {
-  Repo_solvable_iterator(Repo *repo) {
-    Repo_solvable_iterator *s;
-    s = solv_calloc(1, sizeof(*s));
-    s->repo = repo;
-    return s;
-  }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def __iter__(self): return self
-  }
-#ifndef PYTHON3
-  %rename("next") __next__();
-#endif
-  %exception __next__ {
-    $action
-    if (!result) {
-      PyErr_SetString(PyExc_StopIteration,"no more matches");
-      return NULL;
-    }
-  }
-#endif
-#ifdef SWIGPERL
-  perliter(solv::Repo_solvable_iterator)
-#endif
-  %newobject __next__;
-  XSolvable *__next__() {
-    Repo *repo = $self->repo;
-    Pool *pool = repo->pool;
-    if (repo->start > 0 && $self->id < repo->start)
-      $self->id = repo->start - 1;
-    if ($self->id >= repo->end)
-      return 0;
-    while (++$self->id < repo->end)
-      if (pool->solvables[$self->id].repo == repo)
-        return new_XSolvable(pool, $self->id);
-    return 0;
-  }
-#ifdef SWIGRUBY
-  void each() {
-    XSolvable *n;
-    while ((n = Repo_solvable_iterator___next__($self)) != 0) {
-      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_XSolvable, SWIG_POINTER_OWN | 0));
-    }
-  }
-#endif
-  %newobject __getitem__;
-  XSolvable *__getitem__(Id key) {
-    Repo *repo = $self->repo;
-    Pool *pool = repo->pool;
-    if (key > 0 && key < pool->nsolvables && pool->solvables[key].repo == repo)
-      return new_XSolvable(pool, key);
-    return 0;
-  }
-  int __len__() {
-    return $self->repo->pool->nsolvables;
-  }
-}
-
-%extend Dep {
-  Dep(Pool *pool, Id id) {
-    Dep *s;
-    if (!id)
-      return 0;
-    s = solv_calloc(1, sizeof(*s));
-    s->pool = pool;
-    s->id = id;
-    return s;
-  }
-  %newobject Rel;
-  Dep *Rel(int flags, DepId evrid, bool create=1) {
-    Id id = pool_rel2id($self->pool, $self->id, evrid, flags, create);
-    if (!id)
-      return 0;
-    return new_Dep($self->pool, id);
-  }
-  %newobject Selection_name;
-  Selection *Selection_name(int setflags=0) {
-    Selection *sel = new_Selection($self->pool);
-    if (ISRELDEP($self->id)) {
-      Reldep *rd = GETRELDEP($self->pool, $self->id);
-      if (rd->flags == REL_EQ) {
-        setflags |= $self->pool->disttype == DISTTYPE_DEB || strchr(pool_id2str($self->pool, rd->evr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
-        if (ISRELDEP(rd->name))
-          rd = GETRELDEP($self->pool, rd->name);
-      }
-      if (rd->flags == REL_ARCH)
-        setflags |= SOLVER_SETARCH;
-    }
-    queue_push2(&sel->q, SOLVER_SOLVABLE_NAME | setflags, $self->id);
-    return sel;
-  }
-  %newobject Selection_provides;
-  Selection *Selection_provides(int setflags=0) {
-    Selection *sel = new_Selection($self->pool);
-    if (ISRELDEP($self->id)) {
-      Reldep *rd = GETRELDEP($self->pool, $self->id);
-      if (rd->flags == REL_ARCH)
-        setflags |= SOLVER_SETARCH;
-    }
-    queue_push2(&sel->q, SOLVER_SOLVABLE_PROVIDES | setflags, $self->id);
-    return sel;
-  }
-  const char *str() {
-    return pool_dep2str($self->pool, $self->id);
-  }
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(Dep *s) {
-    return $self->pool == s->pool && $self->id == s->id;
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(Dep *s) {
-    return !Dep___eq__($self, s);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  const char *__str__() {
-    return pool_dep2str($self->pool, $self->id);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  %newobject __repr__;
-  const char *__repr__() {
-    char buf[20];
-    sprintf(buf, "<Id #%d ", $self->id);
-    return solv_dupjoin(buf, pool_dep2str($self->pool, $self->id), ">");
-  }
-}
-
-%extend XSolvable {
-  XSolvable(Pool *pool, Id id) {
-    XSolvable *s;
-    if (!id || id >= pool->nsolvables)
-      return 0;
-    s = solv_calloc(1, sizeof(*s));
-    s->pool = pool;
-    s->id = id;
-    return s;
-  }
-  const char *str() {
-    return pool_solvid2str($self->pool, $self->id);
-  }
-  const char *lookup_str(Id keyname) {
-    return pool_lookup_str($self->pool, $self->id, keyname);
-  }
-  Id lookup_id(Id keyname) {
-    return pool_lookup_id($self->pool, $self->id, keyname);
-  }
-  unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) {
-    return pool_lookup_num($self->pool, $self->id, keyname, notfound);
-  }
-  bool lookup_void(Id keyname) {
-    return pool_lookup_void($self->pool, $self->id, keyname);
-  }
-  %newobject lookup_checksum;
-  Chksum *lookup_checksum(Id keyname) {
-    Id type = 0;
-    const unsigned char *b = pool_lookup_bin_checksum($self->pool, $self->id, keyname, &type);
-    return solv_chksum_create_from_bin(type, b);
-  }
-  Queue lookup_idarray(Id keyname, Id marker = -1) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    Queue r;
-    queue_init(&r);
-    solvable_lookup_deparray(s, keyname, &r, marker);
-    return r;
-  }
-  %typemap(out) Queue lookup_deparray Queue2Array(Dep *, 1, new_Dep(arg1->pool, id));
-  %newobject lookup_deparray;
-  Queue lookup_deparray(Id keyname, Id marker = -1) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    Queue r;
-    queue_init(&r);
-    solvable_lookup_deparray(s, keyname, &r, marker);
-    return r;
-  }
-  const char *lookup_location(unsigned int *OUTPUT) {
-    return solvable_lookup_location($self->pool->solvables + $self->id, OUTPUT);
-  }
-  %newobject Dataiterator;
-  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
-    return new_Dataiterator($self->pool, 0, $self->id, key, match, flags);
-  }
-#ifdef SWIGRUBY
-  %rename("installable?") installable;
-#endif
-  bool installable() {
-    return pool_installable($self->pool, pool_id2solvable($self->pool, $self->id));
-  }
-#ifdef SWIGRUBY
-  %rename("isinstalled?") isinstalled;
-#endif
-  bool isinstalled() {
-    Pool *pool = $self->pool;
-    return pool->installed && pool_id2solvable(pool, $self->id)->repo == pool->installed;
-  }
-
-  const char *name;
-  %{
-    SWIGINTERN void XSolvable_name_set(XSolvable *xs, const char *name) {
-      Pool *pool = xs->pool;
-      pool->solvables[xs->id].name = pool_str2id(pool, name, 1);
-    }
-    SWIGINTERN const char *XSolvable_name_get(XSolvable *xs) {
-      Pool *pool = xs->pool;
-      return pool_id2str(pool, pool->solvables[xs->id].name);
-    }
-  %}
-  Id nameid;
-  %{
-    SWIGINTERN void XSolvable_nameid_set(XSolvable *xs, Id nameid) {
-      xs->pool->solvables[xs->id].name = nameid;
-    }
-    SWIGINTERN Id XSolvable_nameid_get(XSolvable *xs) {
-      return xs->pool->solvables[xs->id].name;
-    }
-  %}
-  const char *evr;
-  %{
-    SWIGINTERN void XSolvable_evr_set(XSolvable *xs, const char *evr) {
-      Pool *pool = xs->pool;
-      pool->solvables[xs->id].evr = pool_str2id(pool, evr, 1);
-    }
-    SWIGINTERN const char *XSolvable_evr_get(XSolvable *xs) {
-      Pool *pool = xs->pool;
-      return pool_id2str(pool, pool->solvables[xs->id].evr);
-    }
-  %}
-  Id evrid;
-  %{
-    SWIGINTERN void XSolvable_evrid_set(XSolvable *xs, Id evrid) {
-      xs->pool->solvables[xs->id].evr = evrid;
-    }
-    SWIGINTERN Id XSolvable_evrid_get(XSolvable *xs) {
-      return xs->pool->solvables[xs->id].evr;
-    }
-  %}
-  const char *arch;
-  %{
-    SWIGINTERN void XSolvable_arch_set(XSolvable *xs, const char *arch) {
-      Pool *pool = xs->pool;
-      pool->solvables[xs->id].arch = pool_str2id(pool, arch, 1);
-    }
-    SWIGINTERN const char *XSolvable_arch_get(XSolvable *xs) {
-      Pool *pool = xs->pool;
-      return pool_id2str(pool, pool->solvables[xs->id].arch);
-    }
-  %}
-  Id archid;
-  %{
-    SWIGINTERN void XSolvable_archid_set(XSolvable *xs, Id archid) {
-      xs->pool->solvables[xs->id].arch = archid;
-    }
-    SWIGINTERN Id XSolvable_archid_get(XSolvable *xs) {
-      return xs->pool->solvables[xs->id].arch;
-    }
-  %}
-  const char *vendor;
-  %{
-    SWIGINTERN void XSolvable_vendor_set(XSolvable *xs, const char *vendor) {
-      Pool *pool = xs->pool;
-      pool->solvables[xs->id].vendor = pool_str2id(pool, vendor, 1);
-    }
-    SWIGINTERN const char *XSolvable_vendor_get(XSolvable *xs) {
-      Pool *pool = xs->pool;
-      return pool_id2str(pool, pool->solvables[xs->id].vendor);
-    }
-  %}
-  Id vendorid;
-  %{
-    SWIGINTERN void XSolvable_vendorid_set(XSolvable *xs, Id vendorid) {
-      xs->pool->solvables[xs->id].vendor = vendorid;
-    }
-    SWIGINTERN Id XSolvable_vendorid_get(XSolvable *xs) {
-      return xs->pool->solvables[xs->id].vendor;
-    }
-  %}
-  Repo * const repo;
-  %{
-    SWIGINTERN Repo *XSolvable_repo_get(XSolvable *xs) {
-      return xs->pool->solvables[xs->id].repo;
-    }
-  %}
-
-  /* old interface, please use the generic add_deparray instead */
-  void add_provides(DepId id, Id marker = -1) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    marker = solv_depmarker(SOLVABLE_PROVIDES, marker);
-    s->provides = repo_addid_dep(s->repo, s->provides, id, marker);
-  }
-  void add_obsoletes(DepId id) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    s->obsoletes = repo_addid_dep(s->repo, s->obsoletes, id, 0);
-  }
-  void add_conflicts(DepId id) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
-  }
-  void add_requires(DepId id, Id marker = -1) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    marker = solv_depmarker(SOLVABLE_REQUIRES, marker);
-    s->requires = repo_addid_dep(s->repo, s->requires, id, marker);
-  }
-  void add_recommends(DepId id) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    s->recommends = repo_addid_dep(s->repo, s->recommends, id, 0);
-  }
-  void add_suggests(DepId id) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    s->suggests = repo_addid_dep(s->repo, s->suggests, id, 0);
-  }
-  void add_supplements(DepId id) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    s->supplements = repo_addid_dep(s->repo, s->supplements, id, 0);
-  }
-  void add_enhances(DepId id) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    s->enhances = repo_addid_dep(s->repo, s->enhances, id, 0);
-  }
-
-  void unset(Id keyname) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    repo_unset(s->repo, $self->id, keyname);
-  }
-
-  void add_deparray(Id keyname, DepId id, Id marker = -1) {
-    Solvable *s = $self->pool->solvables + $self->id;
-    solvable_add_deparray(s, keyname, id, marker);
-  }
-
-  %newobject Selection;
-  Selection *Selection(int setflags=0) {
-    Selection *sel = new_Selection($self->pool);
-    queue_push2(&sel->q, SOLVER_SOLVABLE | setflags, $self->id);
-    return sel;
-  }
-
-#ifdef SWIGRUBY
-  %rename("identical?") identical;
-#endif
-  bool identical(XSolvable *s2) {
-    return solvable_identical($self->pool->solvables + $self->id, s2->pool->solvables + s2->id);
-  }
-  int evrcmp(XSolvable *s2) {
-    return pool_evrcmp($self->pool, $self->pool->solvables[$self->id].evr, s2->pool->solvables[s2->id].evr, EVRCMP_COMPARE);
-  }
-
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(XSolvable *s) {
-    return $self->pool == s->pool && $self->id == s->id;
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(XSolvable *s) {
-    return !XSolvable___eq__($self, s);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  const char *__str__() {
-    return pool_solvid2str($self->pool, $self->id);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  %newobject __repr__;
-  const char *__repr__() {
-    char buf[20];
-    sprintf(buf, "<Solvable #%d ", $self->id);
-    return solv_dupjoin(buf, pool_solvid2str($self->pool, $self->id), ">");
-  }
-}
-
-%extend Problem {
-  Problem(Solver *solv, Id id) {
-    Problem *p;
-    p = solv_calloc(1, sizeof(*p));
-    p->solv = solv;
-    p->id = id;
-    return p;
-  }
-  %newobject findproblemrule;
-  XRule *findproblemrule() {
-    Id r = solver_findproblemrule($self->solv, $self->id);
-    return new_XRule($self->solv, r);
-  }
-  %newobject findallproblemrules;
-  %typemap(out) Queue findallproblemrules Queue2Array(XRule *, 1, new_XRule(arg1->solv, id));
-  Queue findallproblemrules(int unfiltered=0) {
-    Solver *solv = $self->solv;
-    Id probr;
-    int i, j;
-    Queue q;
-    queue_init(&q);
-    solver_findallproblemrules(solv, $self->id, &q);
-    if (!unfiltered)
-      {
-        for (i = j = 0; i < q.count; i++)
-          {
-            SolverRuleinfo rclass;
-            probr = q.elements[i];
-            rclass = solver_ruleclass(solv, probr);
-            if (rclass == SOLVER_RULE_UPDATE || rclass == SOLVER_RULE_JOB)
-              continue;
-            q.elements[j++] = probr;
-          }
-        if (j)
-          queue_truncate(&q, j);
-      }
-    return q;
-  }
-  int solution_count() {
-    return solver_solution_count($self->solv, $self->id);
-  }
-  %typemap(out) Queue solutions Queue2Array(Solution *, 1, new_Solution(arg1, id));
-  %newobject solutions;
-  Queue solutions() {
-    Queue q;
-    int i, cnt;
-    queue_init(&q);
-    cnt = solver_solution_count($self->solv, $self->id);
-    for (i = 1; i <= cnt; i++)
-      queue_push(&q, i);
-    return q;
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  const char *__str__() {
-    return solver_problem2str($self->solv, $self->id);
-  }
-}
-
-%extend Solution {
-  Solution(Problem *p, Id id) {
-    Solution *s;
-    s = solv_calloc(1, sizeof(*s));
-    s->solv = p->solv;
-    s->problemid = p->id;
-    s->id = id;
-    return s;
-  }
-  int element_count() {
-    return solver_solutionelement_count($self->solv, $self->problemid, $self->id);
-  }
-
-  %typemap(out) Queue elements Queue2Array(Solutionelement *, 4, new_Solutionelement(arg1->solv, arg1->problemid, arg1->id, id, idp[1], idp[2], idp[3]));
-  %newobject elements;
-  Queue elements(bool expandreplaces=0) {
-    Queue q;
-    int i, cnt;
-    queue_init(&q);
-    cnt = solver_solutionelement_count($self->solv, $self->problemid, $self->id);
-    for (i = 1; i <= cnt; i++)
-      {
-        Id p, rp, type;
-        solver_next_solutionelement($self->solv, $self->problemid, $self->id, i - 1, &p, &rp);
-        if (p > 0) {
-          type = rp ? SOLVER_SOLUTION_REPLACE : SOLVER_SOLUTION_ERASE;
-        } else {
-          type = p;
-          p = rp;
-          rp = 0;
-        }
-        if (type == SOLVER_SOLUTION_REPLACE && expandreplaces) {
-          int illegal = policy_is_illegal(self->solv, self->solv->pool->solvables + p, self->solv->pool->solvables + rp, 0);
-          if (illegal) {
-            if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_DOWNGRADE);
-              queue_push2(&q, p, rp);
-            }
-            if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_ARCHCHANGE);
-              queue_push2(&q, p, rp);
-            }
-            if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_VENDORCHANGE);
-              queue_push2(&q, p, rp);
-            }
-            if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_NAMECHANGE);
-              queue_push2(&q, p, rp);
-            }
-            continue;
-          }
-        }
-        queue_push2(&q, i, type);
-        queue_push2(&q, p, rp);
-      }
-    return q;
-  }
-}
-
-%extend Solutionelement {
-  Solutionelement(Solver *solv, Id problemid, Id solutionid, Id id, Id type, Id p, Id rp) {
-    Solutionelement *e;
-    e = solv_calloc(1, sizeof(*e));
-    e->solv = solv;
-    e->problemid = problemid;
-    e->solutionid = id;
-    e->id = id;
-    e->type = type;
-    e->p = p;
-    e->rp = rp;
-    return e;
-  }
-  const char *str() {
-    Id p = $self->type;
-    Id rp = $self->p;
-    int illegal = 0;
-    if (p == SOLVER_SOLUTION_ERASE)
-      {
-        p = rp;
-        rp = 0;
-      }
-    else if (p == SOLVER_SOLUTION_REPLACE)
-      {
-        p = rp;
-        rp = $self->rp;
-      }
-    else if (p == SOLVER_SOLUTION_REPLACE_DOWNGRADE)
-      illegal = POLICY_ILLEGAL_DOWNGRADE;
-    else if (p == SOLVER_SOLUTION_REPLACE_ARCHCHANGE)
-      illegal = POLICY_ILLEGAL_ARCHCHANGE;
-    else if (p == SOLVER_SOLUTION_REPLACE_VENDORCHANGE)
-      illegal = POLICY_ILLEGAL_VENDORCHANGE;
-    else if (p == SOLVER_SOLUTION_REPLACE_NAMECHANGE)
-      illegal = POLICY_ILLEGAL_NAMECHANGE;
-    if (illegal)
-      return pool_tmpjoin($self->solv->pool, "allow ", policy_illegal2str($self->solv, illegal, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp), 0);
-    return solver_solutionelement2str($self->solv, p, rp);
-  }
-  %typemap(out) Queue replaceelements Queue2Array(Solutionelement *, 1, new_Solutionelement(arg1->solv, arg1->problemid, arg1->solutionid, arg1->id, id, arg1->p, arg1->rp));
-  %newobject replaceelements;
-  Queue replaceelements() {
-    Queue q;
-    int illegal;
-
-    queue_init(&q);
-    if ($self->type != SOLVER_SOLUTION_REPLACE || $self->p <= 0 || $self->rp <= 0)
-      illegal = 0;
-    else
-      illegal = policy_is_illegal($self->solv, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp, 0);
-    if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0)
-      queue_push(&q, SOLVER_SOLUTION_REPLACE_DOWNGRADE);
-    if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0)
-      queue_push(&q, SOLVER_SOLUTION_REPLACE_ARCHCHANGE);
-    if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0)
-      queue_push(&q, SOLVER_SOLUTION_REPLACE_VENDORCHANGE);
-    if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0)
-      queue_push(&q, SOLVER_SOLUTION_REPLACE_NAMECHANGE);
-    if (!q.count)
-      queue_push(&q, $self->type);
-    return q;
-  }
-  int illegalreplace() {
-    if ($self->type != SOLVER_SOLUTION_REPLACE || $self->p <= 0 || $self->rp <= 0)
-      return 0;
-    return policy_is_illegal($self->solv, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp, 0);
-  }
-  %newobject solvable;
-  XSolvable * const solvable;
-  %newobject replacement;
-  XSolvable * const replacement;
-  int const jobidx;
-  %{
-    SWIGINTERN XSolvable *Solutionelement_solvable_get(Solutionelement *e) {
-      return new_XSolvable(e->solv->pool, e->p);
-    }
-    SWIGINTERN XSolvable *Solutionelement_replacement_get(Solutionelement *e) {
-      return new_XSolvable(e->solv->pool, e->rp);
-    }
-    SWIGINTERN int Solutionelement_jobidx_get(Solutionelement *e) {
-      if (e->type != SOLVER_SOLUTION_JOB && e->type != SOLVER_SOLUTION_POOLJOB)
-        return -1;
-      return (e->p - 1) / 2;
-    }
-  %}
-  %newobject Job;
-  Job *Job() {
-    Id extraflags = solver_solutionelement_extrajobflags($self->solv, $self->problemid, $self->solutionid);
-    if ($self->type == SOLVER_SOLUTION_JOB || $self->type == SOLVER_SOLUTION_POOLJOB)
-      return new_Job($self->solv->pool, SOLVER_NOOP, 0);
-    if ($self->type == SOLVER_SOLUTION_INFARCH || $self->type == SOLVER_SOLUTION_DISTUPGRADE || $self->type == SOLVER_SOLUTION_BEST)
-      return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->p);
-    if ($self->type == SOLVER_SOLUTION_REPLACE || $self->type == SOLVER_SOLUTION_REPLACE_DOWNGRADE || $self->type == SOLVER_SOLUTION_REPLACE_ARCHCHANGE || $self->type == SOLVER_SOLUTION_REPLACE_VENDORCHANGE || $self->type == SOLVER_SOLUTION_REPLACE_NAMECHANGE)
-      return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->rp);
-    if ($self->type == SOLVER_SOLUTION_ERASE)
-      return new_Job($self->solv->pool, SOLVER_ERASE|SOLVER_SOLVABLE|extraflags, $self->p);
-    return 0;
-  }
-}
-
-%extend Solver {
-  static const int SOLVER_RULE_UNKNOWN = SOLVER_RULE_UNKNOWN;
-  static const int SOLVER_RULE_PKG = SOLVER_RULE_PKG;
-  static const int SOLVER_RULE_PKG_NOT_INSTALLABLE = SOLVER_RULE_PKG_NOT_INSTALLABLE;
-  static const int SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP = SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP;
-  static const int SOLVER_RULE_PKG_REQUIRES = SOLVER_RULE_PKG_REQUIRES;
-  static const int SOLVER_RULE_PKG_SELF_CONFLICT = SOLVER_RULE_PKG_SELF_CONFLICT;
-  static const int SOLVER_RULE_PKG_CONFLICTS = SOLVER_RULE_PKG_CONFLICTS;
-  static const int SOLVER_RULE_PKG_SAME_NAME = SOLVER_RULE_PKG_SAME_NAME;
-  static const int SOLVER_RULE_PKG_OBSOLETES = SOLVER_RULE_PKG_OBSOLETES;
-  static const int SOLVER_RULE_PKG_IMPLICIT_OBSOLETES = SOLVER_RULE_PKG_IMPLICIT_OBSOLETES;
-  static const int SOLVER_RULE_PKG_INSTALLED_OBSOLETES = SOLVER_RULE_PKG_INSTALLED_OBSOLETES;
-  static const int SOLVER_RULE_UPDATE = SOLVER_RULE_UPDATE;
-  static const int SOLVER_RULE_FEATURE = SOLVER_RULE_FEATURE;
-  static const int SOLVER_RULE_JOB = SOLVER_RULE_JOB;
-  static const int SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP = SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
-  static const int SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM = SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
-  static const int SOLVER_RULE_JOB_UNKNOWN_PACKAGE = SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
-  static const int SOLVER_RULE_JOB_UNSUPPORTED = SOLVER_RULE_JOB_UNSUPPORTED;
-  static const int SOLVER_RULE_DISTUPGRADE = SOLVER_RULE_DISTUPGRADE;
-  static const int SOLVER_RULE_INFARCH = SOLVER_RULE_INFARCH;
-  static const int SOLVER_RULE_CHOICE = SOLVER_RULE_CHOICE;
-  static const int SOLVER_RULE_LEARNT = SOLVER_RULE_LEARNT;
-
-  static const int SOLVER_SOLUTION_JOB = SOLVER_SOLUTION_JOB;
-  static const int SOLVER_SOLUTION_POOLJOB = SOLVER_SOLUTION_POOLJOB;
-  static const int SOLVER_SOLUTION_INFARCH = SOLVER_SOLUTION_INFARCH;
-  static const int SOLVER_SOLUTION_DISTUPGRADE = SOLVER_SOLUTION_DISTUPGRADE;
-  static const int SOLVER_SOLUTION_BEST = SOLVER_SOLUTION_BEST;
-  static const int SOLVER_SOLUTION_ERASE = SOLVER_SOLUTION_ERASE;
-  static const int SOLVER_SOLUTION_REPLACE = SOLVER_SOLUTION_REPLACE;
-  static const int SOLVER_SOLUTION_REPLACE_DOWNGRADE = SOLVER_SOLUTION_REPLACE_DOWNGRADE;
-  static const int SOLVER_SOLUTION_REPLACE_ARCHCHANGE = SOLVER_SOLUTION_REPLACE_ARCHCHANGE;
-  static const int SOLVER_SOLUTION_REPLACE_VENDORCHANGE = SOLVER_SOLUTION_REPLACE_VENDORCHANGE;
-  static const int SOLVER_SOLUTION_REPLACE_NAMECHANGE = SOLVER_SOLUTION_REPLACE_NAMECHANGE;
-
-  static const int POLICY_ILLEGAL_DOWNGRADE = POLICY_ILLEGAL_DOWNGRADE;
-  static const int POLICY_ILLEGAL_ARCHCHANGE = POLICY_ILLEGAL_ARCHCHANGE;
-  static const int POLICY_ILLEGAL_VENDORCHANGE = POLICY_ILLEGAL_VENDORCHANGE;
-  static const int POLICY_ILLEGAL_NAMECHANGE = POLICY_ILLEGAL_NAMECHANGE;
-
-  static const int SOLVER_FLAG_ALLOW_DOWNGRADE = SOLVER_FLAG_ALLOW_DOWNGRADE;
-  static const int SOLVER_FLAG_ALLOW_ARCHCHANGE = SOLVER_FLAG_ALLOW_ARCHCHANGE;
-  static const int SOLVER_FLAG_ALLOW_VENDORCHANGE = SOLVER_FLAG_ALLOW_VENDORCHANGE;
-  static const int SOLVER_FLAG_ALLOW_NAMECHANGE = SOLVER_FLAG_ALLOW_NAMECHANGE;
-  static const int SOLVER_FLAG_ALLOW_UNINSTALL = SOLVER_FLAG_ALLOW_UNINSTALL;
-  static const int SOLVER_FLAG_NO_UPDATEPROVIDE = SOLVER_FLAG_NO_UPDATEPROVIDE;
-  static const int SOLVER_FLAG_SPLITPROVIDES = SOLVER_FLAG_SPLITPROVIDES;
-  static const int SOLVER_FLAG_IGNORE_RECOMMENDED = SOLVER_FLAG_IGNORE_RECOMMENDED;
-  static const int SOLVER_FLAG_ADD_ALREADY_RECOMMENDED = SOLVER_FLAG_ADD_ALREADY_RECOMMENDED;
-  static const int SOLVER_FLAG_NO_INFARCHCHECK = SOLVER_FLAG_NO_INFARCHCHECK;
-  static const int SOLVER_FLAG_BEST_OBEY_POLICY = SOLVER_FLAG_BEST_OBEY_POLICY;
-  static const int SOLVER_FLAG_NO_AUTOTARGET = SOLVER_FLAG_NO_AUTOTARGET;
-  static const int SOLVER_FLAG_DUP_ALLOW_DOWNGRADE = SOLVER_FLAG_DUP_ALLOW_DOWNGRADE;
-  static const int SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE = SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE;
-  static const int SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE = SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE;
-  static const int SOLVER_FLAG_DUP_ALLOW_NAMECHANGE = SOLVER_FLAG_DUP_ALLOW_NAMECHANGE;
-  static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS;
-  static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS;
-  static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED;
-  static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES;
-  static const int SOLVER_FLAG_NEED_UPDATEPROVIDE = SOLVER_FLAG_NEED_UPDATEPROVIDE;
-
-  static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
-  static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
-  static const int SOLVER_REASON_KEEP_INSTALLED = SOLVER_REASON_KEEP_INSTALLED;
-  static const int SOLVER_REASON_RESOLVE_JOB = SOLVER_REASON_RESOLVE_JOB;
-  static const int SOLVER_REASON_UPDATE_INSTALLED = SOLVER_REASON_UPDATE_INSTALLED;
-  static const int SOLVER_REASON_CLEANDEPS_ERASE = SOLVER_REASON_CLEANDEPS_ERASE;
-  static const int SOLVER_REASON_RESOLVE = SOLVER_REASON_RESOLVE;
-  static const int SOLVER_REASON_WEAKDEP = SOLVER_REASON_WEAKDEP;
-  static const int SOLVER_REASON_RESOLVE_ORPHAN = SOLVER_REASON_RESOLVE_ORPHAN;
-  static const int SOLVER_REASON_RECOMMENDED = SOLVER_REASON_RECOMMENDED;
-  static const int SOLVER_REASON_SUPPLEMENTED = SOLVER_REASON_SUPPLEMENTED;
-
-  /* legacy */
-  static const int SOLVER_RULE_RPM = SOLVER_RULE_RPM;
-
-  ~Solver() {
-    solver_free($self);
-  }
-
-  int set_flag(int flag, int value) {
-    return solver_set_flag($self, flag, value);
-  }
-  int get_flag(int flag) {
-    return solver_get_flag($self, flag);
-  }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def solve(self, jobs):
-      j = []
-      for job in jobs: j += [job.how, job.what]
-      return self.solve_helper(j)
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Solver::solve {
-      my ($self, $jobs) = @_;
-      my @j = map {($_->{'how'}, $_->{'what'})} @$jobs;
-      return $self->solve_helper(\@j);
-    }
-  }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Solver\n"
-    "  def solve(jobs)\n"
-    "    jl = []\n"
-    "    jobs.each do |j| ; jl << j.how << j.what ; end\n"
-    "    solve_helper(jl)\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
-  %typemap(out) Queue solve_helper Queue2Array(Problem *, 1, new_Problem(arg1, id));
-  %newobject solve_helper;
-  Queue solve_helper(Queue jobs) {
-    Queue q;
-    int i, cnt;
-    queue_init(&q);
-    solver_solve($self, &jobs);
-    cnt = solver_problem_count($self);
-    for (i = 1; i <= cnt; i++)
-      queue_push(&q, i);
-    return q;
-  }
-#if defined(SWIGTCL)
-  %typemap(out) Queue solve Queue2Array(Problem *, 1, new_Problem(arg1, id));
-  %newobject solve;
-  Queue solve(Queue solvejobs) {
-    Queue q;
-    int i, cnt;
-    queue_init(&q);
-    solver_solve($self, &solvejobs);
-    cnt = solver_problem_count($self);
-    for (i = 1; i <= cnt; i++)
-      queue_push(&q, i);
-    return q;
-  }
-#endif
-
-  %newobject transaction;
-  Transaction *transaction() {
-    return solver_create_transaction($self);
-  }
-
-  int describe_decision(XSolvable *s, XRule **OUTPUT) {
-    int ruleid;
-    int reason = solver_describe_decision($self, s->id, &ruleid);
-    *OUTPUT = new_XRule($self, ruleid);
-    return reason;
-  }
-
-  %newobject describe_weakdep_decision_raw;
-  Queue describe_weakdep_decision_raw(XSolvable *s) {
-    Queue q;
-    queue_init(&q);
-    solver_describe_weakdep_decision($self, s->id, &q);
-    return q;
-  }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def describe_weakdep_decision(self, s):
-      d = iter(self.describe_weakdep_decision_raw(s))
-      return [ (t, XSolvable(self.pool, sid), Dep(self.pool, id)) for t, sid, id in zip(d, d, d) ]
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Solver::describe_weakdep_decision {
-      my ($self, $s) = @_;
-      my $pool = $self->{'pool'};
-      my @res;
-      my @d = $self->describe_weakdep_decision_raw($s);
-      push @res, [ splice(@d, 0, 3) ] while @d;
-      return map { [ $_->[0], solv::XSolvable->new($pool, $_->[1]), solv::Dep->new($pool, $_->[2]) ] } @res;
-    }
-  }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Solver\n"
-    "  def describe_weakdep_decision(s)\n"
-    "    self.describe_weakdep_decision_raw(s).each_slice(3).map { |t, sid, id| [ t, Solv::XSolvable.new(self.pool, sid), Solv::Dep.new(self.pool, id)] }\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
-
-  int alternatives_count() {
-    return solver_alternatives_count($self);
-  }
-
-  %newobject alternative;
-  Alternative *alternative(Id aid) {
-    Alternative *a = solv_calloc(1, sizeof(*a));
-    a->solv = $self;
-    queue_init(&a->choices);
-    a->type = solver_get_alternative($self, aid, &a->dep_id, &a->from_id, &a->chosen_id, &a->choices, &a->level);
-    if (!a->type) {
-      queue_free(&a->choices);
-      solv_free(a);
-      return 0;
-    }
-    if (a->type == SOLVER_ALTERNATIVE_TYPE_RULE) {
-      a->rid = a->dep_id;
-      a->dep_id = 0;
-    }
-    return a;
-  }
-
-  %typemap(out) Queue all_alternatives Queue2Array(Alternative *, 1, Solver_alternative(arg1, id));
-  %newobject all_alternatives;
-  Queue all_alternatives() {
-    Queue q;
-    int i, cnt;
-    queue_init(&q);
-    cnt = solver_alternatives_count($self);
-    for (i = 1; i <= cnt; i++)
-      queue_push(&q, i);
-    return q;
-  }
-
-  bool write_testcase(const char *dir) {
-    return testcase_write($self, dir, TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, 0, 0);
-  }
-}
-
-%extend Transaction {
-  static const int SOLVER_TRANSACTION_IGNORE = SOLVER_TRANSACTION_IGNORE;
-  static const int SOLVER_TRANSACTION_ERASE = SOLVER_TRANSACTION_ERASE;
-  static const int SOLVER_TRANSACTION_REINSTALLED = SOLVER_TRANSACTION_REINSTALLED;
-  static const int SOLVER_TRANSACTION_DOWNGRADED = SOLVER_TRANSACTION_DOWNGRADED;
-  static const int SOLVER_TRANSACTION_CHANGED = SOLVER_TRANSACTION_CHANGED;
-  static const int SOLVER_TRANSACTION_UPGRADED = SOLVER_TRANSACTION_UPGRADED;
-  static const int SOLVER_TRANSACTION_OBSOLETED = SOLVER_TRANSACTION_OBSOLETED;
-  static const int SOLVER_TRANSACTION_INSTALL = SOLVER_TRANSACTION_INSTALL;
-  static const int SOLVER_TRANSACTION_REINSTALL = SOLVER_TRANSACTION_REINSTALL;
-  static const int SOLVER_TRANSACTION_DOWNGRADE = SOLVER_TRANSACTION_DOWNGRADE;
-  static const int SOLVER_TRANSACTION_CHANGE = SOLVER_TRANSACTION_CHANGE;
-  static const int SOLVER_TRANSACTION_UPGRADE = SOLVER_TRANSACTION_UPGRADE;
-  static const int SOLVER_TRANSACTION_OBSOLETES = SOLVER_TRANSACTION_OBSOLETES;
-  static const int SOLVER_TRANSACTION_MULTIINSTALL = SOLVER_TRANSACTION_MULTIINSTALL;
-  static const int SOLVER_TRANSACTION_MULTIREINSTALL = SOLVER_TRANSACTION_MULTIREINSTALL;
-  static const int SOLVER_TRANSACTION_MAXTYPE = SOLVER_TRANSACTION_MAXTYPE;
-  static const int SOLVER_TRANSACTION_SHOW_ACTIVE = SOLVER_TRANSACTION_SHOW_ACTIVE;
-  static const int SOLVER_TRANSACTION_SHOW_ALL = SOLVER_TRANSACTION_SHOW_ALL;
-  static const int SOLVER_TRANSACTION_SHOW_OBSOLETES = SOLVER_TRANSACTION_SHOW_OBSOLETES;
-  static const int SOLVER_TRANSACTION_SHOW_MULTIINSTALL = SOLVER_TRANSACTION_SHOW_MULTIINSTALL;
-  static const int SOLVER_TRANSACTION_CHANGE_IS_REINSTALL = SOLVER_TRANSACTION_CHANGE_IS_REINSTALL;
-  static const int SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE = SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
-  static const int SOLVER_TRANSACTION_MERGE_VENDORCHANGES = SOLVER_TRANSACTION_MERGE_VENDORCHANGES;
-  static const int SOLVER_TRANSACTION_MERGE_ARCHCHANGES = SOLVER_TRANSACTION_MERGE_ARCHCHANGES;
-  static const int SOLVER_TRANSACTION_RPM_ONLY = SOLVER_TRANSACTION_RPM_ONLY;
-  static const int SOLVER_TRANSACTION_ARCHCHANGE = SOLVER_TRANSACTION_ARCHCHANGE;
-  static const int SOLVER_TRANSACTION_VENDORCHANGE = SOLVER_TRANSACTION_VENDORCHANGE;
-  static const int SOLVER_TRANSACTION_KEEP_ORDERDATA = SOLVER_TRANSACTION_KEEP_ORDERDATA;
-  ~Transaction() {
-    transaction_free($self);
-  }
-#ifdef SWIGRUBY
-  %rename("isempty?") isempty;
-#endif
-  bool isempty() {
-    return $self->steps.count == 0;
-  }
-
-  %newobject othersolvable;
-  XSolvable *othersolvable(XSolvable *s) {
-    Id op = transaction_obs_pkg($self, s->id);
-    return new_XSolvable($self->pool, op);
-  }
-
-  %typemap(out) Queue allothersolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject allothersolvables;
-  Queue allothersolvables(XSolvable *s) {
-    Queue q;
-    queue_init(&q);
-    transaction_all_obs_pkgs($self, s->id, &q);
-    return q;
-  }
-
-  %typemap(out) Queue classify Queue2Array(TransactionClass *, 4, new_TransactionClass(arg1, arg2, id, idp[1], idp[2], idp[3]));
-  %newobject classify;
-  Queue classify(int mode = 0) {
-    Queue q;
-    queue_init(&q);
-    transaction_classify($self, mode, &q);
-    return q;
-  }
-
-  /* deprecated, use newsolvables instead */
-  %typemap(out) Queue newpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject newpackages;
-  Queue newpackages() {
-    Queue q;
-    int cut;
-    queue_init(&q);
-    cut = transaction_installedresult(self, &q);
-    queue_truncate(&q, cut);
-    return q;
-  }
-
-  /* deprecated, use keptsolvables instead */
-  %typemap(out) Queue keptpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject keptpackages;
-  Queue keptpackages() {
-    Queue q;
-    int cut;
-    queue_init(&q);
-    cut = transaction_installedresult(self, &q);
-    if (cut)
-      queue_deleten(&q, 0, cut);
-    return q;
-  }
-
-  %typemap(out) Queue newsolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject newsolvables;
-  Queue newsolvables() {
-    Queue q;
-    int cut;
-    queue_init(&q);
-    cut = transaction_installedresult(self, &q);
-    queue_truncate(&q, cut);
-    return q;
-  }
-
-  %typemap(out) Queue keptsolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject keptsolvables;
-  Queue keptsolvables() {
-    Queue q;
-    int cut;
-    queue_init(&q);
-    cut = transaction_installedresult(self, &q);
-    if (cut)
-      queue_deleten(&q, 0, cut);
-    return q;
-  }
-
-  %typemap(out) Queue steps Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
-  %newobject steps;
-  Queue steps() {
-    Queue q;
-    queue_init_clone(&q, &$self->steps);
-    return q;
-  }
-
-  int steptype(XSolvable *s, int mode) {
-    return transaction_type($self, s->id, mode);
-  }
-  int calc_installsizechange() {
-    return transaction_calc_installsizechange($self);
-  }
-  void order(int flags=0) {
-    transaction_order($self, flags);
-  }
-}
-
-%extend TransactionClass {
-  TransactionClass(Transaction *trans, int mode, Id type, int count, Id fromid, Id toid) {
-    TransactionClass *cl = solv_calloc(1, sizeof(*cl));
-    cl->transaction = trans;
-    cl->mode = mode;
-    cl->type = type;
-    cl->count = count;
-    cl->fromid = fromid;
-    cl->toid = toid;
-    return cl;
-  }
-  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->transaction->pool, id));
-  %newobject solvables;
-  Queue solvables() {
-    Queue q;
-    queue_init(&q);
-    transaction_classify_pkgs($self->transaction, $self->mode, $self->type, $self->fromid, $self->toid, &q);
-    return q;
-  }
-  const char * const fromstr;
-  const char * const tostr;
-  %{
-    SWIGINTERN const char *TransactionClass_fromstr_get(TransactionClass *cl) {
-      return pool_id2str(cl->transaction->pool, cl->fromid);
-    }
-    SWIGINTERN const char *TransactionClass_tostr_get(TransactionClass *cl) {
-      return pool_id2str(cl->transaction->pool, cl->toid);
-    }
-  %}
-}
-
-%extend XRule {
-  XRule(Solver *solv, Id id) {
-    if (!id)
-      return 0;
-    XRule *xr = solv_calloc(1, sizeof(*xr));
-    xr->solv = solv;
-    xr->id = id;
-    return xr;
-  }
-  int const type;
-  %{
-    SWIGINTERN int XRule_type_get(XRule *xr) {
-      return solver_ruleclass(xr->solv, xr->id);
-    }
-  %}
-  %newobject info;
-  Ruleinfo *info() {
-    Id type, source, target, dep;
-    type = solver_ruleinfo($self->solv, $self->id, &source, &target, &dep);
-    return new_Ruleinfo($self, type, source, target, dep);
-  }
-  %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1, id, idp[1], idp[2], idp[3]));
-  %newobject allinfos;
-  Queue allinfos() {
-    Queue q;
-    queue_init(&q);
-    solver_allruleinfos($self->solv, $self->id, &q);
-    return q;
-  }
-
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(XRule *xr) {
-    return $self->solv == xr->solv && $self->id == xr->id;
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(XRule *xr) {
-    return !XRule___eq__($self, xr);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  %newobject __repr__;
-  const char *__repr__() {
-    char buf[20];
-    sprintf(buf, "<Rule #%d>", $self->id);
-    return solv_strdup(buf);
-  }
-}
-
-%extend Ruleinfo {
-  Ruleinfo(XRule *r, Id type, Id source, Id target, Id dep_id) {
-    Ruleinfo *ri = solv_calloc(1, sizeof(*ri));
-    ri->solv = r->solv;
-    ri->rid = r->id;
-    ri->type = type;
-    ri->source = source;
-    ri->target = target;
-    ri->dep_id = dep_id;
-    return ri;
-  }
-  %newobject solvable;
-  XSolvable * const solvable;
-  %newobject othersolvable;
-  XSolvable * const othersolvable;
-  %newobject dep;
-  Dep * const dep;
-  %{
-    SWIGINTERN XSolvable *Ruleinfo_solvable_get(Ruleinfo *ri) {
-      return new_XSolvable(ri->solv->pool, ri->source);
-    }
-    SWIGINTERN XSolvable *Ruleinfo_othersolvable_get(Ruleinfo *ri) {
-      return new_XSolvable(ri->solv->pool, ri->target);
-    }
-    SWIGINTERN Dep *Ruleinfo_dep_get(Ruleinfo *ri) {
-      return new_Dep(ri->solv->pool, ri->dep_id);
-    }
-  %}
-  const char *problemstr() {
-    return solver_problemruleinfo2str($self->solv, $self->type, $self->source, $self->target, $self->dep_id);
-  }
-}
-
-%extend XRepodata {
-  XRepodata(Repo *repo, Id id) {
-    XRepodata *xr = solv_calloc(1, sizeof(*xr));
-    xr->repo = repo;
-    xr->id = id;
-    return xr;
-  }
-  Id new_handle() {
-    return repodata_new_handle(repo_id2repodata($self->repo, $self->id));
-  }
-  void set_id(Id solvid, Id keyname, DepId id) {
-    repodata_set_id(repo_id2repodata($self->repo, $self->id), solvid, keyname, id);
-  }
-  void set_str(Id solvid, Id keyname, const char *str) {
-    repodata_set_str(repo_id2repodata($self->repo, $self->id), solvid, keyname, str);
-  }
-  void set_poolstr(Id solvid, Id keyname, const char *str) {
-    repodata_set_poolstr(repo_id2repodata($self->repo, $self->id), solvid, keyname, str);
-  }
-  void add_idarray(Id solvid, Id keyname, DepId id) {
-    repodata_add_idarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, id);
-  }
-  void add_flexarray(Id solvid, Id keyname, Id handle) {
-    repodata_add_flexarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, handle);
-  }
-  void set_checksum(Id solvid, Id keyname, Chksum *chksum) {
-    const unsigned char *buf = solv_chksum_get(chksum, 0);
-    if (buf)
-      repodata_set_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, solv_chksum_get_type(chksum), buf);
-  }
-  const char *lookup_str(Id solvid, Id keyname) {
-    return repodata_lookup_str(repo_id2repodata($self->repo, $self->id), solvid, keyname);
-  }
-  Queue lookup_idarray(Id solvid, Id keyname) {
-    Queue r;
-    queue_init(&r);
-    repodata_lookup_idarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, &r);
-    return r;
-  }
-  %newobject lookup_checksum;
-  Chksum *lookup_checksum(Id solvid, Id keyname) {
-    Id type = 0;
-    const unsigned char *b = repodata_lookup_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, &type);
-    return solv_chksum_create_from_bin(type, b);
-  }
-  void internalize() {
-    repodata_internalize(repo_id2repodata($self->repo, $self->id));
-  }
-  void create_stubs() {
-    Repodata *data = repo_id2repodata($self->repo, $self->id);
-    data = repodata_create_stubs(data);
-    $self->id = data->repodataid;
-  }
-  bool write(FILE *fp) {
-    return repodata_write(repo_id2repodata($self->repo, $self->id), fp) == 0;
-  }
-  bool add_solv(FILE *fp, int flags = 0) {
-    Repodata *data = repo_id2repodata($self->repo, $self->id);
-    int r, oldstate = data->state;
-    data->state = REPODATA_LOADING;
-    r = repo_add_solv(data->repo, fp, flags | REPO_USE_LOADING);
-    if (r || data->state == REPODATA_LOADING)
-      data->state = oldstate;
-    return r;
-  }
-  void extend_to_repo() {
-    Repodata *data = repo_id2repodata($self->repo, $self->id);
-    repodata_extend_block(data, data->repo->start, data->repo->end - data->repo->start);
-  }
-#if defined(SWIGTCL)
-  %rename("==") __eq__;
-#endif
-  bool __eq__(XRepodata *xr) {
-    return $self->repo == xr->repo && $self->id == xr->id;
-  }
-#if defined(SWIGTCL)
-  %rename("!=") __ne__;
-#endif
-  bool __ne__(XRepodata *xr) {
-    return !XRepodata___eq__($self, xr);
-  }
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("repr") __repr__;
-#endif
-  %newobject __repr__;
-  const char *__repr__() {
-    char buf[20];
-    sprintf(buf, "<Repodata #%d>", $self->id);
-    return solv_strdup(buf);
-  }
-}
-
-#ifdef ENABLE_PUBKEY
-%extend Solvsig {
-  Solvsig(FILE *fp) {
-    return solvsig_create(fp);
-  }
-  ~Solvsig() {
-    solvsig_free($self);
-  }
-  %newobject Chksum;
-  Chksum *Chksum() {
-    return $self->htype ? (Chksum *)solv_chksum_create($self->htype) : 0;
-  }
-#ifdef ENABLE_PGPVRFY
-  %newobject verify;
-  XSolvable *verify(Repo *repo, Chksum *chksum) {
-    Id p = solvsig_verify($self, repo, chksum);
-    return new_XSolvable(repo->pool, p);
-  }
-#endif
-}
-#endif
-
-%extend Alternative {
-  static const int SOLVER_ALTERNATIVE_TYPE_RULE = SOLVER_ALTERNATIVE_TYPE_RULE;
-  static const int SOLVER_ALTERNATIVE_TYPE_RECOMMENDS = SOLVER_ALTERNATIVE_TYPE_RECOMMENDS;
-  static const int SOLVER_ALTERNATIVE_TYPE_SUGGESTS = SOLVER_ALTERNATIVE_TYPE_SUGGESTS;
-
-  ~Alternative() {
-    queue_free(&$self->choices);
-    solv_free($self);
-  }
-  %newobject chosen;
-  XSolvable * const chosen;
-  %newobject rule;
-  XRule * const rule;
-  %newobject depsolvable;
-  XSolvable * const depsolvable;
-  %newobject dep;
-  Dep * const dep;
-  %{
-    SWIGINTERN XSolvable *Alternative_chosen_get(Alternative *a) {
-      return new_XSolvable(a->solv->pool, a->chosen_id);
-    }
-    SWIGINTERN XRule *Alternative_rule_get(Alternative *a) {
-      return new_XRule(a->solv, a->rid);
-    }
-    SWIGINTERN XSolvable *Alternative_depsolvable_get(Alternative *a) {
-      return new_XSolvable(a->solv->pool, a->from_id);
-    }
-    SWIGINTERN Dep *Alternative_dep_get(Alternative *a) {
-      return new_Dep(a->solv->pool, a->dep_id);
-    }
-  %}
-
-  Queue choices_raw() {
-    Queue r;
-    queue_init_clone(&r, &$self->choices);
-    return r;
-  }
-
-  %typemap(out) Queue choices Queue2Array(XSolvable *, 1, new_XSolvable(arg1->solv->pool, id));
-  Queue choices() {
-    int i;
-    Queue r;
-    queue_init_clone(&r, &$self->choices);
-    for (i = 0; i < r.count; i++)
-      if (r.elements[i] < 0)
-        r.elements[i] = -r.elements[i];
-    return r;
-  }
-
-#if defined(SWIGPERL) || defined(SWIGTCL)
-  %rename("str") __str__;
-#endif
-  const char *__str__() {
-    return solver_alternative2str($self->solv, $self->type, $self->type == SOLVER_ALTERNATIVE_TYPE_RULE ? $self->rid : $self->dep_id, $self->from_id);
-  }
-}
-
-#if defined(SWIGTCL)
-%init %{
-  Tcl_Eval(interp,
-"proc solv::iter {varname iter body} {\n"\
-"  while 1 {\n"\
-"    set value [$iter __next__]\n"\
-"    if {$value eq \"NULL\"} { break }\n"\
-"    uplevel [list set $varname $value]\n"\
-"    set code [catch {uplevel $body} result]\n"\
-"    switch -exact -- $code {\n"\
-"      0 {}\n"\
-"      3 { return }\n"\
-"      4 {}\n"\
-"      default { return -code $code $result }\n"\
-"    }\n"\
-"  }\n"\
-"}\n"
-  );
-%}
-#endif
-
diff --git a/libsolv-0.6.15/bindings/tcl/CMakeLists.txt b/libsolv-0.6.15/bindings/tcl/CMakeLists.txt
deleted file mode 100644 (file)
index f78de9f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-FIND_PACKAGE (TCL)
-
-SET (SWIG_TCL_FLAGS -namespace -pkgversion ${VERSION})
-
-EXECUTE_PROCESS (
-    COMMAND echo "puts -nonewline [lindex [::tcl::tm::list] end]"
-    COMMAND ${TCL_TCLSH}
-    OUTPUT_VARIABLE TCL_INSTALL_DIR
-)
-
-MESSAGE (STATUS "Tclsh executable: ${TCL_TCLSH}")
-MESSAGE (STATUS "Tcl installation dir: ${TCL_INSTALL_DIR}")
-
-ADD_CUSTOM_COMMAND (
-    OUTPUT solv_tcl.c
-    COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -tcl ${SWIG_TCL_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_tcl.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
-    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
-)
-
-ADD_DEFINITIONS(-Wno-unused)
-INCLUDE_DIRECTORIES (${TCL_INCLUDE_PATH})
-
-ADD_LIBRARY (bindings_tcl SHARED solv_tcl.c)
-SET_TARGET_PROPERTIES (bindings_tcl PROPERTIES PREFIX "" OUTPUT_NAME "solv-${VERSION}" INSTALL_NAME_DIR "${TCL_INSTALL_DIR}")
-TARGET_LINK_LIBRARIES (bindings_tcl libsolvext libsolv ${TCL_LIBRARY} ${SYSTEM_LIBRARIES})
-INSTALL (TARGETS bindings_tcl LIBRARY DESTINATION ${TCL_INSTALL_DIR})
-
-ADD_CUSTOM_COMMAND (
-    OUTPUT solv.tm
-       COMMAND sed -e "s/__VERSION__/${VERSION}/" ${CMAKE_SOURCE_DIR}/bindings/tcl/solv.tm.in >${CMAKE_CURRENT_BINARY_DIR}/solv.tm
-    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/tcl/solv.tm.in
-    COMMENT "Creating Tcl module to load libsolv"
-)
-ADD_CUSTOM_TARGET (solv_tm ALL DEPENDS solv.tm)
-SET_SOURCE_FILES_PROPERTIES (solv.tm PROPERTIES GENERATED TRUE)
-
-INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.tm DESTINATION ${TCL_INSTALL_DIR} RENAME solv-${VERSION}.tm)
diff --git a/libsolv-0.6.15/bindings/tcl/solv.tm.in b/libsolv-0.6.15/bindings/tcl/solv.tm.in
deleted file mode 100644 (file)
index 3b94771..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-package require Tcl
-
-#package provide solv __VERSION__
-load [::file join [::file dirname [::info script]] "solv-__VERSION__[::info sharedlibextension]"]
diff --git a/libsolv-0.6.15/cmake/modules/FindCheck.cmake b/libsolv-0.6.15/cmake/modules/FindCheck.cmake
deleted file mode 100644 (file)
index 8ed3739..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-
-IF (CHECK_INCLUDE_DIR)
-  # Already in cache, be silent
-  SET(CHECK_FIND_QUIETLY TRUE)
-ENDIF (CHECK_INCLUDE_DIR)
-
-FIND_PATH(CHECK_INCLUDE_DIR NAMES check.h)
-
-# Look for the library.
-FIND_LIBRARY(CHECK_LIBRARY NAMES check)
-
-IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4)
-  # handle the QUIETLY and REQUIRED arguments and set CHECK_FOUND to TRUE if
-  # all listed variables are TRUE
-  INCLUDE(FindPackageHandleStandardArgs)
-
-  FIND_PACKAGE_HANDLE_STANDARD_ARGS(Check "Please install 'check' and 'check-devel' packages" CHECK_LIBRARY CHECK_INCLUDE_DIR)
-ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4)
-
-IF(CHECK_FOUND)
-  SET( CHECK_LIBRARIES ${CHECK_LIBRARY} )
-ELSE(CHECK_FOUND)
-  SET( CHECK_LIBRARIES )
-ENDIF(CHECK_FOUND)
-
-MARK_AS_ADVANCED(CHECK_INCLUDE_DIR)
-MARK_AS_ADVANCED(CHECK_LIBRARY)
diff --git a/libsolv-0.6.15/cmake/modules/FindEXPAT.cmake b/libsolv-0.6.15/cmake/modules/FindEXPAT.cmake
deleted file mode 100644 (file)
index d48eef3..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# - Find expat
-# Find the native EXPAT headers and libraries.
-#
-#  EXPAT_INCLUDE_DIRS - where to find expat.h, etc.
-#  EXPAT_LIBRARIES    - List of libraries when using expat.
-#  EXPAT_FOUND        - True if expat found.
-
-# Look for the header file.
-FIND_PATH(EXPAT_INCLUDE_DIR NAMES expat.h)
-MARK_AS_ADVANCED(EXPAT_INCLUDE_DIR)
-
-# Look for the library.
-FIND_LIBRARY(EXPAT_LIBRARY NAMES expat)
-MARK_AS_ADVANCED(EXPAT_LIBRARY)
-
-# Copy the results to the output variables.
-IF(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY)
-  SET(EXPAT_FOUND 1)
-  SET(EXPAT_LIBRARIES ${EXPAT_LIBRARY})
-  SET(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIR})
-ELSE(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY)
-  SET(EXPAT_FOUND 0)
-  SET(EXPAT_LIBRARIES)
-  SET(EXPAT_INCLUDE_DIRS)
-ENDIF(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY)
-
-# Report the results.
-IF(NOT EXPAT_FOUND)
-  SET(EXPAT_DIR_MESSAGE
-    "EXPAT was not found. Make sure EXPAT_LIBRARY and EXPAT_INCLUDE_DIR are set.")
-  IF(NOT EXPAT_FIND_QUIETLY)
-    MESSAGE(STATUS "${EXPAT_DIR_MESSAGE}")
-  ELSE(NOT EXPAT_FIND_QUIETLY)
-    IF(EXPAT_FIND_REQUIRED)
-      MESSAGE(FATAL_ERROR "${EXPAT_DIR_MESSAGE}")
-    ENDIF(EXPAT_FIND_REQUIRED)
-  ENDIF(NOT EXPAT_FIND_QUIETLY)
-ENDIF(NOT EXPAT_FOUND)
diff --git a/libsolv-0.6.15/cmake/modules/FindLZMA.cmake b/libsolv-0.6.15/cmake/modules/FindLZMA.cmake
deleted file mode 100644 (file)
index eb112df..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# - Find lzma
-# Find the native LZMA headers and library
-#
-#  LZMA_INCLUDE_DIR    - where to find lzma.h, etc.
-#  LZMA_LIBRARIES      - List of libraries when using liblzma.
-#  LZMA_FOUND          - True if liblzma found.
-
-IF (LZMA_INCLUDE_DIR)
-  # Already in cache, be silent
-  SET(LZMA_FIND_QUIETLY TRUE)
-ENDIF (LZMA_INCLUDE_DIR)
-
-FIND_PATH(LZMA_INCLUDE_DIR lzma.h)
-FIND_LIBRARY(LZMA_LIBRARY NAMES lzma liblzma)
-
-# handle the QUIETLY and REQUIRED arguments and set LZMA_FOUND to TRUE if 
-# all listed variables are TRUE
-INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMA DEFAULT_MSG LZMA_LIBRARY LZMA_INCLUDE_DIR)
-
-IF(LZMA_FOUND)
-  SET( LZMA_LIBRARIES ${LZMA_LIBRARY} )
-ELSE(LZMA_FOUND)
-  SET( LZMA_LIBRARIES )
-ENDIF(LZMA_FOUND)
diff --git a/libsolv-0.6.15/cmake/modules/FindLibSolv.cmake b/libsolv-0.6.15/cmake/modules/FindLibSolv.cmake
deleted file mode 100644 (file)
index 166e79d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-# FindLibSolv - Find libsolv headers and libraries.
-#
-# Sample:
-#
-#   SET( LibSolv_USE_STATIC_LIBS OFF )
-#   FIND_PACKAGE( LibSolv REQUIRED ext )
-#   IF( LibSolv_FOUND )
-#      INCLUDE_DIRECTORIES( ${LibSolv_INCLUDE_DIRS} )
-#      TARGET_LINK_LIBRARIES( ... ${LibSolv_LIBRARIES} )
-#   ENDIF()
-#
-# Variables used by this module need to be set before calling find_package
-# (not that they are cmale cased like the modiulemane itself):
-#
-#   LibSolv_USE_STATIC_LIBS    Can be set to ON to force the use of the static
-#                              libsolv libraries. Defaults to OFF.
-#
-# Supported components:
-#
-#   ext                                Also include libsolvext
-#
-# Variables provided by this module:
-#
-#   LibSolv_FOUND              Include dir, libsolv and all extra libraries
-#                              specified in the COMPONENTS list were found.
-#
-#   LibSolv_LIBRARIES          Link to these to use all the libraries you specified.
-#
-#   LibSolv_INCLUDE_DIRS       Include directories.
-#
-# For each component you specify in find_package(), the following (UPPER-CASE)
-# variables are set to pick and choose components instead of just using LibSolv_LIBRARIES:
-#
-#   LIBSOLV_FOUND                      TRUE if libsolv was found
-#   LIBSOLV_LIBRARY                    libsolv libraries
-#
-#   LIBSOLV_${COMPONENT}_FOUND         TRUE if the library component was found
-#   LIBSOLV_${COMPONENT}_LIBRARY       The libraries for the specified component
-#
-
-# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
-IF(LibSolv_USE_STATIC_LIBS)
-    SET( _ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
-    SET(CMAKE_FIND_LIBRARY_SUFFIXES .a )
-ENDIF()
-
-# Look for the header files
-UNSET(LibSolv_INCLUDE_DIRS CACHE)
-FIND_PATH(LibSolv_INCLUDE_DIRS NAMES solv/solvable.h)
-
-# Look for the core library
-UNSET(LIBSOLV_LIBRARY CACHE)
-FIND_LIBRARY(LIBSOLV_LIBRARY NAMES solv)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSolv DEFAULT_MSG LIBSOLV_LIBRARY LibSolv_INCLUDE_DIRS)
-MARK_AS_ADVANCED(
-    LIBSOLV_FOUND
-    LIBSOLV_LIBRARY
-)
-
-# Prepare return values and collectiong more components
-SET(LibSolv_FOUND ${LIBSOLV_FOUND})
-SET(LibSolv_LIBRARIES ${LIBSOLV_LIBRARY})
-MARK_AS_ADVANCED(
-    LibSolv_FOUND
-    LibSolv_LIBRARIES
-    LibSolv_INCLUDE_DIRS
-)
-
-# Look for components
-FOREACH(COMPONENT ${LibSolv_FIND_COMPONENTS})
-    STRING(TOUPPER ${COMPONENT} _UPPERCOMPONENT)
-    UNSET(LIBSOLV_${_UPPERCOMPONENT}_LIBRARY CACHE)
-    FIND_LIBRARY(LIBSOLV_${_UPPERCOMPONENT}_LIBRARY NAMES solv${COMPONENT})
-    SET(LibSolv_${COMPONENT}_FIND_REQUIRED ${LibSolv_FIND_REQUIRED})
-    SET(LibSolv_${COMPONENT}_FIND_QUIETLY ${LibSolv_FIND_QUIETLY})
-    FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSolv_${COMPONENT} DEFAULT_MSG LIBSOLV_${_UPPERCOMPONENT}_LIBRARY)
-    MARK_AS_ADVANCED(
-       LIBSOLV_${_UPPERCOMPONENT}_FOUND
-       LIBSOLV_${_UPPERCOMPONENT}_LIBRARY
-    )
-    IF(LIBSOLV_${_UPPERCOMPONENT}_FOUND)
-       SET(LibSolv_LIBRARIES ${LibSolv_LIBRARIES} ${LIBSOLV_${_UPPERCOMPONENT}_LIBRARY})
-    ELSE()
-       SET(LibSolv_FOUND FALSE)
-    ENDIF()
-ENDFOREACH()
-
-# restore CMAKE_FIND_LIBRARY_SUFFIXES
-IF(Solv_USE_STATIC_LIBS)
-    SET(CMAKE_FIND_LIBRARY_SUFFIXES ${_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES} )
-ENDIF()
-
-IF(LibSolv_FOUND AND NOT LibSolv_FIND_QUIETLY)
-    MESSAGE(STATUS "Found LibSolv: ${LibSolv_INCLUDE_DIRS} ${LibSolv_LIBRARIES}")
-ENDIF()
diff --git a/libsolv-0.6.15/cmake/modules/FindPackageHandleStandardArgs.cmake b/libsolv-0.6.15/cmake/modules/FindPackageHandleStandardArgs.cmake
deleted file mode 100644 (file)
index 2fa8fbc..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
-#
-# This function is intended to be used in FindXXX.cmake modules files.
-# It handles the REQUIRED, QUIET and version-related arguments to FIND_PACKAGE().
-# It also sets the <UPPERCASED_NAME>_FOUND variable.
-# The package is considered found if all variables <var1>... listed contain
-# valid results, e.g. valid filepaths.
-#
-# There are two modes of this function. The first argument in both modes is
-# the name of the Find-module where it is called (in original casing).
-#
-# The first simple mode looks like this:
-#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
-# If the variables <var1> to <varN> are all valid, then <UPPERCASED_NAME>_FOUND
-# will be set to TRUE.
-# If DEFAULT_MSG is given as second argument, then the function will generate
-# itself useful success and error messages. You can also supply a custom error message
-# for the failure case. This is not recommended.
-#
-# The second mode is more powerful and also supports version checking:
-#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME [REQUIRED_VARS <var1>...<varN>]
-#                                           [VERSION_VAR   <versionvar>]
-#                                           [HANDLE_COMPONENTS]
-#                                           [CONFIG_MODE]
-#                                           [FAIL_MESSAGE "Custom failure message"] )
-#
-# As above, if <var1> through <varN> are all valid, <UPPERCASED_NAME>_FOUND
-# will be set to TRUE.
-# After REQUIRED_VARS the variables which are required for this package are listed.
-# Following VERSION_VAR the name of the variable can be specified which holds
-# the version of the package which has been found. If this is done, this version
-# will be checked against the (potentially) specified required version used
-# in the find_package() call. The EXACT keyword is also handled. The default
-# messages include information about the required version and the version
-# which has been actually found, both if the version is ok or not.
-# If the package supports components, use the HANDLE_COMPONENTS option to enable
-# handling them. In this case, find_package_handle_standard_args() will report
-# which components have been found and which are missing, and the <NAME>_FOUND
-# variable will be set to FALSE if any of the required components (i.e. not the
-# ones listed after OPTIONAL_COMPONENTS) are missing.
-# Use the option CONFIG_MODE if your FindXXX.cmake module is a wrapper for
-# a find_package(... NO_MODULE) call.  In this case VERSION_VAR will be set
-# to <NAME>_VERSION and the macro will automatically check whether the
-# Config module was found.
-# Via FAIL_MESSAGE a custom failure message can be specified, if this is not
-# used, the default message will be displayed.
-#
-# Example for mode 1:
-#
-#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2  DEFAULT_MSG  LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
-#
-# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
-# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE.
-# If it is not found and REQUIRED was used, it fails with FATAL_ERROR,
-# independent whether QUIET was used or not.
-# If it is found, success will be reported, including the content of <var1>.
-# On repeated Cmake runs, the same message won't be printed again.
-#
-# Example for mode 2:
-#
-#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON  REQUIRED_VARS BISON_EXECUTABLE
-#                                             VERSION_VAR BISON_VERSION)
-# In this case, BISON is considered to be found if the variable(s) listed
-# after REQUIRED_VAR are all valid, i.e. BISON_EXECUTABLE in this case.
-# Also the version of BISON will be checked by using the version contained
-# in BISON_VERSION.
-# Since no FAIL_MESSAGE is given, the default messages will be printed.
-#
-# Another example for mode 2:
-#
-#    FIND_PACKAGE(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
-#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(Automoc4  CONFIG_MODE)
-# In this case, FindAutmoc4.cmake wraps a call to FIND_PACKAGE(Automoc4 NO_MODULE)
-# and adds an additional search directory for automoc4.
-# The following FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
-# success/error message.
-
-#=============================================================================
-# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-#
-# * Neither the names of Kitware, Inc., the Insight Software Consortium,
-#   nor the names of their contributors may be used to endorse or promote
-#   products derived from this software without specific prior written
-#   permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
-
-INCLUDE(FindPackageMessage)
-INCLUDE(_CMakeParseArguments)
-
-# internal helper macro
-MACRO(_FPHSA_FAILURE_MESSAGE _msg)
-  IF (${_NAME}_FIND_REQUIRED)
-    MESSAGE(FATAL_ERROR "${_msg}")
-  ELSE (${_NAME}_FIND_REQUIRED)
-    IF (NOT ${_NAME}_FIND_QUIETLY)
-      MESSAGE(STATUS "${_msg}")
-    ENDIF (NOT ${_NAME}_FIND_QUIETLY)
-  ENDIF (${_NAME}_FIND_REQUIRED)
-ENDMACRO(_FPHSA_FAILURE_MESSAGE _msg)
-
-
-# internal helper macro to generate the failure message when used in CONFIG_MODE:
-MACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
-  # <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
-  IF(${_NAME}_CONFIG)
-    _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
-  ELSE(${_NAME}_CONFIG)
-    # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
-    # List them all in the error message:
-    IF(${_NAME}_CONSIDERED_CONFIGS)
-      SET(configsText "")
-      LIST(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
-      MATH(EXPR configsCount "${configsCount} - 1")
-      FOREACH(currentConfigIndex RANGE ${configsCount})
-        LIST(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
-        LIST(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
-        SET(configsText "${configsText}    ${filename} (version ${version})\n")
-      ENDFOREACH(currentConfigIndex)
-      _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
-
-    ELSE(${_NAME}_CONSIDERED_CONFIGS)
-      # Simple case: No Config-file was found at all:
-      _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
-    ENDIF(${_NAME}_CONSIDERED_CONFIGS)
-  ENDIF(${_NAME}_CONFIG)
-ENDMACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
-
-
-FUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
-
-# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
-# new extended or in the "old" mode:
-  SET(options CONFIG_MODE HANDLE_COMPONENTS)
-  SET(oneValueArgs FAIL_MESSAGE VERSION_VAR)
-  SET(multiValueArgs REQUIRED_VARS)
-  SET(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )
-  LIST(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
-
-  IF(${INDEX} EQUAL -1)
-    SET(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
-    SET(FPHSA_REQUIRED_VARS ${ARGN})
-    SET(FPHSA_VERSION_VAR)
-  ELSE(${INDEX} EQUAL -1)
-
-    CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${_FIRST_ARG} ${ARGN})
-
-    IF(FPHSA_UNPARSED_ARGUMENTS)
-      MESSAGE(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
-    ENDIF(FPHSA_UNPARSED_ARGUMENTS)
-
-    IF(NOT FPHSA_FAIL_MESSAGE)
-      SET(FPHSA_FAIL_MESSAGE  "DEFAULT_MSG")
-    ENDIF(NOT FPHSA_FAIL_MESSAGE)
-  ENDIF(${INDEX} EQUAL -1)
-
-# now that we collected all arguments, process them
-
-  IF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG")
-    SET(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
-  ENDIF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG")
-
-  # In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
-  # when it successfully found the config-file, including version checking:
-  IF(FPHSA_CONFIG_MODE)
-    LIST(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
-    LIST(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
-    SET(FPHSA_VERSION_VAR ${_NAME}_VERSION)
-  ENDIF(FPHSA_CONFIG_MODE)
-
-  IF(NOT FPHSA_REQUIRED_VARS)
-    MESSAGE(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
-  ENDIF(NOT FPHSA_REQUIRED_VARS)
-
-  LIST(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
-
-  STRING(TOUPPER ${_NAME} _NAME_UPPER)
-  STRING(TOLOWER ${_NAME} _NAME_LOWER)
-
-  # collect all variables which were not found, so they can be printed, so the
-  # user knows better what went wrong (#6375)
-  SET(MISSING_VARS "")
-  SET(DETAILS "")
-  SET(${_NAME_UPPER}_FOUND TRUE)
-  # check if all passed variables are valid
-  FOREACH(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
-    IF(NOT ${_CURRENT_VAR})
-      SET(${_NAME_UPPER}_FOUND FALSE)
-      SET(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
-    ELSE(NOT ${_CURRENT_VAR})
-      SET(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
-    ENDIF(NOT ${_CURRENT_VAR})
-  ENDFOREACH(_CURRENT_VAR)
-
-  # component handling
-  SET(FOUND_COMPONENTS_MSG "")
-  SET(MISSING_COMPONENTS_MSG "")
-
-  IF(FPHSA_HANDLE_COMPONENTS)
-    FOREACH(comp ${${_NAME}_FIND_COMPONENTS})
-      IF(${_NAME}_${comp}_FOUND)
-
-        IF(NOT FOUND_COMPONENTS_MSG)
-          SET(FOUND_COMPONENTS_MSG "found components: ")
-        ENDIF()
-        SET(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
-
-      ELSE()
-
-        IF(NOT MISSING_COMPONENTS_MSG)
-          SET(MISSING_COMPONENTS_MSG "missing components: ")
-        ENDIF()
-        SET(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
-
-        IF(${_NAME}_FIND_REQUIRED_${comp})
-          SET(${_NAME_UPPER}_FOUND FALSE)
-          SET(MISSING_VARS "${MISSING_VARS} ${comp}")
-        ENDIF()
-
-      ENDIF()
-    ENDFOREACH(comp)
-    SET(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
-    SET(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
-  ENDIF(FPHSA_HANDLE_COMPONENTS)
-
-  # version handling:
-  SET(VERSION_MSG "")
-  SET(VERSION_OK TRUE)
-  SET(VERSION ${${FPHSA_VERSION_VAR}} )
-  IF (${_NAME}_FIND_VERSION)
-
-    IF(VERSION)
-
-      IF(${_NAME}_FIND_VERSION_EXACT)       # exact version required
-        IF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
-          SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
-          SET(VERSION_OK FALSE)
-        ELSE (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
-          SET(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
-        ENDIF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
-
-      ELSE(${_NAME}_FIND_VERSION_EXACT)     # minimum version specified:
-        IF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
-          SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
-          SET(VERSION_OK FALSE)
-        ELSE ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
-          SET(VERSION_MSG "(found suitable version \"${VERSION}\", required is \"${${_NAME}_FIND_VERSION}\")")
-        ENDIF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
-      ENDIF(${_NAME}_FIND_VERSION_EXACT)
-
-    ELSE(VERSION)
-
-      # if the package was not found, but a version was given, add that to the output:
-      IF(${_NAME}_FIND_VERSION_EXACT)
-         SET(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
-      ELSE(${_NAME}_FIND_VERSION_EXACT)
-         SET(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
-      ENDIF(${_NAME}_FIND_VERSION_EXACT)
-
-    ENDIF(VERSION)
-  ELSE (${_NAME}_FIND_VERSION)
-    IF(VERSION)
-      SET(VERSION_MSG "(found version \"${VERSION}\")")
-    ENDIF(VERSION)
-  ENDIF (${_NAME}_FIND_VERSION)
-
-  IF(VERSION_OK)
-    SET(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
-  ELSE(VERSION_OK)
-    SET(${_NAME_UPPER}_FOUND FALSE)
-  ENDIF(VERSION_OK)
-
-
-  # print the result:
-  IF (${_NAME_UPPER}_FOUND)
-    FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
-  ELSE (${_NAME_UPPER}_FOUND)
-
-    IF(FPHSA_CONFIG_MODE)
-      _FPHSA_HANDLE_FAILURE_CONFIG_MODE()
-    ELSE(FPHSA_CONFIG_MODE)
-      IF(NOT VERSION_OK)
-        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
-      ELSE(NOT VERSION_OK)
-        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
-      ENDIF(NOT VERSION_OK)
-    ENDIF(FPHSA_CONFIG_MODE)
-
-  ENDIF (${_NAME_UPPER}_FOUND)
-
-  SET(${_NAME_UPPER}_FOUND ${${_NAME_UPPER}_FOUND} PARENT_SCOPE)
-
-ENDFUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _FIRST_ARG)
diff --git a/libsolv-0.6.15/cmake/modules/FindRuby.cmake b/libsolv-0.6.15/cmake/modules/FindRuby.cmake
deleted file mode 100644 (file)
index 827a7a6..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-# - Find Ruby
-# This module finds if Ruby is installed and determines where the include files
-# and libraries are. Ruby 1.8 and 1.9 are supported.
-#
-# The minimum required version of Ruby can be specified using the
-# standard syntax, e.g. FIND_PACKAGE(Ruby 1.8)
-#
-# It also determines what the name of the library is. This
-# code sets the following variables:
-#
-#  RUBY_EXECUTABLE   = full path to the ruby binary
-#  RUBY_INCLUDE_DIRS = include dirs to be used when using the ruby library
-#  RUBY_LIBRARY      = full path to the ruby library
-#  RUBY_VERSION      = the version of ruby which was found, e.g. "1.8.7"
-#  RUBY_FOUND        = set to true if ruby ws found successfully
-#
-#  RUBY_INCLUDE_PATH = same as RUBY_INCLUDE_DIRS, only provided for compatibility reasons, don't use it
-
-#=============================================================================
-# Copyright 2004-2009 Kitware, Inc.
-# Copyright 2008-2009 Alexander Neundorf <neundorf@kde.org>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-#
-# * Neither the names of Kitware, Inc., the Insight Software Consortium,
-#   nor the names of their contributors may be used to endorse or promote
-#   products derived from this software without specific prior written
-#   permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
-
-#   RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'`
-#   RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'`
-#   RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'`
-#   RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'`
-#   RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'`
-
-# uncomment the following line to get debug output for this file
-# SET(_RUBY_DEBUG_OUTPUT TRUE)
-
-# Determine the list of possible names of the ruby executable depending
-# on which version of ruby is required
-SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ruby)
-
-# if 1.9 is required, don't look for ruby18 and ruby1.8, default to version 1.8
-IF(Ruby_FIND_VERSION_MAJOR  AND  Ruby_FIND_VERSION_MINOR)
-   SET(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${RUBY_FIND_VERSION_MINOR}")
-ELSE(Ruby_FIND_VERSION_MAJOR  AND  Ruby_FIND_VERSION_MINOR)
-   SET(Ruby_FIND_VERSION_SHORT_NODOT "18")
-ENDIF(Ruby_FIND_VERSION_MAJOR  AND  Ruby_FIND_VERSION_MINOR)
-
-SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES} ruby1.9 ruby19)
-
-# if we want a version below 1.9, also look for ruby 1.8
-IF("${Ruby_FIND_VERSION_SHORT_NODOT}" VERSION_LESS "19")
-   SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES} ruby1.8 ruby18)
-ENDIF("${Ruby_FIND_VERSION_SHORT_NODOT}" VERSION_LESS "19")
-
-FIND_PROGRAM(RUBY_EXECUTABLE NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES})
-
-
-IF(RUBY_EXECUTABLE  AND NOT  RUBY_VERSION_MAJOR)
-  FUNCTION(_RUBY_CONFIG_VAR RBVAR OUTVAR)
-    EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']"
-      RESULT_VARIABLE _RUBY_SUCCESS
-      OUTPUT_VARIABLE _RUBY_OUTPUT
-      ERROR_QUIET)
-    IF(_RUBY_SUCCESS OR NOT _RUBY_OUTPUT)
-      EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['${RBVAR}']"
-        RESULT_VARIABLE _RUBY_SUCCESS
-        OUTPUT_VARIABLE _RUBY_OUTPUT
-        ERROR_QUIET)
-    ENDIF(_RUBY_SUCCESS OR NOT _RUBY_OUTPUT)
-    SET(${OUTVAR} "${_RUBY_OUTPUT}" PARENT_SCOPE)
-  ENDFUNCTION(_RUBY_CONFIG_VAR)
-
-
-  # query the ruby version
-   _RUBY_CONFIG_VAR("MAJOR" RUBY_VERSION_MAJOR)
-   _RUBY_CONFIG_VAR("MINOR" RUBY_VERSION_MINOR)
-   _RUBY_CONFIG_VAR("TEENY" RUBY_VERSION_PATCH)
-
-   # query the different directories
-   _RUBY_CONFIG_VAR("archdir" RUBY_ARCH_DIR)
-   _RUBY_CONFIG_VAR("arch" RUBY_ARCH)
-   _RUBY_CONFIG_VAR("rubyhdrdir" RUBY_HDR_DIR)
-   _RUBY_CONFIG_VAR("libdir" RUBY_POSSIBLE_LIB_DIR)
-   _RUBY_CONFIG_VAR("rubylibdir" RUBY_RUBY_LIB_DIR)
-
-   # site_ruby
-   _RUBY_CONFIG_VAR("sitearchdir" RUBY_SITEARCH_DIR)
-   _RUBY_CONFIG_VAR("sitelibdir" RUBY_SITELIB_DIR)
-
-   # vendor_ruby available ?
-   EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print 'true' unless RbConfig::CONFIG['vendorarchdir'].nil?"
-      OUTPUT_VARIABLE RUBY_HAS_VENDOR_RUBY  ERROR_QUIET)
-
-   IF(RUBY_HAS_VENDOR_RUBY)
-      _RUBY_CONFIG_VAR("vendorlibdir" RUBY_VENDORLIB_DIR)
-      _RUBY_CONFIG_VAR("vendorarchdir" RUBY_VENDORARCH_DIR)
-   ENDIF(RUBY_HAS_VENDOR_RUBY)
-
-   # save the results in the cache so we don't have to run ruby the next time again
-   SET(RUBY_VERSION_MAJOR    ${RUBY_VERSION_MAJOR}    CACHE PATH "The Ruby major version" FORCE)
-   SET(RUBY_VERSION_MINOR    ${RUBY_VERSION_MINOR}    CACHE PATH "The Ruby minor version" FORCE)
-   SET(RUBY_VERSION_PATCH    ${RUBY_VERSION_PATCH}    CACHE PATH "The Ruby patch version" FORCE)
-   SET(RUBY_ARCH_DIR         ${RUBY_ARCH_DIR}         CACHE PATH "The Ruby arch dir" FORCE)
-   SET(RUBY_HDR_DIR          ${RUBY_HDR_DIR}          CACHE PATH "The Ruby header dir (1.9)" FORCE)
-   SET(RUBY_POSSIBLE_LIB_DIR ${RUBY_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE)
-   SET(RUBY_RUBY_LIB_DIR     ${RUBY_RUBY_LIB_DIR}     CACHE PATH "The Ruby ruby-lib dir" FORCE)
-   SET(RUBY_SITEARCH_DIR     ${RUBY_SITEARCH_DIR}     CACHE PATH "The Ruby site arch dir" FORCE)
-   SET(RUBY_SITELIB_DIR      ${RUBY_SITELIB_DIR}      CACHE PATH "The Ruby site lib dir" FORCE)
-   SET(RUBY_HAS_VENDOR_RUBY  ${RUBY_HAS_VENDOR_RUBY}  CACHE BOOL "Vendor Ruby is available" FORCE)
-   SET(RUBY_VENDORARCH_DIR   ${RUBY_VENDORARCH_DIR}   CACHE PATH "The Ruby vendor arch dir" FORCE)
-   SET(RUBY_VENDORLIB_DIR    ${RUBY_VENDORLIB_DIR}    CACHE PATH "The Ruby vendor lib dir" FORCE)
-
-   MARK_AS_ADVANCED(
-     RUBY_ARCH_DIR
-     RUBY_ARCH
-     RUBY_HDR_DIR
-     RUBY_POSSIBLE_LIB_DIR
-     RUBY_RUBY_LIB_DIR
-     RUBY_SITEARCH_DIR
-     RUBY_SITELIB_DIR
-     RUBY_HAS_VENDOR_RUBY
-     RUBY_VENDORARCH_DIR
-     RUBY_VENDORLIB_DIR
-     RUBY_VERSION_MAJOR
-     RUBY_VERSION_MINOR
-     RUBY_VERSION_PATCH
-     )
-ENDIF(RUBY_EXECUTABLE  AND NOT  RUBY_VERSION_MAJOR)
-
-# In case RUBY_EXECUTABLE could not be executed (e.g. cross compiling)
-# try to detect which version we found. This is not too good.
-IF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR)
-   # by default assume 1.8.0
-   SET(RUBY_VERSION_MAJOR 1)
-   SET(RUBY_VERSION_MINOR 8)
-   SET(RUBY_VERSION_PATCH 0)
-   # check whether we found 1.9.x
-   IF(${RUBY_EXECUTABLE} MATCHES "ruby1.?9"  OR  RUBY_HDR_DIR)
-      SET(RUBY_VERSION_MAJOR 1)
-      SET(RUBY_VERSION_MINOR 9)
-   ENDIF(${RUBY_EXECUTABLE} MATCHES "ruby1.?9"  OR  RUBY_HDR_DIR)
-ENDIF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR)
-
-IF(RUBY_VERSION_MAJOR)
-   SET(RUBY_VERSION "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}")
-   SET(_RUBY_VERSION_SHORT "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}")
-   SET(_RUBY_VERSION_SHORT_NODOT "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}")
-   SET(_RUBY_NODOT_VERSION "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}")
-ENDIF(RUBY_VERSION_MAJOR)
-
-FIND_PATH(RUBY_INCLUDE_DIR
-   NAMES ruby.h
-   HINTS
-   ${RUBY_HDR_DIR}
-   ${RUBY_ARCH_DIR}
-   /usr/lib/ruby/${_RUBY_VERSION_SHORT}/i586-linux-gnu/ )
-
-SET(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIR} )
-
-# if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir
-IF( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18  OR  "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18  OR  RUBY_HDR_DIR)
-   FIND_PATH(RUBY_CONFIG_INCLUDE_DIR
-     NAMES ruby/config.h  config.h
-     HINTS
-     ${RUBY_HDR_DIR}/${RUBY_ARCH}
-     ${RUBY_ARCH_DIR}
-     )
-
-   SET(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIRS} ${RUBY_CONFIG_INCLUDE_DIR} )
-ENDIF( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18  OR  "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18  OR  RUBY_HDR_DIR)
-
-
-# Determine the list of possible names for the ruby library
-SET(_RUBY_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_RUBY_VERSION_SHORT} ruby${_RUBY_VERSION_SHORT_NODOT} ruby-${_RUBY_VERSION_SHORT} ruby-${RUBY_VERSION})
-
-IF(WIN32)
-   SET( _RUBY_MSVC_RUNTIME "" )
-   IF( MSVC60 )
-     SET( _RUBY_MSVC_RUNTIME "60" )
-   ENDIF( MSVC60 )
-   IF( MSVC70 )
-     SET( _RUBY_MSVC_RUNTIME "70" )
-   ENDIF( MSVC70 )
-   IF( MSVC71 )
-     SET( _RUBY_MSVC_RUNTIME "71" )
-   ENDIF( MSVC71 )
-   IF( MSVC80 )
-     SET( _RUBY_MSVC_RUNTIME "80" )
-   ENDIF( MSVC80 )
-   IF( MSVC90 )
-     SET( _RUBY_MSVC_RUNTIME "90" )
-   ENDIF( MSVC90 )
-
-   LIST(APPEND _RUBY_POSSIBLE_LIB_NAMES
-               "msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}"
-               "msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}-static"
-               "msvcrt-ruby${_RUBY_NODOT_VERSION}"
-               "msvcrt-ruby${_RUBY_NODOT_VERSION}-static" )
-ENDIF(WIN32)
-
-FIND_LIBRARY(RUBY_LIBRARY NAMES ${_RUBY_POSSIBLE_LIB_NAMES} HINTS ${RUBY_POSSIBLE_LIB_DIR} )
-
-INCLUDE(FindPackageHandleStandardArgs)
-SET(_RUBY_REQUIRED_VARS RUBY_EXECUTABLE RUBY_INCLUDE_DIR RUBY_LIBRARY)
-IF(_RUBY_VERSION_SHORT_NODOT GREATER 18)
-   LIST(APPEND _RUBY_REQUIRED_VARS RUBY_CONFIG_INCLUDE_DIR)
-ENDIF(_RUBY_VERSION_SHORT_NODOT GREATER 18)
-
-IF(_RUBY_DEBUG_OUTPUT)
-   MESSAGE(STATUS "--------FindRuby.cmake debug------------")
-   MESSAGE(STATUS "_RUBY_POSSIBLE_EXECUTABLE_NAMES: ${_RUBY_POSSIBLE_EXECUTABLE_NAMES}")
-   MESSAGE(STATUS "_RUBY_POSSIBLE_LIB_NAMES: ${_RUBY_POSSIBLE_LIB_NAMES}")
-   MESSAGE(STATUS "RUBY_ARCH_DIR: ${RUBY_ARCH_DIR}")
-   MESSAGE(STATUS "RUBY_HDR_DIR: ${RUBY_HDR_DIR}")
-   MESSAGE(STATUS "RUBY_POSSIBLE_LIB_DIR: ${RUBY_POSSIBLE_LIB_DIR}")
-   MESSAGE(STATUS "Found RUBY_VERSION: \"${RUBY_VERSION}\" , short: \"${_RUBY_VERSION_SHORT}\", nodot: \"${_RUBY_VERSION_SHORT_NODOT}\"")
-   MESSAGE(STATUS "_RUBY_REQUIRED_VARS: ${_RUBY_REQUIRED_VARS}")
-   MESSAGE(STATUS "RUBY_EXECUTABLE: ${RUBY_EXECUTABLE}")
-   MESSAGE(STATUS "RUBY_LIBRARY: ${RUBY_LIBRARY}")
-   MESSAGE(STATUS "RUBY_INCLUDE_DIR: ${RUBY_INCLUDE_DIR}")
-   MESSAGE(STATUS "RUBY_CONFIG_INCLUDE_DIR: ${RUBY_CONFIG_INCLUDE_DIR}")
-   MESSAGE(STATUS "--------------------")
-ENDIF(_RUBY_DEBUG_OUTPUT)
-
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ruby  REQUIRED_VARS  ${_RUBY_REQUIRED_VARS}
-                                        VERSION_VAR RUBY_VERSION )
-
-MARK_AS_ADVANCED(
-  RUBY_EXECUTABLE
-  RUBY_LIBRARY
-  RUBY_INCLUDE_DIR
-  RUBY_CONFIG_INCLUDE_DIR
-  )
-
-# Set some variables for compatibility with previous version of this file
-SET(RUBY_POSSIBLE_LIB_PATH ${RUBY_POSSIBLE_LIB_DIR})
-SET(RUBY_RUBY_LIB_PATH ${RUBY_RUBY_LIB_DIR})
-SET(RUBY_INCLUDE_PATH ${RUBY_INCLUDE_DIRS})
diff --git a/libsolv-0.6.15/cmake/modules/_CMakeParseArguments.cmake b/libsolv-0.6.15/cmake/modules/_CMakeParseArguments.cmake
deleted file mode 100644 (file)
index 7122094..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
-#
-# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for
-# parsing the arguments given to that macro or function.
-# It processes the arguments and defines a set of variables which hold the
-# values of the respective options.
-#
-# The <options> argument contains all options for the respective macro,
-# i.e. keywords which can be used when calling the macro without any value
-# following, like e.g. the OPTIONAL keyword of the install() command.
-#
-# The <one_value_keywords> argument contains all keywords for this macro
-# which are followed by one value, like e.g. DESTINATION keyword of the
-# install() command.
-#
-# The <multi_value_keywords> argument contains all keywords for this macro
-# which can be followed by more than one value, like e.g. the TARGETS or
-# FILES keywords of the install() command.
-#
-# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
-# keywords listed in <options>, <one_value_keywords> and
-# <multi_value_keywords> a variable composed of the given <prefix>
-# followed by "_" and the name of the respective keyword.
-# These variables will then hold the respective value from the argument list.
-# For the <options> keywords this will be TRUE or FALSE.
-#
-# All remaining arguments are collected in a variable
-# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see whether
-# your macro was called with unrecognized parameters.
-#
-# As an example here a my_install() macro, which takes similar arguments as the
-# real install() command:
-#
-#   function(MY_INSTALL)
-#     set(options OPTIONAL FAST)
-#     set(oneValueArgs DESTINATION RENAME)
-#     set(multiValueArgs TARGETS CONFIGURATIONS)
-#     cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
-#     ...
-#
-# Assume my_install() has been called like this:
-#   my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
-#
-# After the cmake_parse_arguments() call the macro will have set the following
-# variables:
-#   MY_INSTALL_OPTIONAL = TRUE
-#   MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
-#   MY_INSTALL_DESTINATION = "bin"
-#   MY_INSTALL_RENAME = "" (was not used)
-#   MY_INSTALL_TARGETS = "foo;bar"
-#   MY_INSTALL_CONFIGURATIONS = "" (was not used)
-#   MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
-#
-# You can the continue and process these variables.
-#
-# Keywords terminate lists of values, e.g. if directly after a one_value_keyword
-# another recognized keyword follows, this is interpreted as the beginning of
-# the new option.
-# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
-# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
-# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
-
-#=============================================================================
-# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
-#
-# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-#
-# * Neither the names of Kitware, Inc., the Insight Software Consortium,
-#   nor the names of their contributors may be used to endorse or promote
-#   products derived from this software without specific prior written
-#   permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
-
-
-if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
-  return()
-endif()
-set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
-
-
-function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
-  # first set all result variables to empty/FALSE
-  foreach(arg_name ${_singleArgNames} ${_multiArgNames})
-    set(${prefix}_${arg_name})
-  endforeach(arg_name)
-
-  foreach(option ${_optionNames})
-    set(${prefix}_${option} FALSE)
-  endforeach(option)
-
-  set(${prefix}_UNPARSED_ARGUMENTS)
-
-  set(insideValues FALSE)
-  set(currentArgName)
-
-  # now iterate over all arguments and fill the result variables
-  foreach(currentArg ${ARGN})
-    list(FIND _optionNames "${currentArg}" optionIndex)  # ... then this marks the end of the arguments belonging to this keyword
-    list(FIND _singleArgNames "${currentArg}" singleArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
-    list(FIND _multiArgNames "${currentArg}" multiArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
-
-    if(${optionIndex} EQUAL -1  AND  ${singleArgIndex} EQUAL -1  AND  ${multiArgIndex} EQUAL -1)
-      if(insideValues)
-        if("${insideValues}" STREQUAL "SINGLE")
-          set(${prefix}_${currentArgName} ${currentArg})
-          set(insideValues FALSE)
-        elseif("${insideValues}" STREQUAL "MULTI")
-          list(APPEND ${prefix}_${currentArgName} ${currentArg})
-        endif()
-      else(insideValues)
-        list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
-      endif(insideValues)
-    else()
-      if(NOT ${optionIndex} EQUAL -1)
-        set(${prefix}_${currentArg} TRUE)
-        set(insideValues FALSE)
-      elseif(NOT ${singleArgIndex} EQUAL -1)
-        set(currentArgName ${currentArg})
-        set(${prefix}_${currentArgName})
-        set(insideValues "SINGLE")
-      elseif(NOT ${multiArgIndex} EQUAL -1)
-        set(currentArgName ${currentArg})
-        set(${prefix}_${currentArgName})
-        set(insideValues "MULTI")
-      endif()
-    endif()
-
-  endforeach(currentArg)
-
-  # propagate the result variables to the caller:
-  foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
-    set(${prefix}_${arg_name}  ${${prefix}_${arg_name}} PARENT_SCOPE)
-  endforeach(arg_name)
-  set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
-
-endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
diff --git a/libsolv-0.6.15/doc/CMakeLists.txt b/libsolv-0.6.15/doc/CMakeLists.txt
deleted file mode 100644 (file)
index 13e086c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-
-SET (libsolv_MANPAGES3
-    libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3
-    libsolv-pool.3)
-
-SET (libsolv_MANPAGES1
-    mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1)
-
-IF (ENABLE_RPMDB)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} rpmdb2solv.1 rpms2solv.1)
-ENDIF (ENABLE_RPMDB)
-
-IF (ENABLE_RPMMD)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} repomdxml2solv.1 rpmmd2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1)
-ENDIF (ENABLE_RPMMD)
-
-IF (ENABLE_HELIXREPO)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} helix2solv.1)
-ENDIF (ENABLE_HELIXREPO)
-
-IF (ENABLE_SUSEREPO)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} susetags2solv.1)
-ENDIF (ENABLE_SUSEREPO)
-
-IF (ENABLE_COMPS)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} comps2solv.1)
-ENDIF (ENABLE_COMPS)
-
-IF (ENABLE_DEBIAN)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} deb2solv.1)
-ENDIF (ENABLE_DEBIAN)
-
-IF (ENABLE_MDKREPO)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} mdk2solv.1)
-ENDIF (ENABLE_MDKREPO)
-
-IF (ENABLE_ARCHREPO)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} archpkgs2solv.1 archrepo2solv.1)
-ENDIF (ENABLE_ARCHREPO)
-
-IF (ENABLE_APPDATA)
-SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} appdata2solv.1)
-ENDIF (ENABLE_APPDATA)
-
-INSTALL(FILES
-    ${libsolv_MANPAGES3}
-    DESTINATION "${MAN_INSTALL_DIR}/man3")
-
-INSTALL(FILES
-    ${libsolv_MANPAGES1}
-    DESTINATION "${MAN_INSTALL_DIR}/man1")
diff --git a/libsolv-0.6.15/doc/Makefile.gen b/libsolv-0.6.15/doc/Makefile.gen
deleted file mode 100644 (file)
index 84a1095..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-man:   man3 man1
-
-man3:  libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 libsolv-pool.3
-
-man1:  mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 rpmdb2solv.1 rpms2solv.1 \
-       rpmmd2solv.1 repomdxml2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1 \
-       helix2solv.1 susetags2solv.1 comps2solv.1 deb2solv.1 mdk2solv.1 \
-       archpkgs2solv.1 archrepo2solv.1 appdata2solv.1
-
-html: libsolv.html libsolv-bindings.html libsolv-constantids.html libsolv-history.html libsolv-pool.html
-
-.SUFFIXES: .html .3 .1 .txt
-
-.txt.1:
-       a2x -f manpage $<
-
-.txt.3:
-       a2x -f manpage $<
-
-.txt.html:
-       a2x -f xhtml $<
diff --git a/libsolv-0.6.15/doc/appdata2solv.1 b/libsolv-0.6.15/doc/appdata2solv.1
deleted file mode 100644 (file)
index b5fdf9f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-'\" t
-.\"     Title: appdata2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "APPDATA2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-appdata2solv \- convert application meta data into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBappdata2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The appdata format contains metadata about application\&. It can be available both in repositories (for available applications) and in the installed system (for installed applications)\&. The appdata2solv tool reads the metadata from stdin and writes the parsed data as solv file to standard output\&. The parser will create \fBapplication:\fR pseudo packages for each entry\&.
-.PP
-\fB\-d\fR \fIAPPDATADIR\fR
-.RS 4
-Do not read from standard input, instead scan the specified directory for appdata entries\&.
-\fIAPPDATADIR\fR
-is normally set to
-\fB/usr/share/appdata\fR\&.
-.RE
-.PP
-\fB\-r\fR \fIROOTDIR\fR
-.RS 4
-Use
-\fIROOTDIR\fR
-as root directory\&.
-.RE
-.SH "SEE ALSO"
-.sp
-mergesolv(1)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/appdata2solv.txt b/libsolv-0.6.15/doc/appdata2solv.txt
deleted file mode 100644 (file)
index 3ccb4b5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-appdata2solv(1)
-===============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-appdata2solv - convert application meta data into a solv file
-
-Synopsis
---------
-*appdata2solv* ['OPTIONS']
-
-Description
------------
-The appdata format contains metadata about application. It can
-be available both in repositories (for available applications)
-and in the installed system (for installed applications).
-The appdata2solv tool reads the metadata from stdin and
-writes the parsed data as solv file to standard output. The
-parser will create *application:* pseudo packages for each entry.
-
-*-d* 'APPDATADIR'::
-Do not read from standard input, instead scan the specified
-directory for appdata entries. 'APPDATADIR' is normally
-set to */usr/share/appdata*.
-
-*-r* 'ROOTDIR'::
-Use 'ROOTDIR' as root directory.
-
-
-See Also
---------
-mergesolv(1)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/archpkgs2solv.1 b/libsolv-0.6.15/doc/archpkgs2solv.1
deleted file mode 100644 (file)
index 6052aee..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-'\" t
-.\"     Title: archpkgs2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "ARCHPKGS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-archpkgs2solv \- convert one or more Arch package files into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBarchpkgs2solv\fR [\fIOPTIONS\fR] \fIPKG1\&.pkg\&.xz\fR \&...
-.SH "DESCRIPTION"
-.sp
-The archpkgs2solv tool converts the meta data from one or more Arch Linux packages into the solv file written to standard output\&.
-.PP
-\fB\-m\fR \fIMANIFESTFILE\fR
-.RS 4
-Read the rpm file names from the specified
-\fIMANIFESTFILE\fR\&. You can use
-\fB\-\fR
-to read the manifest from standard input\&.
-.RE
-.PP
-\fB\-0\fR
-.RS 4
-Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the
-\fB\-print0\fR
-option in
-\fBfind\fR\&.
-.RE
-.SH "SEE ALSO"
-.sp
-pacman(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/archpkgs2solv.txt b/libsolv-0.6.15/doc/archpkgs2solv.txt
deleted file mode 100644 (file)
index 2a17066..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-archpkgs2solv(1)
-================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-archpkgs2solv - convert one or more Arch package files into a solv file
-
-Synopsis
---------
-*archpkgs2solv* ['OPTIONS'] 'PKG1.pkg.xz' ...
-
-Description
------------
-The archpkgs2solv tool converts the meta data from one or more
-Arch Linux packages into the solv file written to standard output.
-
-*-m* 'MANIFESTFILE'::
-Read the rpm file names from the specified 'MANIFESTFILE'. You can
-use *-* to read the manifest from standard input.
-
-*-0*::
-Use a null byte as line terminator for manifest files instead of
-a newline. This is useful if the file names can contain newlines.
-See also the *-print0* option in *find*.
-
-See Also
---------
-pacman(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/archrepo2solv.1 b/libsolv-0.6.15/doc/archrepo2solv.1
deleted file mode 100644 (file)
index 94f5c41..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-'\" t
-.\"     Title: archrepo2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "ARCHREPO2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-archrepo2solv \- convert files in Arch repository format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBarchrepo2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The archrepo2solv tool reads Arch Linux repository data (\fBcore\&.db\fR) from stdin, and writes it as solv file to standard output\&.
-.PP
-\fB\-l\fR \fIDATABASEDIR\fR
-.RS 4
-Instead of reading from standard input, scan the specified directory for package meta files\&. Set
-\fIDATABASEDIR\fR
-to
-\fB/var/lib/pacman/local\fR
-to scan the installed packages\&.
-.RE
-.SH "SEE ALSO"
-.sp
-pacman(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/archrepo2solv.txt b/libsolv-0.6.15/doc/archrepo2solv.txt
deleted file mode 100644 (file)
index 3f5b138..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-archrepo2solv(1)
-================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-archrepo2solv - convert files in Arch repository format into a solv file
-
-Synopsis
---------
-*archrepo2solv* ['OPTIONS']
-
-Description
------------
-The archrepo2solv tool reads Arch Linux repository data (*core.db*) from stdin,
-and writes it as solv file to standard output.
-
-*-l* 'DATABASEDIR'::
-Instead of reading from standard input, scan the specified directory for
-package meta files. Set 'DATABASEDIR' to */var/lib/pacman/local* to
-scan the installed packages.
-
-See Also
---------
-pacman(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/comps2solv.1 b/libsolv-0.6.15/doc/comps2solv.1
deleted file mode 100644 (file)
index c6f8d32..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-'\" t
-.\"     Title: comps2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "COMPS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-comps2solv \- convert rpm\-md comps\&.xml file into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBcomps2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The comps\&.xml file is Fedora\(cqs way to implement package groups\&. The comps2solv tool reads the comps xml file from stdin and writes the parsed data as solv file to standard output\&. The parser will create \fBgroup:\fR and \fBcategory:\fR pseudo packages for each comps entry\&.
-.SH "SEE ALSO"
-.sp
-mergesolv(1), createrepo(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/comps2solv.txt b/libsolv-0.6.15/doc/comps2solv.txt
deleted file mode 100644 (file)
index 23e304e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-comps2solv(1)
-=============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-comps2solv - convert rpm-md comps.xml file into a solv file
-
-Synopsis
---------
-*comps2solv* ['OPTIONS']
-
-Description
------------
-The comps.xml file is Fedora's way to implement package groups.
-The comps2solv tool reads the comps xml file from stdin and
-writes the parsed data as solv file to standard output. The
-parser will create *group:* and *category:* pseudo packages
-for each comps entry.
-
-See Also
---------
-mergesolv(1), createrepo(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/deb2solv.1 b/libsolv-0.6.15/doc/deb2solv.1
deleted file mode 100644 (file)
index 95f5091..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-'\" t
-.\"     Title: deb2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "DEB2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-deb2solv \- convert one or more Debian package files into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBdeb2solv\fR [\fIOPTIONS\fR] \fIPKG1\&.deb\fR \&...
-.SH "DESCRIPTION"
-.sp
-The deb2solv tool converts the meta data from one or more Debian packages into the solv file written to standard output\&.
-.PP
-\fB\-m\fR \fIMANIFESTFILE\fR
-.RS 4
-Read the rpm file names from the specified
-\fIMANIFESTFILE\fR\&. You can use
-\fB\-\fR
-to read the manifest from standard input\&.
-.RE
-.PP
-\fB\-0\fR
-.RS 4
-Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the
-\fB\-print0\fR
-option in
-\fBfind\fR\&.
-.RE
-.SH "SEE ALSO"
-.sp
-deb(5), dpkg\-deb(1)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/deb2solv.txt b/libsolv-0.6.15/doc/deb2solv.txt
deleted file mode 100644 (file)
index 0907383..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-deb2solv(1)
-============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-deb2solv - convert one or more Debian package files into a solv file
-
-Synopsis
---------
-*deb2solv* ['OPTIONS'] 'PKG1.deb' ...
-
-Description
------------
-The deb2solv tool converts the meta data from one or more
-Debian packages into the solv file written to standard output.
-
-*-m* 'MANIFESTFILE'::
-Read the rpm file names from the specified 'MANIFESTFILE'. You can
-use *-* to read the manifest from standard input.
-
-*-0*::
-Use a null byte as line terminator for manifest files instead of
-a newline. This is useful if the file names can contain newlines.
-See also the *-print0* option in *find*.
-
-See Also
---------
-deb(5), dpkg-deb(1)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/deltainfoxml2solv.1 b/libsolv-0.6.15/doc/deltainfoxml2solv.1
deleted file mode 100644 (file)
index 11cda74..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-'\" t
-.\"     Title: deltainfoxml2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "DELTAINFOXML2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-deltainfoxml2solv \- convert rpm\-md\*(Aqs deltainfo format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBdeltainfoxml2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The deltainfoxml2solv tool reads rpm\-md\(cqs \fBdeltainfo\&.xml\fR data from stdin, and writes it as solv file to standard output\&. Some distributions name the input \fBprestodelta\&.xml\fR instead\&. Each delta rpm element is converted and added as \fBrepository:deltainfo\fR element to the meta section of the solv file\&.
-.SH "SEE ALSO"
-.sp
-mergesolv(1), createrepo(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/deltainfoxml2solv.txt b/libsolv-0.6.15/doc/deltainfoxml2solv.txt
deleted file mode 100644 (file)
index f14a843..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-deltainfoxml2solv(1)
-====================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-deltainfoxml2solv - convert rpm-md's deltainfo format into a solv file
-
-Synopsis
---------
-*deltainfoxml2solv* ['OPTIONS']
-
-Description
------------
-The deltainfoxml2solv tool reads rpm-md's *deltainfo.xml* data from stdin,
-and writes it as solv file to standard output. Some distributions name
-the input *prestodelta.xml* instead. Each delta rpm element is converted
-and added as *repository:deltainfo* element to the meta section of the
-solv file.
-
-See Also
---------
-mergesolv(1), createrepo(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/dumpsolv.1 b/libsolv-0.6.15/doc/dumpsolv.1
deleted file mode 100644 (file)
index cb6a136..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-'\" t
-.\"     Title: dumpsolv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "DUMPSOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-dumpsolv \- print a solv file into a human readable format
-.SH "SYNOPSIS"
-.sp
-\fBdumpsolv\fR [\fIOPTIONS\fR] [\fIFILE\&.solv\fR]
-.SH "DESCRIPTION"
-.sp
-The dumpsolv tool reads a solv files and writes its contents to standard output\&. If no input file is given, it reads the solv file from standard input\&.
-.PP
-\fB\-j\fR
-.RS 4
-Write the contents in JSON format\&.
-.RE
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/dumpsolv.txt b/libsolv-0.6.15/doc/dumpsolv.txt
deleted file mode 100644 (file)
index ec2d771..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-dumpsolv(1)
-===========
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-dumpsolv - print a solv file into a human readable format
-
-Synopsis
---------
-*dumpsolv* ['OPTIONS'] ['FILE.solv']
-
-Description
------------
-The dumpsolv tool reads a solv files and writes its contents
-to standard output. If no input file is given, it reads the
-solv file from standard input.
-
-*-j*::
-Write the contents in JSON format.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/filters/xcode.conf b/libsolv-0.6.15/doc/filters/xcode.conf
deleted file mode 100644 (file)
index 294f908..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-[blockdef-listing]
-xcode-style=template="verseblock",presubs=(),postsubs=("callouts",),filter="filters/xcode.pl {basebackend}"
-
-[paradef-xcode]
-delimiter=(?s)^(?P<text>\s+.*)
-template=verseblock
-subs=verbatim
-filter=filters/xcode.pl {basebackend}
-
-[paradef-literal]
-delimiter=(?s)^(?P<text>\s{1,7}\S.*)
-
diff --git a/libsolv-0.6.15/doc/filters/xcode.pl b/libsolv-0.6.15/doc/filters/xcode.pl
deleted file mode 100755 (executable)
index 407641f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/perl
-
-die("I only understand docbook\n") unless @ARGV && $ARGV[0] eq 'docbook';
-
-#my $ii = '//';
-#my $io = '//';
-
-#my $si = '**';
-#my $so = '**';
-
-my $ii = '<emphasis>';
-my $io = '</emphasis>';
-
-my $si = '<emphasis role="strong">';
-my $so = '</emphasis>';
-
-while(<STDIN>) {
-  chomp;
-  my $in = '';
-  my $out = '';
-  s/^\s+//;
-  s/\s+$//;
-  if (/^(.*)(\s*\/\*.*?\*\/\s*?)$/) {
-    $out = $2;
-    $_ = $1;
-  }
-  if (/^(my\s+)(.*?)$/) {
-    $in = $1;
-    $_ = $2;
-  }
-  if (/(?<!\&gt);$/) {
-    $out = ";$out";
-    chop $_;
-  }
-  if (!/^[a-zA-Z0-9_]+$/) {
-    $_ = " $_";
-    $_ = "$_ ";
-    if (s/^ TCL +/ /) {
-      s/(\$[a-zA-Z_][a-zA-Z0-9_:]*)/<-S><I>$1<-I><S>/g;
-    } else {
-      s/(?<=[^a-zA-Z_\&:\.\'\";])(?!solv\W|Solv\W|Pool\W)([\$\@a-zA-Z_][a-zA-Z0-9_]*)(?=[^a-zA-Z0-9_\(;\[])(?!::)(?! [^=])/<-S><I>$1<-I><S>/g;
-    }
-    # fixup for perl bare words
-    s/{<-S><I>([a-zA-Z_][a-zA-Z0-9]*)<-I><S>}/{$1}/g;
-    # fixup for callbackfunctions
-    s/\\(&amp;[a-zA-Z_]+)/\\<-S><I>$1<-I><S>/;
-    # fixup for stringification
-    s/\$<-S><I>/<-S><I>\$/g;
-    # fixup for %d
-    s/%<-S><I>d<-I><S>\"/%d\"/;
-    s/%<-S><I>d<-I><S>\\<-S><I>n<-I><S>/%d\\n/;
-    # iterators
-    s/^ //;
-    s/ $//;
-    s/^(for (?:my )?)(\S+) /$1<-S><I>$2<-I><S> /;
-  }
-  $_ = "<S>$_<-S>";
-  s/<S>(\s*)<-S>/$1/g;
-  s/<-S>(\s*)<S>/$1/g;
-  s/<I>(\s*)<-I>/$1/g;
-  s/<-I>(\s*)<I>/$1/g;
-  s/<S>(\s+)/$1<S>/g;
-  s/(\s+)<-S>/<-S>$1/g;
-  s/<I>(\s+)/$1<I>/g;
-  s/(\s+)<-I>/<-I>$1/g;
-  s/<S>/$si/g;
-  s/<-S>/$so/g;
-  s/<I>/$ii/g;
-  s/<-I>/$io/g;
-  print "$in$_$out\n";
-}
diff --git a/libsolv-0.6.15/doc/helix2solv.1 b/libsolv-0.6.15/doc/helix2solv.1
deleted file mode 100644 (file)
index 07d9497..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-'\" t
-.\"     Title: helix2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 12/14/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "HELIX2SOLV" "1" "12/14/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-helix2solv \- convert legacy helixcode format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBhelix2solv\fR
-.SH "DESCRIPTION"
-.sp
-The helix format was a metadata format used in the RedCarpet package manager\&. It\(cqs still used in libzypp testcases\&. The helix2solv tool reads data in helix format from standard input and writes it in solv file format to standard output\&.
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/helix2solv.txt b/libsolv-0.6.15/doc/helix2solv.txt
deleted file mode 100644 (file)
index f9b303f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-helix2solv(1)
-=============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-helix2solv - convert legacy helixcode format into a solv file
-
-Synopsis
---------
-*helix2solv*
-
-Description
------------
-The helix format was a metadata format used in the RedCarpet
-package manager. It's still used in libzypp testcases.
-The helix2solv tool reads data in helix format from standard
-input and writes it in solv file format to standard output.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/installcheck.1 b/libsolv-0.6.15/doc/installcheck.1
deleted file mode 100644 (file)
index 7ee3e4d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-'\" t
-.\"     Title: installcheck
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "INSTALLCHECK" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-installcheck \- find out which packages cannot be installed
-.SH "SYNOPSIS"
-.sp
-\fBinstallcheck\fR \fIARCH\fR \fIREPO1\fR \fIREPO2\fR\&... \fB\-\-nocheck\fR \fINREPO1\fR \fINREPO2\fR\&...
-.SH "DESCRIPTION"
-.sp
-The installcheck tool checks if all packages in \fIREPO1\fR\&...\fIREPON\fR are installable\&. A package is installable if there is a set of packages from the repositories that satisfies its dependencies\&. The repositories after the \fB\-\-nocheck\fR option are only used for dependency resolving, but the tool does not check if the packages in them are installable\&.
-.sp
-A Repository can be a solv file, a rpmmd \fBprimary\&.xml\&.gz\fR file, a SUSE \fBpackages\fR or \fBpackages\&.gz\fR file, or a Debian \fBPackages\fR or \fBPackages\&.gz\fR file\&.
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/installcheck.txt b/libsolv-0.6.15/doc/installcheck.txt
deleted file mode 100644 (file)
index 99eb279..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-installcheck(1)
-===============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-installcheck - find out which packages cannot be installed
-
-Synopsis
---------
-*installcheck* 'ARCH' 'REPO1' 'REPO2'... *--nocheck* 'NREPO1' 'NREPO2'...
-
-Description
------------
-The installcheck tool checks if all packages in 'REPO1'...'REPON' are
-installable. A package is installable if there is a set of packages
-from the repositories that satisfies its dependencies. The repositories
-after the *--nocheck* option are only used for dependency resolving,
-but the tool does not check if the packages in them are installable.
-
-A Repository can be a solv file, a rpmmd *primary.xml.gz* file, a SUSE
-*packages* or *packages.gz* file, or a Debian *Packages* or *Packages.gz*
-file.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/libsolv-bindings.3 b/libsolv-0.6.15/doc/libsolv-bindings.3
deleted file mode 100644 (file)
index 14bf96c..0000000
+++ /dev/null
@@ -1,5721 +0,0 @@
-'\" t
-.\"     Title: Libsolv-Bindings
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 12/14/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "LIBSOLV\-BINDINGS" "3" "12/14/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-libsolv-bindings \- access libsolv from perl/python/ruby
-.SH "DESCRIPTION"
-.sp
-Libsolv\(cqs language bindings offer an abstract, object orientated interface to the library\&. The supported languages are currently perl, python, and ruby\&. All example code (except in the specifics sections, of course) lists first the \(lqC\-ish\(rq interface, then the syntax for perl, python, and ruby (in that order)\&.
-.SH "PERL SPECIFICS"
-.sp
-Libsolv\(cqs perl bindings can be loaded with the following statement:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBuse solv\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Objects are either created by calling the new() method on a class or they are returned by calling methods on other objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-my \fI$pool\fR \fB= solv::Pool\->new()\fR;
-my \fI$repo\fR \fB=\fR \fI$pool\fR\fB\->add_repo("my_first_repo")\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Swig encapsulates all objects as tied hashes, thus the attributes can be accessed by treating the object as standard hash reference:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fI$pool\fR\fB\->{appdata} = 42\fR;
-\fBprintf "appdata is %d\en",\fR \fI$pool\fR\fB\->{appdata}\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-A special exception to this are iterator objects, they are encapsulated as tied arrays so that it is possible to iterate with a for() statement:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-my \fI$iter\fR \fB=\fR \fI$pool\fR\fB\->solvables_iter()\fR;
-\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@$iter\fR\fB) { \&.\&.\&. }\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-As a downside of this approach, iterator objects cannot have attributes\&.
-.sp
-If an array needs to be passed to a method it is usually done by reference, if a method returns an array it returns it on the stack:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-my \fI@problems\fR \fB=\fR \fI$solver\fR\fB\->solve(\e\fR\fI@jobs\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Due to a bug in swig, stringification does not work for libsolv\(cqs objects\&. Instead, you have to call the object\(cqs str() method\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBprint\fR \fI$dep\fR\fB\->str() \&. "\e\fR\fIn\fR\fB"\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Swig implements all constants as numeric variables (instead of the more natural constant subs), so don\(cqt forget the leading \(lq$\(rq when accessing a constant\&. Also do not forget to prepend the namespace of the constant:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fI$pool\fR\fB\->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.SH "PYTHON SPECIFICS"
-.sp
-The python bindings can be loaded with:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBimport solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Objects are either created by calling the constructor method for a class or they are returned by calling methods on other objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIpool\fR \fB= solv\&.Pool()\fR
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo("my_first_repo")\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Attributes can be accessed as usual:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIpool\fR\fB\&.appdata = 42\fR
-\fBprint "appdata is %d" % (\fR\fIpool\fR\fB\&.appdata)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterators also work as expected:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter():\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Arrays are passed and returned as list objects:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIjobs\fR \fB= []\fR
-\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The bindings define stringification for many classes, some also have a \fIrepr\fR method to ease debugging\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBprint\fR \fIdep\fR
-\fBprint repr(\fR\fIrepo\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Constants are attributes of the classes:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIpool\fR\fB\&.set_flag(solv\&.Pool\&.POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.SH "RUBY SPECIFICS"
-.sp
-The ruby bindings can be loaded with:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBrequire \*(Aqsolv\*(Aq\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Objects are either created by calling the new method on a class or they are returned by calling methods on other objects\&. Note that all classes start with an uppercase letter in ruby, so the class is called \(lqSolv\(rq\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIpool\fR \fB= Solv::Pool\&.new\fR
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo("my_first_repo")\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Attributes can be accessed as usual:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIpool\fR\fB\&.appdata = 42\fR
-\fBputs "appdata is #{\fR\fIpool\fR\fB\&.appdata}"\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterators also work as expected:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter() do \&.\&.\&.\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Arrays are passed and returned as array objects:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIjobs\fR \fB= []\fR
-\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Most classes define a to_s method, so objects can be easily stringified\&. Many also define an inspect() method\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBputs\fR \fIdep\fR
-\fBputs\fR \fIrepo\fR\fB\&.inspect\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Constants live in the namespace of the class they belong to:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fIpool\fR\fB\&.set_flag(Solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Note that boolean methods have an added trailing \(lq?\(rq, to be consistent with other ruby modules:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBputs "empty" if\fR \fIrepo\fR\fB\&.isempty?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.SH "TCL SPECIFICS"
-.sp
-Libsolv\(cqs tcl bindings can be loaded with the following statement:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBpackage require solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Objects are either created by calling class name prefixed with \(lqnew_\(rq, or they are returned by calling methods on other objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBset pool [solv::new_Pool]\fR
-\fBset repo [\fR\fI$pool\fR \fBadd_repo "my_first_repo"]\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Swig provides a \(lqcget\(rq method to read object attributes, and a \(lqconfigure\(rq method to write them:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fI$pool\fR \fBconfigure \-appdata 42\fR
-\fBputs "appdata is [\fR\fI$pool\fR \fBcget \-appdata]"\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The tcl bindings provide a little helper to work with iterators in a foreach style:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBset iter [\fR\fI$pool\fR \fBsolvables_iter]\fR
-\fBsolv::iter s\fR \fI$iter\fR \fB{ \&.\&.\&. }\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-libsolv\(cqs arrays are mapped to tcl\(cqs lists:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBset jobs [list\fR \fI$job1 $job2\fR\fB]\fR
-\fBset problems [\fR\fI$solver\fR \fBsolve\fR \fI$jobs\fR\fB]\fR
-\fBputs "We have [llength\fR \fI$problems\fR\fB] problems\&.\&.\&."\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Stringification is done by calling the object\(cqs \(lqstr\(rq method\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBputs [\fR\fI$dep\fR \fBstr]\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-There is one exception: you have to use \(lqstringify\(rq for Datamatch objects, as swig reports a clash with the \(lqstr\(rq attribute\&. Some objects also support a \(lq==\(rq method for equality tests, and a \(lq!=\(rq method\&.
-.sp
-Swig implements all constants as numeric variables, constants belonging to a libsolv class are prefixed with the class name:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fI$pool\fR \fBset_flag\fR \fI$solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS\fR  \fB1\fR
-\fBputs [\fR\fI$solvable\fR \fBlookup_str\fR \fI$solv::SOLVABLE_SUMMARY\fR\fB]\fR
-.fi
-.if n \{\
-.RE
-.\}
-.SH "THE SOLV CLASS"
-.sp
-This is the main namespace of the library, you cannot create objects of this type but it contains some useful constants\&.
-.SS "CONSTANTS"
-.sp
-Relational flag constants, the first three can be or\-ed together
-.PP
-\fBREL_LT\fR
-.RS 4
-the \(lqless than\(rq bit
-.RE
-.PP
-\fBREL_EQ\fR
-.RS 4
-the \(lqequals to\(rq bit
-.RE
-.PP
-\fBREL_GT\fR
-.RS 4
-the \(lqgreater than\(rq bit
-.RE
-.PP
-\fBREL_ARCH\fR
-.RS 4
-used for relations that describe an extra architecture filter, the version part of the relation is interpreted as architecture\&.
-.RE
-.sp
-Special Solvable Ids
-.PP
-\fBSOLVID_META\fR
-.RS 4
-Access the meta section of a repository or repodata area\&. This is like an extra Solvable that has the Id SOLVID_META\&.
-.RE
-.PP
-\fBSOLVID_POS\fR
-.RS 4
-Use the data position stored inside of the pool instead of accessing some solvable by Id\&. The bindings have the Datapos objects as an abstraction mechanism, so you do not need this constant\&.
-.RE
-.sp
-Constant string Ids
-.PP
-\fBID_NULL\fR
-.RS 4
-Always zero
-.RE
-.PP
-\fBID_EMPTY\fR
-.RS 4
-Always one, describes the empty string
-.RE
-.PP
-\fBSOLVABLE_NAME\fR
-.RS 4
-The keyname Id of the name of the solvable\&.
-.RE
-.PP
-\fB\&...\fR
-.RS 4
-see the libsolv\-constantids manpage for a list of fixed Ids\&.
-.RE
-.SH "THE POOL CLASS"
-.sp
-The pool is libsolv\(cqs central resource manager\&. A pool consists of Solvables, Repositories, Dependencies, each indexed by Ids\&.
-.SS "CLASS METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *Pool()\fR
-my \fI$pool\fR \fB= solv::Pool\->new()\fR;
-\fIpool\fR \fB= solv\&.Pool()\fR
-\fIpool\fR \fB= Solv::Pool\&.new()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a new pool instance\&. In most cases you just need one pool\&. Note that the returned object "owns" the pool, i\&.e\&. if the object is freed, the pool is also freed\&. You can use the disown method to break this ownership relation\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid *appdata;\fR                  /* read/write */
-\fI$pool\fR\fB\->{appdata}\fR
-\fIpool\fR\fB\&.appdata\fR
-\fIpool\fR\fB\&.appdata\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Application specific data that may be used in any way by the code using the pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable solvables[];\fR           /* read only */
-my \fI$solvable\fR \fB=\fR \fI$pool\fR\fB\->{solvables}\->[\fR\fI$solvid\fR\fB]\fR;
-\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.solvables[\fR\fIsolvid\fR\fB]\fR
-\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.solvables[\fR\fIsolvid\fR\fB]\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Look up a Solvable by its id\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo repos[];\fR                   /* read only */
-my \fI$repo\fR \fB=\fR \fI$pool\fR\fB\->{repos}\->[\fR\fI$repoid\fR\fB]\fR;
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.repos[\fR\fIrepoid\fR\fB]\fR
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.repos[\fR\fIrepoid\fR\fB]\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Look up a Repository by its id\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo *installed;\fR                /* read/write */
-\fI$pool\fR\fB\->{installed} =\fR \fI$repo\fR;
-\fIpool\fR\fB\&.installed =\fR \fIrepo\fR
-\fIpool\fR\fB\&.installed =\fR \fIrepo\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Define which repository contains all the installed packages\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *errstr;\fR             /* read only */
-my \fI$err\fR \fB=\fR \fI$pool\fR\fB\->{errstr}\fR;
-\fIerr\fR \fB=\fR \fIpool\fR\fB\&.errstr\fR
-\fIerr\fR \fB=\fR \fIpool\fR\fB\&.errstr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the last error string that was stored in the pool\&.
-.SS "CONSTANTS"
-.PP
-\fBPOOL_FLAG_PROMOTEEPOCH\fR
-.RS 4
-Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch\&. Used at some time in old rpm versions, modern systems should never need this\&.
-.RE
-.PP
-\fBPOOL_FLAG_FORBIDSELFCONFLICTS\fR
-.RS 4
-Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them recently\&.
-.RE
-.PP
-\fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR
-.RS 4
-Make obsolete type dependency match against provides instead of just the name and version of packages\&. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version\&.
-.RE
-.PP
-\fBPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES\fR
-.RS 4
-An implicit obsoletes is the internal mechanism to remove the old package on an update\&. The default is to remove all packages with the same name, rpm\-5 switched to also removing packages providing the same name\&.
-.RE
-.PP
-\fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR
-.RS 4
-Rpm\(cqs multilib implementation (used in RedHat and Fedora) distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&.
-.RE
-.PP
-\fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR
-.RS 4
-Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel\&. For current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled)\&.
-.RE
-.PP
-\fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR
-.RS 4
-New versions of rpm consider the obsoletes of installed packages when checking for dependency, thus you may not install a package that is obsoleted by some other installed package, unless you also erase the other package\&.
-.RE
-.PP
-\fBPOOL_FLAG_HAVEDISTEPOCH\fR
-.RS 4
-Mandriva added a new field called distepoch that gets checked in version comparison if the epoch/version/release of two packages are the same\&.
-.RE
-.PP
-\fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR
-.RS 4
-If a package is installed in multiversionmode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&.
-.RE
-.PP
-\fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR
-.RS 4
-Make the addfileprovides method only add files from the standard locations (i\&.e\&. the \(lqbin\(rq and \(lqetc\(rq directories)\&. This is useful if you have only few packages that use non\-standard file dependencies, but you still want the fast speed that addfileprovides() generates\&.
-.RE
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid free()\fR
-\fI$pool\fR\fB\->free()\fR;
-\fIpool\fR\fB\&.free()\fR
-\fIpool\fR\fB\&.free()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Force a free of the pool\&. After this call, you must not access any object that still references the pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid disown()\fR
-\fI$pool\fR\fB\->disown()\fR;
-\fIpool\fR\fB\&.disown()\fR
-\fIpool\fR\fB\&.disown()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Break the ownership relation between the binding object and the pool\&. After this call, the pool will not get freed even if the object goes out of scope\&. This also means that you must manually call the free method to free the pool data\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid setdebuglevel(int\fR \fIlevel\fR\fB)\fR
-\fI$pool\fR\fB\->setdebuglevel(\fR\fI$level\fR\fB)\fR;
-\fIpool\fR\fB\&.setdebuglevel(\fR\fIlevel\fR\fB)\fR
-\fIpool\fR\fB\&.setdebuglevel(\fR\fIlevel\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the debug level\&. A value of zero means no debug output, the higher the value, the more output is generated\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint set_flag(int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR
-my \fI$oldvalue\fR \fB=\fR \fI$pool\fR\fB\->set_flag(\fR\fI$flag\fR\fB,\fR \fI$value\fR\fB)\fR;
-\fIoldvalue\fR \fB=\fR \fIpool\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
-\fIoldvalue\fR \fB=\fR \fIpool\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint get_flag(int\fR \fIflag\fR\fB)\fR
-my \fI$value\fR \fB=\fR \fI$pool\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR;
-\fIvalue\fR \fB=\fR \fIpool\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
-\fIvalue\fR \fB=\fR \fIpool\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set/get a pool specific flag\&. The flags define how the system works, e\&.g\&. how the package manager treats obsoletes\&. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if you want to solv package dependencies for some other system than yours\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid set_rootdir(const char *\fR\fIrootdir\fR\fB)\fR
-\fI$pool\fR\fB\->set_rootdir(\fR\fIrootdir\fR\fB)\fR;
-\fIpool\fR\fB\&.set_rootdir(\fR\fIrootdir\fR\fB)\fR
-\fIpool\fR\fB\&.set_rootdir(\fR\fIrootdir\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *get_rootdir()\fR
-my \fI$rootdir\fR \fB=\fR \fI$pool\fR\fB\->get_rootdir()\fR;
-\fIrootdir\fR \fB=\fR \fIpool\fR\fB\&.get_rootdir()\fR
-\fIrootdir\fR \fB=\fR \fIpool\fR\fB\&.get_rootdir()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set/get the rootdir to use\&. This is useful if you want package management to work only in some directory, for example if you want to setup a chroot jail\&. Note that the rootdir will only be prepended to file paths if the \fBREPO_USE_ROOTDIR\fR flag is used\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid setarch(const char *\fR\fIarch\fR \fB= 0)\fR
-\fI$pool\fR\fB\->setarch()\fR;
-\fIpool\fR\fB\&.setarch()\fR
-\fIpool\fR\fB\&.setarch()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the architecture for your system\&. The architecture is used to determine which packages are installable\&. It defaults to the result of \(lquname \-m\(rq\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo add_repo(const char *\fR\fIname\fR\fB)\fR
-\fI$repo\fR \fB=\fR \fI$pool\fR\fB\->add_repo(\fR\fI$name\fR\fB)\fR;
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo(\fR\fIname\fR\fB)\fR
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo(\fR\fIname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a Repository with the specified name to the pool\&. The repository is empty on creation, use the repository methods to populate it with packages\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepoiterator repos_iter()\fR
-\fBfor my\fR \fI$repo\fR \fB(\fR\fI@\fR\fB{\fR\fI$pool\fR\fB\->repos_iter()})\fR
-\fBfor\fR \fIrepo\fR \fBin\fR \fIpool\fR\fB\&.repos_iter():\fR
-\fBfor\fR \fIrepo\fR \fBin\fR \fIpool\fR\fB\&.repos_iter()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over the existing repositories\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvableiterator solvables_iter()\fR
-\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@\fR\fB{\fR\fI$pool\fR\fB\->solvables_iter()})\fR
-\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter():\fR
-\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over the existing solvables\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDep Dep(const char *\fR\fIstr\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
-my \fI$dep\fR \fB=\fR \fI$pool\fR\fB\->Dep(\fR\fI$string\fR\fB)\fR;
-\fIdep\fR \fB=\fR \fIpool\fR\fB\&.Dep(\fR\fIstring\fR\fB)\fR
-\fIdep\fR \fB=\fR \fIpool\fR\fB\&.Dep(\fR\fIstring\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create an object describing a string or dependency\&. If the string is currently not in the pool and \fIcreate\fR is false, \fBundef\fR/\fBNone\fR/\fBnil\fR is returned\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid addfileprovides()\fR
-\fI$pool\fR\fB\->addfileprovides()\fR;
-\fIpool\fR\fB\&.addfileprovides()\fR
-\fIpool\fR\fB\&.addfileprovides()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *addfileprovides_queue()\fR
-my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->addfileprovides_queue()\fR;
-\fIids\fR \fB=\fR \fIpool\fR\fB\&.addfileprovides_queue()\fR
-\fIids\fR \fB=\fR \fIpool\fR\fB\&.addfileprovides_queue()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Some package managers like rpm allow dependencies on files contained in other packages\&. To allow libsolv to deal with those dependencies in an efficient way, you need to call the addfileprovides method after creating and reading all repositories\&. This method will scan all dependency for file names and then scan all packages for matching files\&. If a filename has been matched, it will be added to the provides list of the corresponding package\&. The addfileprovides_queue variant works the same way but returns an array containing all file dependencies\&. This information can be stored in the meta section of the repositories to speed up the next time the repository is loaded and addfileprovides is called\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid createwhatprovides()\fR
-\fI$pool\fR\fB\->createwhatprovides()\fR;
-\fIpool\fR\fB\&.createwhatprovides()\fR
-\fIpool\fR\fB\&.createwhatprovides()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create the internal \(lqwhatprovides\(rq hash over all of the provides of all packages\&. This method must be called before doing any lookups on provides\&. It\(cqs encouraged to do it right after all repos are set up, usually right after the call to addfileprovides()\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *whatprovides(DepId\fR \fIdep\fR\fB)\fR
-my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatprovides(\fR\fI$dep\fR\fB)\fR;
-\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatprovides(\fR\fIdep\fR\fB)\fR
-\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatprovides(\fR\fIdep\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return all solvables that provide the specified dependency\&. You can use either a Dep object or a simple Id as argument\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *matchprovidingids(const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR
-my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->matchprovidingids(\fR\fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Search the names of all provides and return the ones matching the specified string\&. See the Dataiterator class for the allowed flags\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId towhatprovides(Id *\fR\fIids\fR\fB)\fR
-my \fI$offset\fR \fB=\fR \fI$pool\fR\fB\->towhatprovides(\e\fR\fI@ids\fR\fB)\fR;
-\fIoffset\fR \fB=\fR \fIpool\fR\fB\&.towhatprovides(\fR\fIids\fR\fB)\fR
-\fIoffset\fR \fB=\fR \fIpool\fR\fB\&.towhatprovides(\fR\fIids\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-\(lqInternalize\(rq an array containing Ids\&. The returned value can be used to create solver jobs working on a specific set of packages\&. See the Solver class for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool isknownarch(DepId\fR \fIid\fR\fB)\fR
-my \fI$bool\fR \fB=\fR \fI$pool\fR\fB\->isknownarch(\fR\fI$id\fR\fB)\fR;
-\fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch(\fR\fIid\fR\fB)\fR
-\fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch?(\fR\fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if the specified Id describes a known architecture\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolver Solver()\fR
-my \fI$solver\fR \fB=\fR \fI$pool\fR\fB\->Solver()\fR;
-\fIsolver\fR \fB=\fR \fIpool\fR\fB\&.Solver()\fR
-\fIsolver\fR \fB=\fR \fIpool\fR\fB\&.Solver()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a new solver object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBJob Job(int\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR
-my \fI$job\fR \fB=\fR \fI$pool\fR\fB\->Job(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR;
-\fIjob\fR \fB=\fR \fIpool\fR\fB\&.Job(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
-\fIjob\fR \fB=\fR \fIpool\fR\fB\&.Job(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a new Job object\&. Kind of low level, in most cases you would use a Selection or Dep job constructor instead\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection Selection()\fR
-my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->Selection()\fR;
-\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection()\fR
-\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create an empty selection\&. Useful as a starting point for merging other selections\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection Selection_all()\fR
-my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->Selection_all()\fR;
-\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection_all()\fR
-\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection_all()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a selection containing all packages\&. Useful as starting point for intersecting other selections or for update/distupgrade jobs\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection select(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB)\fR
-my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->select(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIsel\fR \fB=\fR \fIpool\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIsel\fR \fB=\fR \fIpool\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a selection by matching packages against the specified string\&. See the Selection class for a list of flags and how to create solver jobs from a selection\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid setpooljobs(Jobs *\fR\fIjobs\fR\fB)\fR
-\fI$pool\fR\fB\->setpooljobs(\e\fR\fI@jobs\fR\fB)\fR;
-\fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR
-\fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBJob *getpooljobs()\fR
-\fI@jobs\fR \fB=\fR \fI$pool\fR\fB\->getpooljobs()\fR;
-\fIjobs\fR \fB=\fR \fIpool\fR\fB\&.getpooljobs()\fR
-\fIjobs\fR \fB=\fR \fIpool\fR\fB\&.getpooljobs()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Get/Set fixed jobs stored in the pool\&. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages can be multiversion installed, which packages were userinstalled or must not be erased\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid set_loadcallback(Callable *\fR\fIcallback\fR\fB)\fR
-\fI$pool\fR\fB\->setloadcallback(\e\fR\fI&callbackfunction\fR\fB)\fR;
-\fIpool\fR\fB\&.setloadcallback(\fR\fIcallbackfunction\fR\fB)\fR
-\fIpool\fR\fB\&.setloadcallback { |\fR\fIrepodata\fR\fB| \&.\&.\&. }\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the callback function called when repository metadata needs to be loaded on demand\&. To make use of this feature, you need to create repodata stubs that tell the library which data is available but not loaded\&. If later on the data needs to be accessed, the callback function is called with a repodata argument\&. You can then load the data (maybe fetching it first from a remote server)\&. The callback should return true if the data has been made available\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-/* bindings only */
-\fI$pool\fR\fB\->appdata_disown()\fR
-\fIpool\fR\fB\&.appdata_disown()\fR
-\fIpool\fR\fB\&.appdata_disown()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Decrement the reference count of the appdata object\&. This can be used to break circular references (e\&.g\&. if the pool\(cqs appdata value points to some meta data structure that contains a pool handle)\&. If used incorrectly, this method can lead to application crashes, so beware\&. (This method is a no\-op for ruby and tcl\&.)
-.SS "DATA RETRIEVAL METHODS"
-.sp
-In the following functions, the \fIkeyname\fR argument describes what to retrieve\&. For the standard cases you can use the available Id constants\&. For example,
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB$solv::SOLVABLE_SUMMARY\fR
-\fBsolv\&.SOLVABLE_SUMMARY\fR
-\fBSolv::SOLVABLE_SUMMARY\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-selects the \(lqSummary\(rq entry of a solvable\&. The \fIsolvid\fR argument selects the desired solvable by Id\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$string\fR \fB=\fR \fI$pool\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIstring\fR \fB=\fR \fIpool\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIstring\fR \fB=\fR \fIpool\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$id\fR \fB=\fR \fI$pool\fR\fB\->lookup_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
-my \fI$num\fR \fB=\fR \fI$pool\fR\fB\->lookup_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fInum\fR \fB=\fR \fIpool\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fInum\fR \fB=\fR \fIpool\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool lookup_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$bool\fR \fB=\fR \fI$pool\fR\fB\->lookup_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIbool\fR \fB=\fR \fIpool\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIbool\fR \fB=\fR \fIpool\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *lookup_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIids\fR \fB=\fR \fIpool\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIids\fR \fB=\fR \fIpool\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum lookup_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$chksum\fR \fB=\fR \fI$pool\fR\fB\->lookup_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIchksum\fR \fB=\fR \fIpool\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIchksum\fR \fB=\fR \fIpool\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Lookup functions\&. Return the data element stored in the specified solvable\&. You should probably use the methods of the Solvable class instead\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$di\fR \fB=\fR \fI$pool\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator Dataiterator_solvid(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$di\fR \fB=\fR \fI$pool\fR\fB\->Dataiterator(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over the matching data elements\&. See the Dataiterator class for more information\&. The Dataiterator method iterates over all solvables in the pool, whereas the Dataiterator_solvid only iterates over the specified solvable\&.
-.SS "ID METHODS"
-.sp
-The following methods deal with Ids, i\&.e\&. integers representing objects in the pool\&. They are considered \(lqlow level\(rq, in most cases you would not use them but instead the object orientated methods\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo id2repo(Id\fR \fIid\fR\fB)\fR
-\fI$repo\fR \fB=\fR \fI$pool\fR\fB\->id2repo(\fR\fI$id\fR\fB)\fR;
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.id2repo(\fR\fIid\fR\fB)\fR
-\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.id2repo(\fR\fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Lookup an existing Repository by id\&. You can also do this by using the \fBrepos\fR attribute\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable id2solvable(Id\fR \fIid\fR\fB)\fR
-\fI$solvable\fR \fB=\fR \fI$pool\fR\fB\->id2solvable(\fR\fI$id\fR\fB)\fR;
-\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.id2solvable(\fR\fIid\fR\fB)\fR
-\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.id2solvable(\fR\fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Lookup an existing Repository by id\&. You can also do this by using the \fBsolvables\fR attribute\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *solvid2str(Id\fR \fIid\fR\fB)\fR
-my \fI$str\fR \fB=\fR \fI$pool\fR\fB\->solvid2str(\fR\fI$id\fR\fB)\fR;
-\fIstr\fR \fB=\fR \fIpool\fR\fB\&.solvid2str(\fR\fIid\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIpool\fR\fB\&.solvid2str(\fR\fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string describing the Solvable with the specified id\&. The string consists of the name, version, and architecture of the Solvable\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId str2id(const char *\fR\fIstr\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
-my \fI$id\fR \fB=\fR \fIpool\fR\fB\->str2id(\fR\fI$string\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.str2id(\fR\fIstring\fR\fB)\fR
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.str2id(\fR\fIstring\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *id2str(Id\fR \fIid\fR\fB)\fR
-\fI$string\fR \fB=\fR \fIpool\fR\fB\->id2str(\fR\fI$id\fR\fB)\fR;
-\fIstring\fR \fB=\fR \fIpool\fR\fB\&.id2str(\fR\fIid\fR\fB)\fR
-\fIstring\fR \fB=\fR \fIpool\fR\fB\&.id2str(\fR\fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a string into an Id and back\&. If the string is currently not in the pool and \fIcreate\fR is false, zero is returned\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId rel2id(Id\fR \fIname\fR\fB, Id\fR \fIevr\fR\fB, int\fR \fIflags\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
-my \fI$id\fR \fB=\fR \fIpool\fR\fB\->rel2id(\fR\fI$nameid\fR\fB,\fR \fI$evrid\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.rel2id(\fR\fInameid\fR\fB,\fR \fIevrid\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.rel2id(\fR\fInameid\fR\fB,\fR \fIevrid\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a \(lqrelational\(rq dependency\&. Such dependencies consist of a name part, the \fIflags\fR describing the relation, and a version part\&. The flags are:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB$solv::REL_EQ | $solv::REL_GT | $solv::REL_LT\fR
-\fBsolv\&.REL_EQ | solv\&.REL_GT | solv\&.REL_LT\fR
-\fBSolv::REL_EQ | Solv::REL_GT | Solv::REL_LT\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Thus, if you want a \(lq<=\(rq relation, you would use \fBREL_LT | REL_EQ\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id2langid(Id\fR \fIid\fR\fB, const char *\fR\fIlang\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
-my \fI$id\fR \fB=\fR \fI$pool\fR\fB\->id2langid(\fR\fI$id\fR\fB,\fR \fI$language\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.id2langid(\fR\fIid\fR\fB,\fR \fIlanguage\fR\fB)\fR
-\fIid\fR \fB=\fR \fIpool\fR\fB\&.id2langid(\fR\fIid\fR\fB,\fR \fIlanguage\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a language specific Id from some other id\&. This function simply converts the id into a string, appends a dot and the specified language to the string and converts the result back into an Id\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *dep2str(Id\fR \fIid\fR\fB)\fR
-\fI$string\fR \fB=\fR \fIpool\fR\fB\->dep2str(\fR\fI$id\fR\fB)\fR;
-\fIstring\fR \fB=\fR \fIpool\fR\fB\&.dep2str(\fR\fIid\fR\fB)\fR
-\fIstring\fR \fB=\fR \fIpool\fR\fB\&.dep2str(\fR\fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a dependency id into a string\&. If the id is just a string, this function has the same effect as id2str()\&. For relational dependencies, the result is the correct \(lqname relation evr\(rq string\&.
-.SH "THE DEPENDENCY CLASS"
-.sp
-The dependency class is an object orientated way to work with strings and dependencies\&. Internally, dependencies are represented as Ids, i\&.e\&. simple numbers\&. Dependency objects can be constructed by using the Pool\(cqs Dep() method\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR             /* read only */
-\fI$dep\fR\fB\->{pool}\fR
-\fIdep\fR\fB\&.pool\fR
-\fIdep\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back reference to the pool this dependency belongs to\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR          /* read only */
-\fI$dep\fR\fB\->{id}\fR
-\fIdep\fR\fB\&.id\fR
-\fIdep\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of this dependency\&.
-.SH "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDep Rel(int\fR \fIflags\fR\fB, DepId\fR \fIevrid\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
-my \fI$reldep\fR \fB=\fR \fI$dep\fR\fB\->Rel(\fR\fI$flags\fR\fB,\fR \fI$evrdep\fR\fB)\fR;
-\fIreldep\fR \fB=\fR \fIdep\fR\fB\&.Rel(\fR\fIflags\fR\fB,\fR \fIevrdep\fR\fB)\fR
-\fIreldep\fR \fB=\fR \fIdep\fR\fB\&.Rel(\fR\fIflags\fR\fB,\fR \fIevrdep\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a relational dependency from to string dependencies and a flags argument\&. See the pool\(cqs rel2id method for a description of the flags\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection Selection_name(int\fR \fIsetflags\fR \fB= 0)\fR
-my \fI$sel\fR \fB=\fR \fI$dep\fR\fB\->Selection_name()\fR;
-\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_name()\fR
-\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_name()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a Selection from a dependency\&. The selection consists of all packages that have a name equal to the dependency\&. If the dependency is of a relational type, the packages version must also fulfill the dependency\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection Selection_provides(int\fR \fIsetflags\fR \fB= 0)\fR
-my \fI$sel\fR \fB=\fR \fI$dep\fR\fB\->Selection_provides()\fR;
-\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_provides()\fR
-\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_provides()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a Selection from a dependency\&. The selection consists of all packages that have at least one provides matching the dependency\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *str()\fR
-my \fI$str\fR \fB=\fR \fI$dep\fR\fB\->str()\fR;
-\fIstr\fR \fB=\fR \fI$dep\fR\fB\&.str()\fR
-\fIstr\fR \fB=\fR \fI$dep\fR\fB\&.str()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string describing the dependency\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$dep\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIdep\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIdep\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as calling the str() method\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$dep1\fR \fB==\fR \fI$dep2\fR\fB)\fR
-\fBif\fR \fIdep1\fR \fB==\fR \fIdep2\fR\fB:\fR
-\fBif\fR \fIdep1\fR \fB==\fR \fIdep2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The dependencies are equal if they are part of the same pool and have the same ids\&.
-.SH "THE REPOSITORY CLASS"
-.sp
-A Repository describes a group of packages, normally coming from the same source\&. Repositories are created by the Pool\(cqs add_repo() method\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                     /* read only */
-\fI$repo\fR\fB\->{pool}\fR
-\fIrepo\fR\fB\&.pool\fR
-\fIrepo\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back reference to the pool this dependency belongs to\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                          /* read only */
-\fI$repo\fR\fB\->{id}\fR
-\fIrepo\fR\fB\&.id\fR
-\fIrepo\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *name;\fR               /* read/write */
-\fI$repo\fR\fB\->{name}\fR
-\fIrepo\fR\fB\&.name\fR
-\fIrepo\fR\fB\&.name\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The repositories name\&. To libsolv, the name is just a string with no specific meaning\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint priority;\fR                   /* read/write */
-\fI$repo\fR\fB\->{priority}\fR
-\fIrepo\fR\fB\&.priority\fR
-\fIrepo\fR\fB\&.priority\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The priority of the repository\&. A higher number means that packages of this repository will be chosen over other repositories, even if they have a greater package version\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint subpriority;\fR                /* read/write */
-\fI$repo\fR\fB\->{subpriority}\fR
-\fIrepo\fR\fB\&.subpriority\fR
-\fIrepo\fR\fB\&.subpriority\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The sub\-priority of the repository\&. This value is compared when the priorities of two repositories are the same\&. It is useful to make the library prefer on\-disk repositories to remote ones\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint nsolvables;\fR                 /* read only */
-\fI$repo\fR\fB\->{nsolvables}\fR
-\fIrepo\fR\fB\&.nsolvables\fR
-\fIrepo\fR\fB\&.nsolvables\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The number of solvables in this repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid *appdata;\fR                  /* read/write */
-\fI$repo\fR\fB\->{appdata}\fR
-\fIrepo\fR\fB\&.appdata\fR
-\fIrepo\fR\fB\&.appdata\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Application specific data that may be used in any way by the code using the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDatapos *meta;\fR                  /* read only */
-\fI$repo\fR\fB\->{meta}\fR
-\fIrepo\fR\fB\&.meta\fR
-\fIrepo\fR\fB\&.meta\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a Datapos object of the repodata\(cqs metadata\&. You can use the lookup methods of the Datapos class to lookup metadata attributes, like the repository timestamp\&.
-.SS "CONSTANTS"
-.PP
-\fBREPO_REUSE_REPODATA\fR
-.RS 4
-Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new one\&.
-.RE
-.PP
-\fBREPO_NO_INTERNALIZE\fR
-.RS 4
-Do not internalize the added repository data\&. This is useful if you plan to add more data because internalization is a costly operation\&.
-.RE
-.PP
-\fBREPO_LOCALPOOL\fR
-.RS 4
-Use the repodata\(cqs pool for Id storage instead of the global pool\&. Useful if you don\(cqt want to pollute the global pool with many unneeded ids, like when storing the filelist\&.
-.RE
-.PP
-\fBREPO_USE_LOADING\fR
-.RS 4
-Use the repodata that is currently being loaded instead of creating a new one\&. This only makes sense if used in a load callback\&.
-.RE
-.PP
-\fBREPO_EXTEND_SOLVABLES\fR
-.RS 4
-Do not create new solvables for the new data, but match existing solvables and add the data to them\&. Repository metadata is often split into multiple parts, with one primary file describing all packages and other parts holding information that is normally not needed, like the changelog\&.
-.RE
-.PP
-\fBREPO_USE_ROOTDIR\fR
-.RS 4
-Prepend the pool\(cqs rootdir to the path when doing file operations\&.
-.RE
-.PP
-\fBREPO_NO_LOCATION\fR
-.RS 4
-Do not add a location element to the solvables\&. Useful if the solvables are not in the final position, so you can add the correct location later in your code\&.
-.RE
-.PP
-\fBSOLV_ADD_NO_STUBS\fR
-.RS 4
-Do not create stubs for repository parts that can be downloaded on demand\&.
-.RE
-.PP
-\fBSUSETAGS_RECORD_SHARES\fR
-.RS 4
-This is specific to the add_susetags() method\&. Susetags allows one to refer to already read packages to save disk space\&. If this data sharing needs to work over multiple calls to add_susetags, you need to specify this flag so that the share information is made available to subsequent calls\&.
-.RE
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid free(bool\fR \fIreuseids\fR \fB= 0)\fR
-\fI$repo\fR\fB\->free()\fR;
-\fIrepo\fR\fB\&.free()\fR
-\fIrepo\fR\fB\&.free()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Free the repository and all solvables it contains\&. If \fIreuseids\fR is set to true, the solvable ids and the repository id may be reused by the library when added new solvables\&. Thus you should leave it false if you are not sure that somebody holds a reference\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid empty(bool\fR \fIreuseids\fR \fB= 0)\fR
-\fI$repo\fR\fB\->empty()\fR;
-\fIrepo\fR\fB\&.empty()\fR
-\fIrepo\fR\fB\&.empty()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Free all the solvables in a repository\&. The repository will be empty after this call\&. See the free() method for the meaning of \fIreuseids\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool isempty()\fR
-\fI$repo\fR\fB\->isempty()\fR
-\fIrepo\fR\fB\&.empty()\fR
-\fIrepo\fR\fB\&.empty?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if there are no solvables in this repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid internalize()\fR
-\fI$repo\fR\fB\->internalize()\fR;
-\fIrepo\fR\fB\&.internalize()\fR
-\fIrepo\fR\fB\&.internalize()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Internalize added data\&. Data must be internalized before it is available to the lookup and data iterator functions\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool write(FILE *\fR\fIfp\fR\fB)\fR
-\fI$repo\fR\fB\->write(\fR\fI$fp\fR\fB)\fR
-\fIrepo\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Write a repo as a \(lqsolv\(rq file\&. These files can be read very fast and thus are a good way to cache repository data\&. Returns false if there was some error writing the file\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvableiterator solvables_iter()\fR
-\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@\fR\fB{\fR\fI$repo\fR\fB\->solvables_iter()})\fR
-\fBfor\fR \fIsolvable\fR \fBin\fR \fIrepo\fR\fB\&.solvables_iter():\fR
-\fBfor\fR \fIsolvable\fR \fBin\fR \fIrepo\fR\fB\&.solvables_iter()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over all solvables in a repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepodata add_repodata(int\fR \fIflags\fR \fB= 0)\fR
-my \fI$repodata\fR \fB=\fR \fI$repo\fR\fB\->add_repodata()\fR;
-\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.add_repodata()\fR
-\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.add_repodata()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a new repodata area to the repository\&. This is normally automatically done by the repo_add methods, so you need this method only in very rare circumstances\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid create_stubs()\fR
-\fI$repo\fR\fB\->create_stubs()\fR;
-\fIrepo\fR\fB\&.create_stubs()\fR
-\fIrepo\fR\fB\&.create_stubs()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Calls the create_stubs() repodata method for the last repodata of the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool iscontiguous()\fR
-\fI$repo\fR\fB\->iscontiguous()\fR
-\fIrepo\fR\fB\&.iscontiguous()\fR
-\fIrepo\fR\fB\&.iscontiguous?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if the solvables of this repository are all in a single block with no holes, i\&.e\&. they have consecutive ids\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepodata first_repodata()\fR
-my \fI$repodata\fR \fB=\fR \fI$repo\fR\fB\->first_repodata()\fR;
-\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.first_repodata()\fR
-\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.first_repodata()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Checks if all repodatas but the first repodata are extensions, and return the first repodata if this is the case\&. Useful if you want to do a store/retrieve sequence on the repository to reduce the memory using and enable paging, as this does not work if the repository contains multiple non\-extension repodata areas\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection Selection(int\fR \fIsetflags\fR \fB= 0)\fR
-my \fI$sel\fR \fB=\fR \fI$repo\fR\fB\->Selection()\fR;
-\fIsel\fR \fB=\fR \fIrepo\fR\fB\&.Selection()\fR
-\fIsel\fR \fB=\fR \fIrepo\fR\fB\&.Selection()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a Selection consisting of all packages in the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator Dataiterator(Id\fR \fIkey\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$di\fR \fB=\fR \fI$repo\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator Dataiterator_meta(Id\fR \fIkey\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$di\fR \fB=\fR \fI$repo\fR\fB\->Dataiterator_meta(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator_meta(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator_meta(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over the matching data elements in this repository\&. See the Dataiterator class for more information\&. The Dataiterator() method iterates over all solvables in a repository, whereas the Dataiterator_meta method only iterates over the repository\(cqs meta data\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$repo\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIrepo\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIrepo\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the name of the repository, or "Repo#<id>" if no name is set\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$repo1\fR \fB==\fR \fI$repo2\fR\fB)\fR
-\fBif\fR \fIrepo1\fR \fB==\fR \fIrepo2\fR\fB:\fR
-\fBif\fR \fIrepo1\fR \fB==\fR \fIrepo2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Two repositories are equal if they belong to the same pool and have the same id\&.
-.SS "DATA ADD METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable add_solvable()\fR
-\fI$repo\fR\fB\->add_solvable()\fR;
-\fIrepo\fR\fB\&.add_solvable()\fR
-\fIrepo\fR\fB\&.add_solvable()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a single empty solvable to the repository\&. Returns a Solvable object, see the Solvable class for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_solv(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_solv(\fR\fI$name\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_solv(\fR\fIname\fR\fB)\fR
-\fIrepo\fR\fB\&.add_solv(\fR\fIname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Read a \(lqsolv\(rq file and add its contents to the repository\&. These files can be written with the write() method and are normally used as fast cache for repository metadata\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_rpmdb(int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_rpmdb()\fR;
-\fIrepo\fR\fB\&.add_rpmdb()\fR
-\fIrepo\fR\fB\&.add_rpmdb()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_rpmdb_reffp(FILE *\fR\fIreffp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_rpmdb_reffp(\fR\fI$reffp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_rpmdb_reffp(\fR\fIreffp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_rpmdb_reffp(\fR\fIreffp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the rpm database to the repository\&. If a solv file containing an old version of the database is available, it can be passed as reffp to speed up reading\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable add_rpm(const char *\fR\fIfilename\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_rpm(\fR\fI$filename\fR\fB)\fR;
-\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_rpm(\fR\fIfilename\fR\fB)\fR
-\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_rpm(\fR\fIfilename\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the metadata of a single rpm package to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_rpmdb_pubkeys(int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_rpmdb_pubkeys()\fR;
-\fIrepo\fR\fB\&.add_rpmdb_pubkeys()\fR
-\fIrepo\fR\fB\&.add_rpmdb_pubkeys()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add all pubkeys contained in the rpm database to the repository\&. Note that newer rpm versions also allow to store the pubkeys in some directory instead of the rpm database\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable add_pubkey(const char *\fR\fIkeyfile\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_pubkey(\fR\fI$keyfile\fR\fB)\fR;
-\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_pubkey(\fR\fIkeyfile\fR\fB)\fR
-\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_pubkey(\fR\fIkeyfile\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a pubkey from a file to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_rpmmd(FILE *\fR\fIfp\fR\fB, const char *\fR\fIlanguage\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_rpmmd(\fR\fI$fp\fR\fB,\fR \fIundef\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_rpmmd(\fR\fIfp\fR\fB,\fR \fINone\fR\fB)\fR
-\fIrepo\fR\fB\&.add_rpmmd(\fR\fIfp\fR\fB,\fR \fInil\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add metadata stored in the "rpm\-md" format (i\&.e\&. from files in the \(lqrepodata\(rq directory) to a repository\&. Supported files are "primary", "filelists", "other", "suseinfo"\&. Do not forget to specify the \fBREPO_EXTEND_SOLVABLES\fR for extension files like "filelists" and "other"\&. Use the \fIlanguage\fR parameter if you have language extension files, otherwise simply use a \fBundef\fR/\fBNone\fR/\fBnil\fR parameter\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_repomdxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_repomdxml(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_repomdxml(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_repomdxml(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the repomd\&.xml meta description from the "rpm\-md" format to the repository\&. This file contains information about the repository like keywords, and also a list of all database files with checksums\&. The data is added to the "meta" section of the repository, i\&.e\&. no package gets created\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_updateinfoxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_updateinfoxml(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_updateinfoxml(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_updateinfoxml(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the updateinfo\&.xml file containing available maintenance updates to the repository\&. All updates are created as special packages that have a "patch:" prefix in their name\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_deltainfoxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_deltainfoxml(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_deltainfoxml(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_deltainfoxml(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the deltainfo\&.xml file (also called prestodelta\&.xml) containing available delta\-rpms to the repository\&. The data is added to the "meta" section, i\&.e\&. no package gets created\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_debdb(int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_debdb()\fR;
-\fIrepo\fR\fB\&.add_debdb()\fR
-\fIrepo\fR\fB\&.add_debdb()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the debian installed package database to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_debpackages(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_debpackages(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_debpackages(\fR\fI$fp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_debpackages(\fR\fI$fp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the debian repository metadata (the "packages" file) to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable add_deb(const char *\fR\fIfilename\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_deb(\fR\fI$filename\fR\fB)\fR;
-\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_deb(\fR\fIfilename\fR\fB)\fR
-\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_deb(\fR\fIfilename\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the metadata of a single deb package to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_mdk(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_mdk(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the mageia/mandriva repository metadata (the "synthesis\&.hdlist" file) to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_mdk_info(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_mdk(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Extend the packages from the synthesis file with the info\&.xml and files\&.xml data\&. Do not forget to specify \fBREPO_EXTEND_SOLVABLES\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_arch_repo(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_arch_repo(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_arch_repo(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_arch_repo(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the archlinux repository metadata (the "\&.db\&.tar" file) to the repository\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_arch_local(const char *\fR\fIdir\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_arch_local(\fR\fI$dir\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_arch_local(\fR\fIdir\fR\fB)\fR
-\fIrepo\fR\fB\&.add_arch_local(\fR\fIdir\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the archlinux installed package database to the repository\&. The \fIdir\fR parameter is usually set to "/var/lib/pacman/local"\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_content(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_content(\fR\fI$fp\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_content(\fR\fIfp\fR\fB)\fR
-\fIrepo\fR\fB\&.add_content(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the \(lqcontent\(rq meta description from the susetags format to the repository\&. This file contains information about the repository like keywords, and also a list of all database files with checksums\&. The data is added to the "meta" section of the repository, i\&.e\&. no package gets created\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_susetags(FILE *\fR\fIfp\fR\fB, Id\fR \fIdefvendor\fR\fB, const char *\fR\fIlanguage\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_susetags(\fR\fI$fp\fR\fB,\fR \fI$defvendor\fR\fB,\fR \fI$language\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_susetags(\fR\fIfp\fR\fB,\fR \fIdefvendor\fR\fB,\fR \fIlanguage\fR\fB)\fR
-\fIrepo\fR\fB\&.add_susetags(\fR\fIfp\fR\fB,\fR \fIdefvendor\fR\fB,\fR \fIlanguage\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add repository metadata in the susetags format to the repository\&. Like with add_rpmmd, you can specify a language if you have language extension files\&. The \fIdefvendor\fR parameter provides a default vendor for packages with missing vendors, it is usually provided in the content file\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_products(const char *\fR\fIdir\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
-\fI$repo\fR\fB\->add_products(\fR\fI$dir\fR\fB)\fR;
-\fIrepo\fR\fB\&.add_products(\fR\fIdir\fR\fB)\fR
-\fIrepo\fR\fB\&.add_products(\fR\fIdir\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the installed SUSE products database to the repository\&. The \fIdir\fR parameter is usually "/etc/products\&.d"\&.
-.SH "THE SOLVABLE CLASS"
-.sp
-A solvable describes all the information of one package\&. Each solvable belongs to one repository, it can be added and filled manually but in most cases solvables will get created by the repo_add methods\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo *repo;\fR                     /* read only */
-\fI$solvable\fR\fB\->{repo}\fR
-\fIsolvable\fR\fB\&.repo\fR
-\fIsolvable\fR\fB\&.repo\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The repository this solvable belongs to\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                     /* read only */
-\fI$solvable\fR\fB\->{pool}\fR
-\fIsolvable\fR\fB\&.pool\fR
-\fIsolvable\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The pool this solvable belongs to, same as the pool of the repo\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                          /* read only */
-\fI$solvable\fR\fB\->{id}\fR
-\fIsolvable\fR\fB\&.id\fR
-\fIsolvable\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The specific id of the solvable\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *name;\fR                     /* read/write */
-\fI$solvable\fR\fB\->{name}\fR
-\fIsolvable\fR\fB\&.name\fR
-\fIsolvable\fR\fB\&.name\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *evr;\fR                      /* read/write */
-\fI$solvable\fR\fB\->{evr}\fR
-\fIsolvable\fR\fB\&.evr\fR
-\fIsolvable\fR\fB\&.evr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *arch;\fR                     /* read/write */
-\fI$solvable\fR\fB\->{arch}\fR
-\fIsolvable\fR\fB\&.arch\fR
-\fIsolvable\fR\fB\&.arch\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *vendor;\fR                   /* read/write */
-\fI$solvable\fR\fB\->{vendor}\fR
-\fIsolvable\fR\fB\&.vendor\fR
-\fIsolvable\fR\fB\&.vendor\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Easy access to often used attributes of solvables\&. They are internally stored as Ids\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId nameid;\fR                      /* read/write */
-\fI$solvable\fR\fB\->{nameid}\fR
-\fIsolvable\fR\fB\&.nameid\fR
-\fIsolvable\fR\fB\&.nameid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId evrid;\fR                       /* read/write */
-\fI$solvable\fR\fB\->{evrid}\fR
-\fIsolvable\fR\fB\&.evrid\fR
-\fIsolvable\fR\fB\&.evrid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId archid;\fR                      /* read/write */
-\fI$solvable\fR\fB\->{archid}\fR
-\fIsolvable\fR\fB\&.archid\fR
-\fIsolvable\fR\fB\&.archid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId vendorid;\fR                    /* read/write */
-\fI$solvable\fR\fB\->{vendorid}\fR
-\fIsolvable\fR\fB\&.vendorid\fR
-\fIsolvable\fR\fB\&.vendorid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Raw interface to the ids\&. Useful if you want to search for a specific id and want to avoid the string compare overhead\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_str(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$string\fR \fB=\fR \fI$solvable\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\fR;
-\fIstring\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
-\fIstring\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId lookup_id(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$id\fR \fB=\fR \fI$solvable\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB)\fR
-\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
-my \fI$num\fR \fB=\fR \fI$solvable\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR;
-\fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
-\fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool lookup_void(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$bool\fR \fB=\fR \fI$solvable\fR\fB\->lookup_void(\fR\fI$keyname\fR\fB)\fR;
-\fIbool\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
-\fIbool\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum lookup_checksum(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$chksum\fR \fB=\fR \fI$solvable\fR\fB\->lookup_checksum(\fR\fI$keyname\fR\fB)\fR;
-\fIchksum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
-\fIchksum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *lookup_idarray(Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
-my \fI@ids\fR \fB=\fR \fI$solvable\fR\fB\->lookup_idarray(\fR\fI$keyname\fR\fB)\fR;
-\fIids\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
-\fIids\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDep *lookup_deparray(Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
-my \fI@deps\fR \fB=\fR \fI$solvable\fR\fB\->lookup_deparray(\fR\fI$keyname\fR\fB)\fR;
-\fIdeps\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_deparray(\fR\fIkeyname\fR\fB)\fR
-\fIdeps\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_deparray(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Generic lookup methods\&. Retrieve data stored for the specific keyname\&. The lookup_idarray() method will return an array of Ids, use lookup_deparray if you want an array of Dependency objects instead\&. Some Id arrays contain two parts of data divided by a specific marker, for example the provides array uses the SOLVABLE_FILEMARKER id to store both the ids provided by the package and the ids added by the addfileprovides method\&. The default, \-1, translates to the correct marker for the keyname and returns the first part of the array, use 1 to select the second part or 0 to retrieve all ids including the marker\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_location(unsigned int *\fR\fIOUTPUT\fR\fB)\fR;
-my \fB(\fR\fI$location\fR\fB,\fR \fI$medianr\fR\fB) =\fR \fI$solvable\fR\fB\->lookup_location()\fR;
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a tuple containing the on\-media location and an optional media number for multi\-part repositories (e\&.g\&. repositories spawning multiple DVDs)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$di\fR \fB=\fR \fI$solvable\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIsolvable\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIsolvable\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over the matching data elements\&. See the Dataiterator class for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_deparray(Id\fR \fIkeyname\fR\fB, DepId\fR \fIdep\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR;
-\fI$solvable\fR\fB\->add_deparray(\fR\fI$keyname\fR\fB,\fR \fI$dep\fR\fB)\fR;
-\fIsolvable\fR\fB\&.add_deparray(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR
-\fIsolvable\fR\fB\&.add_deparray(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a new dependency to the attributes stored in keyname\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid unset(Id\fR \fIkeyname\fR\fB)\fR;
-\fI$solvable\fR\fB\->unset(\fR\fI$keyname\fR\fB)\fR;
-\fIsolvable\fR\fB\&.unset(\fR\fIkeyname\fR\fB)\fR
-\fIsolvable\fR\fB\&.unset(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Delete data stored for the specific keyname\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool installable()\fR;
-\fI$solvable\fR\fB\->installable()\fR
-\fIsolvable\fR\fB\&.installable()\fR
-\fIsolvable\fR\fB\&.installable?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if the solvable is installable on the system\&. Solvables are not installable if the system does not support their architecture\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool isinstalled()\fR;
-\fI$solvable\fR\fB\->isinstalled()\fR
-\fIsolvable\fR\fB\&.isinstalled()\fR
-\fIsolvable\fR\fB\&.isinstalled?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if the solvable is installed on the system\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool identical(Solvable *\fR\fIother\fR\fB)\fR
-\fI$solvable\fR\fB\->identical(\fR\fI$other\fR\fB)\fR
-\fI$solvable\fR\fB\&.identical(\fR\fIother\fR\fB)\fR
-\fI$solvable\fR\fB\&.identical?(\fR\fIother\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if the two solvables are identical\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint evrcmp(Solvable *\fR\fIother\fR\fB)\fR
-\fI$solvable\fR\fB\->evrcmp(\fR\fIother\fR\fB)\fR
-\fI$solvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR
-\fI$solvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Returns \-1 if the epoch/version/release of the solvable is less than the one from the other solvable, 1 if it is greater, and 0 if they are equal\&. Note that "equal" does not mean that the evr is identical\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSelection Selection(int\fR \fIsetflags\fR \fB= 0)\fR
-my \fI$sel\fR \fB=\fR \fI$solvable\fR\fB\->Selection()\fR;
-\fIsel\fR \fB=\fR \fIsolvable\fR\fB\&.Selection()\fR
-\fIsel\fR \fB=\fR \fIsolvable\fR\fB\&.Selection()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a Selection containing just the single solvable\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *str()\fR
-my \fI$str\fR \fB=\fR \fI$solvable\fR\fB\->str()\fR;
-\fIstr\fR \fB=\fR \fI$solvable\fR\fB\&.str()\fR
-\fIstr\fR \fB=\fR \fI$solvable\fR\fB\&.str()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string describing the solvable\&. The string consists of the name, version, and architecture of the Solvable\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$solvable\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIsolvable\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIsolvable\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as calling the str() method\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$solvable1\fR \fB==\fR \fI$solvable2\fR\fB)\fR
-\fBif\fR \fIsolvable1\fR \fB==\fR \fIsolvable2\fR\fB:\fR
-\fBif\fR \fIsolvable1\fR \fB==\fR \fIsolvable2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Two solvables are equal if they are part of the same pool and have the same ids\&.
-.SH "THE DATAITERATOR CLASS"
-.sp
-Dataiterators can be used to do complex string searches or to iterate over arrays\&. They can be created via the constructors in the Pool, Repo, and Solvable classes\&. The Repo and Solvable constructors will limit the search to the repository or the specific package\&.
-.SS "CONSTANTS"
-.PP
-\fBSEARCH_STRING\fR
-.RS 4
-Return a match if the search string matches the value\&.
-.RE
-.PP
-\fBSEARCH_STRINGSTART\fR
-.RS 4
-Return a match if the value starts with the search string\&.
-.RE
-.PP
-\fBSEARCH_STRINGEND\fR
-.RS 4
-Return a match if the value ends with the search string\&.
-.RE
-.PP
-\fBSEARCH_SUBSTRING\fR
-.RS 4
-Return a match if the search string can be matched somewhere in the value\&.
-.RE
-.PP
-\fBSEARCH_GLOB\fR
-.RS 4
-Do a glob match of the search string against the value\&.
-.RE
-.PP
-\fBSEARCH_REGEX\fR
-.RS 4
-Do a regular expression match of the search string against the value\&.
-.RE
-.PP
-\fBSEARCH_NOCASE\fR
-.RS 4
-Ignore case when matching strings\&. Works for all the above match types\&.
-.RE
-.PP
-\fBSEARCH_FILES\fR
-.RS 4
-Match the complete filenames of the file list, not just the base name\&.
-.RE
-.PP
-\fBSEARCH_COMPLETE_FILELIST\fR
-.RS 4
-When matching the file list, check every file of the package not just the subset from the primary metadata\&.
-.RE
-.PP
-\fBSEARCH_CHECKSUMS\fR
-.RS 4
-Allow the matching of checksum entries\&.
-.RE
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid prepend_keyname(Id\fR \fIkeyname\fR\fB)\fR;
-\fI$di\fR\fB\->prepend_keyname(\fR\fI$keyname\fR\fB)\fR;
-\fIdi\fR\fB\&.prepend_keyname(\fR\fIkeyname\fR\fB)\fR
-\fIdi\fR\fB\&.prepend_keyname(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Do a sub\-search in the array stored in keyname\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid skip_solvable()\fR;
-\fI$di\fR\fB\->kip_solvable()\fR;
-\fIdi\fR\fB\&.skip_solvable()\fR
-\fIdi\fR\fB\&.skip_solvable()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Stop matching the current solvable and advance to the next one\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<iteration>\fR
-\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate through the matches\&. If there is a match, the object in d will be of type Datamatch\&.
-.SH "THE DATAMATCH CLASS"
-.sp
-Objects of this type will be created for every value matched by a dataiterator\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                             /* read only */
-\fI$d\fR\fB\->{pool}\fR
-\fId\fR\fB\&.pool\fR
-\fId\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo *repo;\fR                             /* read only */
-\fI$d\fR\fB\->{repo}\fR
-\fId\fR\fB\&.repo\fR
-\fId\fR\fB\&.repo\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The repository containing the matched object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *solvable;\fR                     /* read only */
-\fI$d\fR\fB\->{solvable}\fR
-\fId\fR\fB\&.solvable\fR
-\fId\fR\fB\&.solvable\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The solvable containing the value that was matched\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId solvid;\fR                              /* read only */
-\fI$d\fR\fB\->{solvid}\fR
-\fId\fR\fB\&.solvid\fR
-\fId\fR\fB\&.solvid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of the solvable that matched\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId\fR \fIkey_id\fR;
-\fI$d\fR\fB\->{\fR\fIkey_id\fR\fB}\fR
-\fId\fR\fB\&.key_id\fR
-\fId\fR\fB\&.key_id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *\fR\fIkey_idstr\fR;
-\fI$d\fR\fB\->{\fR\fIkey_idstr\fR\fB}\fR
-\fId\fR\fB\&.key_idstr\fR
-\fId\fR\fB\&.key_idstr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The keyname that matched, either as id or string\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId\fR \fItype_id\fR;
-\fI$d\fR\fB\->{\fR\fItype_id\fR\fB}\fR
-\fId\fR\fB\&.type_id\fR
-\fId\fR\fB\&.type_id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *\fR\fItype_idstr\fR;
-\fI$d\fR\fB\->{\fR\fItype_idstr\fR\fB}\fR;
-\fId\fR\fB\&.type_idstr\fR
-\fId\fR\fB\&.type_idstr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The key type of the value that was matched, either as id or string\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId\fR \fIid\fR;
-\fI$d\fR\fB\->{id}\fR
-\fId\fR\fB\&.id\fR
-\fId\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId\fR \fIidstr\fR;
-\fI$d\fR\fB\->{idstr}\fR
-\fId\fR\fB\&.idstr\fR
-\fId\fR\fB\&.idstr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The Id of the value that was matched (only valid for id types), either as id or string\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *\fR\fIstr\fR;
-\fI$d\fR\fB\->{str}\fR
-\fId\fR\fB\&.str\fR
-\fId\fR\fB\&.str\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The string value that was matched (only valid for string types)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned long long\fR \fInum\fR;
-\fI$d\fR\fB\->{num}\fR
-\fId\fR\fB\&.num\fR
-\fId\fR\fB\&.num\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The numeric value that was matched (only valid for numeric types)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned int\fR \fInum2\fR;
-\fI$d\fR\fB\->{num2}\fR
-\fId\fR\fB\&.num2\fR
-\fId\fR\fB\&.num2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The secondary numeric value that was matched (only valid for types containing two values)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned int\fR \fIbinary\fR;
-\fI$d\fR\fB\->{binary}\fR
-\fId\fR\fB\&.binary\fR
-\fId\fR\fB\&.binary\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The value in binary form, useful for checksums and other data that cannot be represented as a string\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDatapos pos()\fR;
-my \fI$pos\fR \fB=\fR \fI$d\fR\fB\->pos()\fR;
-\fIpos\fR \fB=\fR \fId\fR\fB\&.pos()\fR
-\fIpos\fR \fB=\fR \fId\fR\fB\&.pos()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The position object of the current match\&. It can be used to do sub\-searches starting at the match (if it is of an array type)\&. See the Datapos class for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDatapos parentpos()\fR;
-my \fI$pos\fR \fB=\fR \fI$d\fR\fB\->parentpos()\fR;
-\fIpos\fR \fB=\fR \fId\fR\fB\&.parentpos()\fR
-\fIpos\fR \fB=\fR \fId\fR\fB\&.parentpos()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The position object of the array containing the current match\&. It can be used to do sub\-searches, see the Datapos class for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$d\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fId\fR\fB)\fR
-\fIstr\fR \fB=\fR \fId\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the stringification of the matched value\&. Stringification depends on the search flags, for file list entries it will return just the base name unless SEARCH_FILES is used, for checksums it will return an empty string unless SEARCH_CHECKSUMS is used\&. Numeric values are currently stringified to an empty string\&.
-.SH "THE SELECTION CLASS"
-.sp
-Selections are a way to easily deal with sets of packages\&. There are multiple constructors to create them, the most useful is probably the select() method in the Pool class\&.
-.SS "CONSTANTS"
-.PP
-\fBSELECTION_NAME\fR
-.RS 4
-Create the selection by matching package names\&.
-.RE
-.PP
-\fBSELECTION_PROVIDES\fR
-.RS 4
-Create the selection by matching package provides\&.
-.RE
-.PP
-\fBSELECTION_FILELIST\fR
-.RS 4
-Create the selection by matching package files\&.
-.RE
-.PP
-\fBSELECTION_CANON\fR
-.RS 4
-Create the selection by matching the canonical representation of the package\&. This is normally a combination of the name, the version, and the architecture of a package\&.
-.RE
-.PP
-\fBSELECTION_DOTARCH\fR
-.RS 4
-Allow an \(lq\&.<architecture>\(rq suffix when matching names or provides\&.
-.RE
-.PP
-\fBSELECTION_REL\fR
-.RS 4
-Allow the specification of a relation when matching names or provides, e\&.g\&. "name >= 1\&.2"\&.
-.RE
-.PP
-\fBSELECTION_INSTALLED_ONLY\fR
-.RS 4
-Limit the package search to installed packages\&.
-.RE
-.PP
-\fBSELECTION_SOURCE_ONLY\fR
-.RS 4
-Limit the package search to source packages only\&.
-.RE
-.PP
-\fBSELECTION_WITH_SOURCE\fR
-.RS 4
-Extend the package search to also match source packages\&. The default is only to match binary packages\&.
-.RE
-.PP
-\fBSELECTION_GLOB\fR
-.RS 4
-Allow glob matching for package names, package provides, and file names\&.
-.RE
-.PP
-\fBSELECTION_NOCASE\fR
-.RS 4
-Ignore case when matching package names, package provides, and file names\&.
-.RE
-.PP
-\fBSELECTION_FLAT\fR
-.RS 4
-Return only one selection element describing the selected packages\&. The default is to create multiple elements for all globbed packages\&. Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package\&.
-.RE
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                             /* read only */
-\fI$d\fR\fB\->{pool}\fR
-\fId\fR\fB\&.pool\fR
-\fId\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to pool\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint flags()\fR;
-my \fI$flags\fR \fB=\fR \fI$sel\fR\fB\->flags()\fR;
-\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags()\fR
-\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the result flags of the selection\&. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result\&. For example, if you create the selection with \(lqSELECTION_NAME | SELECTION_PROVIDES\(rq, the resulting flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not\&. If there was no match at all, the flags will be zero\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool isempty()\fR;
-\fI$sel\fR\fB\->isempty()\fR
-\fIsel\fR\fB\&.isempty()\fR
-\fIsel\fR\fB\&.isempty?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return true if the selection is empty, i\&.e\&. no package could be matched\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid filter(Selection *\fR\fIother\fR\fB)\fR
-\fI$sel\fR\fB\->filter(\fR\fI$other\fR\fB)\fR;
-\fIsel\fR\fB\&.filter(\fR\fIother\fR\fB)\fR
-\fIsel\fR\fB\&.filter(\fR\fIother\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Intersect two selections\&. Packages will only stay in the selection if there are also included in the other selecting\&. Does an in\-place modification\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add(Selection *\fR\fIother\fR\fB)\fR
-\fI$sel\fR\fB\->add(\fR\fI$other\fR\fB)\fR;
-\fIsel\fR\fB\&.add(\fR\fIother\fR\fB)\fR
-\fIsel\fR\fB\&.add(\fR\fIother\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Build the union of two selections\&. All packages of the other selection will be added to the set of packages of the selection object\&. Does an in\-place modification\&. Note that the selection flags are no longer meaningful after the add operation\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_raw(Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR
-\fI$sel\fR\fB\->add_raw(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR;
-\fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
-\fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a raw element to the selection\&. Check the Job class for information about the how and what parameters\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBJob *jobs(int\fR \fIaction\fR\fB)\fR
-my \fI@jobs\fR \fB=\fR \fI$sel\fR\fB\->jobs(\fR\fI$action\fR\fB)\fR;
-\fIjobs\fR \fB=\fR \fIsel\fR\fB\&.jobs(\fR\fIaction\fR\fB)\fR
-\fIjobs\fR \fB=\fR \fIsel\fR\fB\&.jobs(\fR\fIaction\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a selection into an array of Job objects\&. The action parameter is or\-ed to the \(lqhow\(rq part of the job, it describes the type of job (e\&.g\&. install, erase)\&. See the Job class for the action and action modifier constants\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *solvables()\fR
-my \fI@solvables\fR \fB=\fR \fI$sel\fR\fB\->solvables()\fR;
-\fIsolvables\fR \fB=\fR \fIsel\fR\fB\&.solvables()\fR
-\fIsolvables\fR \fB=\fR \fIsel\fR\fB\&.solvables()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a selection into an array of Solvable objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$sel\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIsel\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIsel\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string describing the selection\&.
-.SH "THE JOB CLASS"
-.sp
-Jobs are the way to specify to the dependency solver what to do\&. Most of the times jobs will get created by calling the jobs() method on a Selection object, but there is also a Job() constructor in the Pool class\&.
-.SS "CONSTANTS"
-.sp
-Selection constants:
-.PP
-\fBSOLVER_SOLVABLE\fR
-.RS 4
-The \(lqwhat\(rq part is the id of a solvable\&.
-.RE
-.PP
-\fBSOLVER_SOLVABLE_NAME\fR
-.RS 4
-The \(lqwhat\(rq part is the id of a package name\&.
-.RE
-.PP
-\fBSOLVER_SOLVABLE_PROVIDES\fR
-.RS 4
-The \(lqwhat\(rq part is the id of a package provides\&.
-.RE
-.PP
-\fBSOLVER_SOLVABLE_ONE_OF\fR
-.RS 4
-The \(lqwhat\(rq part is an offset into the \(lqwhatprovides\(rq data, created by calling the towhatprovides() pool method\&.
-.RE
-.PP
-\fBSOLVER_SOLVABLE_REPO\fR
-.RS 4
-The \(lqwhat\(rq part is the id of a repository\&.
-.RE
-.PP
-\fBSOLVER_SOLVABLE_ALL\fR
-.RS 4
-The \(lqwhat\(rq part is ignored, all packages are selected\&.
-.RE
-.PP
-\fBSOLVER_SOLVABLE_SELECTMASK\fR
-.RS 4
-A mask containing all the above selection bits\&.
-.RE
-.sp
-Action constants:
-.PP
-\fBSOLVER_NOOP\fR
-.RS 4
-Do nothing\&.
-.RE
-.PP
-\fBSOLVER_INSTALL\fR
-.RS 4
-Install a package of the specified set of packages\&. It tries to install the best matching package (i\&.e\&. the highest version of the packages from the repositories with the highest priority)\&.
-.RE
-.PP
-\fBSOLVER_ERASE\fR
-.RS 4
-Erase all of the packages from the specified set\&. If a package is not installed, erasing it will keep it from getting installed\&.
-.RE
-.PP
-\fBSOLVER_UPDATE\fR
-.RS 4
-Update the matching installed packages to their best version\&. If none of the specified packages are installed, try to update the installed packages to the specified versions\&. See the section about targeted updates about more information\&.
-.RE
-.PP
-\fBSOLVER_WEAKENDEPS\fR
-.RS 4
-Allow to break the dependencies of the matching packages\&. Handle with care\&.
-.RE
-.PP
-\fBSOLVER_MULTIVERSION\fR
-.RS 4
-Mark the matched packages for multiversion install\&. If they get to be installed because of some other job, the installation will keep the old version of the package installed (for rpm this is done by using \(lq\-i\(rq instead of \(lq\-U\(rq)\&.
-.RE
-.PP
-\fBSOLVER_LOCK\fR
-.RS 4
-Do not change the state of the matched packages, i\&.e\&. when they are installed they stay installed, if not they are not selected for installation\&.
-.RE
-.PP
-\fBSOLVER_DISTUPGRADE\fR
-.RS 4
-Update the matching installed packages to the best version included in one of the repositories\&. After this operation, all come from one of the available repositories except orphaned packages\&. Orphaned packages are packages that have no relation to the packages in the repositories, i\&.e\&. no package in the repositories have the same name or obsolete the orphaned package\&. This action brings the installed packages in sync with the ones in the repository\&. By default it also turns of arch/vendor/version locking for the affected packages to simulate a fresh installation\&. This means that distupgrade can actually downgrade packages if only lower versions of a package are available in the repositories\&. You can tweak this behavior with the SOLVER_FLAG_DUP_ solver flags\&.
-.RE
-.PP
-\fBSOLVER_DROP_ORPHANED\fR
-.RS 4
-Erase all the matching installed packages if they are orphaned\&. This only makes sense if there is a \(lqdistupgrade all packages\(rq job\&. The default is to erase orphaned packages only if they block the installation of other packages\&.
-.RE
-.PP
-\fBSOLVER_VERIFY\fR
-.RS 4
-Fix dependency problems of matching installed packages\&. The default is to ignore dependency problems for installed packages\&.
-.RE
-.PP
-\fBSOLVER_USERINSTALLED\fR
-.RS 4
-The matching installed packages are considered to be installed by a user, thus not installed to fulfill some dependency\&. This is needed input for the calculation of unneeded packages for jobs that have the SOLVER_CLEANDEPS flag set\&.
-.RE
-.PP
-\fBSOLVER_ALLOWUNINSTALL\fR
-.RS 4
-Allow the solver to deinstall the matching installed packages if they get into the way of resolving a dependency\&. This is like the SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages\&.
-.RE
-.PP
-\fBSOLVER_JOBMASK\fR
-.RS 4
-A mask containing all the above action bits\&.
-.RE
-.sp
-Action modifier constants:
-.PP
-\fBSOLVER_WEAK\fR
-.RS 4
-Makes the job a weak job\&. The solver tries to fulfill weak jobs, but does not report a problem if it is not possible to do so\&.
-.RE
-.PP
-\fBSOLVER_ESSENTIAL\fR
-.RS 4
-Makes the job an essential job\&. If there is a problem with the job, the solver will not propose to remove the job as one solution (unless all other solutions are also to remove essential jobs)\&.
-.RE
-.PP
-\fBSOLVER_CLEANDEPS\fR
-.RS 4
-The solver will try to also erase all packages dragged in through dependencies when erasing the package\&. This needs SOLVER_USERINSTALLED jobs to maximize user satisfaction\&.
-.RE
-.PP
-\fBSOLVER_FORCEBEST\fR
-.RS 4
-Insist on the best package for install, update, and distupgrade jobs\&. If this flag is not used, the solver will use the second\-best package if the best package cannot be installed for some reason\&. When this flag is used, the solver will generate a problem instead\&.
-.RE
-.PP
-\fBSOLVER_TARGETED\fR
-.RS 4
-Forces targeted operation update and distupgrade jobs\&. See the section about targeted updates about more information\&.
-.RE
-.sp
-Set constants\&.
-.PP
-\fBSOLVER_SETEV\fR
-.RS 4
-The job specified the exact epoch and version of the package set\&.
-.RE
-.PP
-\fBSOLVER_SETEVR\fR
-.RS 4
-The job specified the exact epoch, version, and release of the package set\&.
-.RE
-.PP
-\fBSOLVER_SETARCH\fR
-.RS 4
-The job specified the exact architecture of the packages from the set\&.
-.RE
-.PP
-\fBSOLVER_SETVENDOR\fR
-.RS 4
-The job specified the exact vendor of the packages from the set\&.
-.RE
-.PP
-\fBSOLVER_SETREPO\fR
-.RS 4
-The job specified the exact repository of the packages from the set\&.
-.RE
-.PP
-\fBSOLVER_SETNAME\fR
-.RS 4
-The job specified the exact name of the packages from the set\&.
-.RE
-.PP
-\fBSOLVER_NOAUTOSET\fR
-.RS 4
-Turn of automatic set flag generation for SOLVER_SOLVABLE jobs\&.
-.RE
-.PP
-\fBSOLVER_SETMASK\fR
-.RS 4
-A mask containing all the above set bits\&.
-.RE
-.sp
-See the section about set bits for more information\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                             /* read only */
-\fI$job\fR\fB\->{pool}\fR
-\fId\fR\fB\&.pool\fR
-\fId\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId how;\fR                                 /* read/write */
-\fI$job\fR\fB\->{how}\fR
-\fId\fR\fB\&.how\fR
-\fId\fR\fB\&.how\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Union of the selection, action, action modifier, and set flags\&. The selection part describes the semantics of the \(lqwhat\(rq Id\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId what;\fR                                /* read/write */
-\fI$job\fR\fB\->{what}\fR
-\fId\fR\fB\&.what\fR
-\fId\fR\fB\&.what\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id describing the set of packages, the meaning depends on the selection part of the \(lqhow\(rq attribute\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *solvables()\fR
-my \fI@solvables\fR \fB=\fR \fI$job\fR\fB\->solvables()\fR;
-\fIsolvables\fR \fB=\fR \fIjob\fR\fB\&.solvables()\fR
-\fIsolvables\fR \fB=\fR \fIjob\fR\fB\&.solvables()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the set of solvables of the job as an array of Solvable objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool isemptyupdate()\fR;
-\fI$job\fR\fB\->isemptyupdate()\fR
-\fIjob\fR\fB\&.isemptyupdate()\fR
-\fIjob\fR\fB\&.isemptyupdate?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convenience function to find out if the job describes an update job with no matching packages, i\&.e\&. a job that does nothing\&. Some package managers like \(lqzypper\(rq like to turn those jobs into install jobs, i\&.e\&. an update of a not\-installed package will result into the installation of the package\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$job\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIjob\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIjob\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string describing the job\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$job1\fR \fB==\fR \fI$job2\fR\fB)\fR
-\fBif\fR \fIjob1\fR \fB==\fR \fIjob2\fR\fB:\fR
-\fBif\fR \fIjob1\fR \fB==\fR \fIjob2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Two jobs are equal if they belong to the same pool and both the \(lqhow\(rq and the \(lqwhat\(rq attributes are the same\&.
-.SS "TARGETED UPDATES"
-.sp
-Libsolv has two modes for upgrades and distupgrade: targeted and untargeted\&. Untargeted mode means that the installed packages from the specified set will be updated to the best version\&. Targeted means that packages that can be updated to a package in the specified set will be updated to the best package of the set\&.
-.sp
-Here\(cqs an example to explain the subtle difference\&. Suppose that you have package A installed in version "1\&.1", "A\-1\&.2" is available in one of the repositories and there is also package "B" that obsoletes package A\&.
-.sp
-An untargeted update of "A" will update the installed "A\-1\&.1" to package "B", because that is the newest version (B obsoletes A and is thus newer)\&.
-.sp
-A targeted update of "A" will update "A\-1\&.1" to "A\-1\&.2", as the set of packages contains both "A\-1\&.1" and "A\-1\&.2", and "A\-1\&.2" is the newer one\&.
-.sp
-An untargeted update of "B" will do nothing, as "B" is not installed\&.
-.sp
-An targeted update of "B" will update "A\-1\&.1" to "B"\&.
-.sp
-Note that the default is to do "auto\-targeting", thus if the specified set of packages does not include an installed package, the solver will assume targeted operation even if SOLVER_TARGETED is not used\&.
-.sp
-This mostly matches the intent of the user, with one exception: In the example above, an update of "A\-1\&.2" will update "A\-1\&.1" to "A\-1\&.2" (targeted mode), but a second update of "A\-1\&.2" will suddenly update to "B", as untargeted mode is chosen because "A\-1\&.2" is now installed\&.
-.sp
-If you want to have full control over when targeting mode is chosen, turn off auto\-targeting with the SOLVER_FLAG_NO_AUTOTARGET solver option\&. In that case, all updates are considered to be untargeted unless they include the SOLVER_TARGETED flag\&.
-.SS "SET BITS"
-.sp
-Set bits specify which parts of the specified packages where specified by the user\&. It is used by the solver when checking if an operation is allowed or not\&. For example, the solver will normally not allow the downgrade of an installed package\&. But it will not report a problem if the SOLVER_SETEVR flag is used, as it then assumes that the user specified the exact version and thus knows what he is doing\&.
-.sp
-So if a package "screen\-1\-1" is installed for the x86_64 architecture and version "2\-1" is only available for the i586 architecture, installing package "screen\-2\&.1" will ask the user for confirmation because of the different architecture\&. When using the Selection class to create jobs the set bits are automatically added, e\&.g\&. selecting \(lqscreen\&.i586\(rq will automatically add SOLVER_SETARCH, and thus no problem will be reported\&.
-.SH "THE SOLVER CLASS"
-.sp
-Dependency solving is what this library is about\&. A solver object is needed for solving to store the result of the solver run\&. The solver object can be used multiple times for different jobs, reusing it allows the solver to re\-use the dependency rules it already computed\&.
-.SS "CONSTANTS"
-.sp
-Flags to modify some of the solver\(cqs behavior:
-.PP
-\fBSOLVER_FLAG_ALLOW_DOWNGRADE\fR
-.RS 4
-Allow the solver to downgrade packages without asking for confirmation (i\&.e\&. reporting a problem)\&.
-.RE
-.PP
-\fBSOLVER_FLAG_ALLOW_ARCHCHANGE\fR
-.RS 4
-Allow the solver to change the architecture of an installed package without asking for confirmation\&. Note that changes to/from noarch are always considered to be allowed\&.
-.RE
-.PP
-\fBSOLVER_FLAG_ALLOW_VENDORCHANGE\fR
-.RS 4
-Allow the solver to change the vendor of an installed package without asking for confirmation\&. Each vendor is part of one or more vendor equivalence classes, normally installed packages may only change their vendor if the new vendor shares at least one equivalence class\&.
-.RE
-.PP
-\fBSOLVER_FLAG_ALLOW_NAMECHANGE\fR
-.RS 4
-Allow the solver to change the name of an installed package, i\&.e\&. install a package with a different name that obsoletes the installed package\&. This option is on by default\&.
-.RE
-.PP
-\fBSOLVER_FLAG_ALLOW_UNINSTALL\fR
-.RS 4
-Allow the solver to erase installed packages to fulfill the jobs\&. This flag also includes the above flags\&. You may want to set this flag if you only have SOLVER_ERASE jobs, as in that case it\(cqs better for the user to check the transaction overview instead of approving every single package that needs to be erased\&.
-.RE
-.PP
-\fBSOLVER_FLAG_DUP_ALLOW_DOWNGRADE\fR
-.RS 4
-Like SOLVER_FLAG_ALLOW_DOWNGRADE, but used in distupgrade mode\&.
-.RE
-.PP
-\fBSOLVER_FLAG_DUP_ALLOW_ARCHCHANGE\fR
-.RS 4
-Like SOLVER_FLAG_ALLOW_ARCHCHANGE, but used in distupgrade mode\&.
-.RE
-.PP
-\fBSOLVER_FLAG_DUP_ALLOW_VENDORCHANGE\fR
-.RS 4
-Like SOLVER_FLAG_ALLOW_VENDORCHANGE, but used in distupgrade mode\&.
-.RE
-.PP
-\fBSOLVER_FLAG_DUP_ALLOW_NAMECHANGE\fR
-.RS 4
-Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode\&.
-.RE
-.PP
-\fBSOLVER_FLAG_NO_UPDATEPROVIDE\fR
-.RS 4
-If multiple packages obsolete an installed package, the solver checks the provides of every such package and ignores all packages that do not provide the installed package name\&. Thus, you can have an official update candidate that provides the old name, and other packages that also obsolete the package but are not considered for updating\&. If you cannot use this feature, you can turn it off by setting this flag\&.
-.RE
-.PP
-\fBSOLVER_FLAG_SPLITPROVIDES\fR
-.RS 4
-Make the solver aware of special provides of the form \(lq<packagename>:<path>\(rq used in SUSE systems to support package splits\&.
-.RE
-.PP
-\fBSOLVER_FLAG_IGNORE_RECOMMENDED\fR
-.RS 4
-Do not process optional (aka weak) dependencies\&.
-.RE
-.PP
-\fBSOLVER_FLAG_ADD_ALREADY_RECOMMENDED\fR
-.RS 4
-Install recommended or supplemented packages even if they have no connection to the current transaction\&. You can use this feature to implement a simple way for the user to install new recommended packages that were not available in the past\&.
-.RE
-.PP
-\fBSOLVER_FLAG_NO_INFARCHCHECK\fR
-.RS 4
-Turn off the inferior architecture checking that is normally done by the solver\&. Normally, the solver allows only the installation of packages from the "best" architecture if a package is available for multiple architectures\&.
-.RE
-.PP
-\fBSOLVER_FLAG_BEST_OBEY_POLICY\fR
-.RS 4
-Make the SOLVER_FORCEBEST job option consider only packages that meet the policies for installed packages, i\&.e\&. no downgrades, no architecture change, no vendor change (see the first flags of this section)\&. If the flag is not specified, the solver will enforce the installation of the best package ignoring the installed packages, which may conflict with the set policy\&.
-.RE
-.PP
-\fBSOLVER_FLAG_NO_AUTOTARGET\fR
-.RS 4
-Do not enable auto\-targeting up update and distupgrade jobs\&. See the section on targeted updates for more information\&.
-.RE
-.PP
-\fBSOLVER_FLAG_KEEP_ORPHANS\fR
-.RS 4
-Do not allow orphaned packages to be deinstalled if they get in the way of resolving other packages\&.
-.RE
-.PP
-\fBSOLVER_FLAG_BREAK_ORPHANS\fR
-.RS 4
-Ignore dependencies of orphaned packages that get in the way of resolving non\-orphaned ones\&. Setting the flag might result in no longer working packages in case they are orphaned\&.
-.RE
-.PP
-\fBSOLVER_FLAG_FOCUS_INSTALLED\fR
-.RS 4
-Resolve installed packages before resolving the given job\&. Setting this flag means that the solver will prefer picking a package version that fits the other installed packages over updating installed packages\&.
-.RE
-.sp
-Basic rule types:
-.PP
-\fBSOLVER_RULE_UNKNOWN\fR
-.RS 4
-A rule of an unknown class\&. You should never encounter those\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG\fR
-.RS 4
-A package dependency rule\&.
-.RE
-.PP
-\fBSOLVER_RULE_UPDATE\fR
-.RS 4
-A rule to implement the update policy of installed packages\&. Every installed package has an update rule that consists of the packages that may replace the installed package\&.
-.RE
-.PP
-\fBSOLVER_RULE_FEATURE\fR
-.RS 4
-Feature rules are fallback rules used when an update rule is disabled\&. They include all packages that may replace the installed package ignoring the update policy, i\&.e\&. they contain downgrades, arch changes and so on\&. Without them, the solver would simply erase installed packages if their update rule gets disabled\&.
-.RE
-.PP
-\fBSOLVER_RULE_JOB\fR
-.RS 4
-Job rules implement the job given to the solver\&.
-.RE
-.PP
-\fBSOLVER_RULE_DISTUPGRADE\fR
-.RS 4
-These are simple negative assertions that make sure that only packages are kept that are also available in one of the repositories\&.
-.RE
-.PP
-\fBSOLVER_RULE_INFARCH\fR
-.RS 4
-Infarch rules are also negative assertions, they disallow the installation of packages when there are packages of the same name but with a better architecture\&.
-.RE
-.PP
-\fBSOLVER_RULE_CHOICE\fR
-.RS 4
-Choice rules are used to make sure that the solver prefers updating to installing different packages when some dependency is provided by multiple packages with different names\&. The solver may always break choice rules, so you will not see them when a problem is found\&.
-.RE
-.PP
-\fBSOLVER_RULE_LEARNT\fR
-.RS 4
-These rules are generated by the solver to keep it from running into the same problem multiple times when it has to backtrack\&. They are the main reason why a sat solver is faster than other dependency solver implementations\&.
-.RE
-.sp
-Special dependency rule types:
-.PP
-\fBSOLVER_RULE_PKG_NOT_INSTALLABLE\fR
-.RS 4
-This rule was added to prevent the installation of a package of an architecture that does not work on the system\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_NOTHING_PROVIDES_DEP\fR
-.RS 4
-The package contains a required dependency which was not provided by any package\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_REQUIRES\fR
-.RS 4
-Similar to SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, but in this case some packages provided the dependency but none of them could be installed due to other dependency issues\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_SELF_CONFLICT\fR
-.RS 4
-The package conflicts with itself\&. This is not allowed by older rpm versions\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_CONFLICTS\fR
-.RS 4
-To fulfill the dependencies two packages need to be installed, but one of the packages contains a conflict with the other one\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_SAME_NAME\fR
-.RS 4
-The dependencies can only be fulfilled by multiple versions of a package, but installing multiple versions of the same package is not allowed\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_OBSOLETES\fR
-.RS 4
-To fulfill the dependencies two packages need to be installed, but one of the packages obsoletes the other one\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_IMPLICIT_OBSOLETES\fR
-.RS 4
-To fulfill the dependencies two packages need to be installed, but one of the packages has provides a dependency that is obsoleted by the other one\&. See the POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES flag\&.
-.RE
-.PP
-\fBSOLVER_RULE_PKG_INSTALLED_OBSOLETES\fR
-.RS 4
-To fulfill the dependencies a package needs to be installed that is obsoleted by an installed package\&. See the POOL_FLAG_NOINSTALLEDOBSOLETES flag\&.
-.RE
-.PP
-\fBSOLVER_RULE_JOB_NOTHING_PROVIDES_DEP\fR
-.RS 4
-The user asked for installation of a package providing a specific dependency, but no available package provides it\&.
-.RE
-.PP
-\fBSOLVER_RULE_JOB_UNKNOWN_PACKAGE\fR
-.RS 4
-The user asked for installation of a package with a specific name, but no available package has that name\&.
-.RE
-.PP
-\fBSOLVER_RULE_JOB_PROVIDED_BY_SYSTEM\fR
-.RS 4
-The user asked for the erasure of a dependency that is provided by the system (i\&.e\&. for special hardware or language dependencies), this cannot be done with a job\&.
-.RE
-.PP
-\fBSOLVER_RULE_JOB_UNSUPPORTED\fR
-.RS 4
-The user asked for something that is not yet implemented, e\&.g\&. the installation of all packages at once\&.
-.RE
-.sp
-Policy error constants
-.PP
-\fBPOLICY_ILLEGAL_DOWNGRADE\fR
-.RS 4
-The solver ask for permission before downgrading packages\&.
-.RE
-.PP
-\fBPOLICY_ILLEGAL_ARCHCHANGE\fR
-.RS 4
-The solver ask for permission before changing the architecture of installed packages\&.
-.RE
-.PP
-\fBPOLICY_ILLEGAL_VENDORCHANGE\fR
-.RS 4
-The solver ask for permission before changing the vendor of installed packages\&.
-.RE
-.PP
-\fBPOLICY_ILLEGAL_NAMECHANGE\fR
-.RS 4
-The solver ask for permission before replacing an installed packages with a package that has a different name\&.
-.RE
-.sp
-Solution element type constants
-.PP
-\fBSOLVER_SOLUTION_JOB\fR
-.RS 4
-The problem can be solved by removing the specified job\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_POOLJOB\fR
-.RS 4
-The problem can be solved by removing the specified job that is defined in the pool\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_INFARCH\fR
-.RS 4
-The problem can be solved by allowing the installation of the specified package with an inferior architecture\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_DISTUPGRADE\fR
-.RS 4
-The problem can be solved by allowing to keep the specified package installed\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_BEST\fR
-.RS 4
-The problem can be solved by allowing to install the specified package that is not the best available package\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_ERASE\fR
-.RS 4
-The problem can be solved by allowing to erase the specified package\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_REPLACE\fR
-.RS 4
-The problem can be solved by allowing to replace the package with some other package\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_REPLACE_DOWNGRADE\fR
-.RS 4
-The problem can be solved by allowing to replace the package with some other package that has a lower version\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_REPLACE_ARCHCHANGE\fR
-.RS 4
-The problem can be solved by allowing to replace the package with some other package that has a different architecture\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_REPLACE_VENDORCHANGE\fR
-.RS 4
-The problem can be solved by allowing to replace the package with some other package that has a different vendor\&.
-.RE
-.PP
-\fBSOLVER_SOLUTION_REPLACE_NAMECHANGE\fR
-.RS 4
-The problem can be solved by allowing to replace the package with some other package that has a different name\&.
-.RE
-.sp
-Reason constants
-.PP
-\fBSOLVER_REASON_UNRELATED\fR
-.RS 4
-The package status did not change as it was not related to any job\&.
-.RE
-.PP
-\fBSOLVER_REASON_UNIT_RULE\fR
-.RS 4
-The package was installed/erased/kept because of a unit rule, i\&.e\&. a rule where all literals but one were false\&.
-.RE
-.PP
-\fBSOLVER_REASON_KEEP_INSTALLED\fR
-.RS 4
-The package was chosen when trying to keep as many packages installed as possible\&.
-.RE
-.PP
-\fBSOLVER_REASON_RESOLVE_JOB\fR
-.RS 4
-The decision happened to fulfill a job rule\&.
-.RE
-.PP
-\fBSOLVER_REASON_UPDATE_INSTALLED\fR
-.RS 4
-The decision happened to fulfill a package update request\&.
-.RE
-.PP
-\fBSOLVER_REASON_CLEANDEPS_ERASE\fR
-.RS 4
-The package was erased when cleaning up dependencies from other erased packages\&.
-.RE
-.PP
-\fBSOLVER_REASON_RESOLVE\fR
-.RS 4
-The package was installed to fulfill package dependencies\&.
-.RE
-.PP
-\fBSOLVER_REASON_WEAKDEP\fR
-.RS 4
-The package was installed because of a weak dependency (Recommends or Supplements)\&.
-.RE
-.PP
-\fBSOLVER_REASON_RESOLVE_ORPHAN\fR
-.RS 4
-The decision about the package was made when deciding the fate of orphaned packages\&.
-.RE
-.PP
-\fBSOLVER_REASON_RECOMMENDED\fR
-.RS 4
-This is a special case of SOLVER_REASON_WEAKDEP\&.
-.RE
-.PP
-\fBSOLVER_REASON_SUPPLEMENTED\fR
-.RS 4
-This is a special case of SOLVER_REASON_WEAKDEP\&.
-.RE
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                             /* read only */
-\fI$job\fR\fB\->{pool}\fR
-\fId\fR\fB\&.pool\fR
-\fId\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to pool\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint set_flag(int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR
-my \fI$oldvalue\fR \fB=\fR \fI$solver\fR\fB\->set_flag(\fR\fI$flag\fR\fB,\fR \fI$value\fR\fB)\fR;
-\fIoldvalue\fR \fB=\fR \fIsolver\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
-\fIoldvalue\fR \fB=\fR \fIsolver\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint get_flag(int\fR \fIflag\fR\fB)\fR
-my \fI$value\fR \fB=\fR \fI$solver\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR;
-\fIvalue\fR \fB=\fR \fIsolver\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
-\fIvalue\fR \fB=\fR \fIsolver\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set/get a solver specific flag\&. The flags define the policies the solver has to obey\&. The flags are explained in the CONSTANTS section of this class\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBProblem *solve(Job *\fR\fIjobs\fR\fB)\fR
-my \fI@problems\fR \fB=\fR \fI$solver\fR\fB\->solve(\e\fR\fI@jobs\fR\fB)\fR;
-\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
-\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Solve a problem specified in the job list (plus the jobs defined in the pool)\&. Returns an array of problems that need user interaction, or an empty array if no problems were encountered\&. See the Problem class on how to deal with problems\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBTransaction transaction()\fR
-my \fI$trans\fR \fB=\fR \fI$solver\fR\fB\->transaction()\fR;
-\fItrans\fR \fB=\fR \fIsolver\fR\fB\&.transaction()\fR
-\fItrans\fR \fB=\fR \fIsolver\fR\fB\&.transaction()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the transaction to implement the calculated package changes\&. A transaction is available even if problems were found, this is useful for interactive user interfaces that show both the job result and the problems\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint\fR \fIreason\fR \fB= describe_decision(Solvable *\fR\fIs\fR\fB, Rule *\fR\fIOUTPUT\fR\fB)\fR
-my \fB(\fR\fI$reason\fR\fB,\fR \fI$rule\fR\fB) =\fR \fI$solver\fR\fB\->describe_decision(\fR\fI$solvable\fR\fB)\fR;
-\fB(\fR\fIreason\fR\fB,\fR \fIrule\fR\fB) =\fR \fIsolver\fR\fB\&.describe_decision(\fR\fIsolvable\fR\fB)\fR
-\fB(\fR\fIreason\fR\fB,\fR \fIrule\fR\fB) =\fR \fIsolver\fR\fB\&.describe_decision(\fR\fIsolvable\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the reason why a specific solvable was installed or erased\&. For most of the reasons the rule that triggered the decision is also returned\&.
-.SH "THE PROBLEM CLASS"
-.sp
-Problems are the way of the solver to interact with the user\&. You can simply list all problems and terminate your program, but a better way is to present solutions to the user and let him pick the ones he likes\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolver *solv;\fR                           /* read only */
-\fI$problem\fR\fB\->{solv}\fR
-\fIproblem\fR\fB\&.solv\fR
-\fIproblem\fR\fB\&.solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to solver object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                                  /* read only */
-\fI$problem\fR\fB\->{id}\fR
-\fIproblem\fR\fB\&.id\fR
-\fIproblem\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id of the problem\&. The first problem has Id 1, they are numbered consecutively\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRule findproblemrule()\fR
-my \fI$probrule\fR \fB=\fR \fI$problem\fR\fB\->findproblemrule()\fR;
-\fIprobrule\fR \fB=\fR \fIproblem\fR\fB\&.findproblemrule()\fR
-\fIprobrule\fR \fB=\fR \fIproblem\fR\fB\&.findproblemrule()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the rule that caused the problem\&. Of course in most situations there is no single responsible rule, but many rules that interconnect with each created the problem\&. Nevertheless, the solver uses some heuristic approach to find a rule that somewhat describes the problem best to the user\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRule *findallproblemrules(bool\fR \fIunfiltered\fR \fB= 0)\fR
-my \fI@probrules\fR \fB=\fR \fI$problem\fR\fB\->findallproblemrules()\fR;
-\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrule()\fR
-\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrule()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return all rules responsible for the problem\&. The returned set of rules contains all the needed information why there was a problem, but it\(cqs hard to present them to the user in a sensible way\&. The default is to filter out all update and job rules (unless the returned rules only consist of those types)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolution *solutions()\fR
-my \fI@solutions\fR \fB=\fR \fI$problem\fR\fB\->solutions()\fR;
-\fIsolutions\fR \fB=\fR \fIproblem\fR\fB\&.solutions()\fR
-\fIsolutions\fR \fB=\fR \fIproblem\fR\fB\&.solutions()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return an array containing multiple possible solutions to fix the problem\&. See the solution class for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint solution_count()\fR
-my \fI$cnt\fR \fB=\fR \fI$problem\fR\fB\->solution_count()\fR;
-\fIcnt\fR \fB=\fR \fIproblem\fR\fB\&.solution_count()\fR
-\fIcnt\fR \fB=\fR \fIproblem\fR\fB\&.solution_count()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the number of solutions without creating solution objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$problem\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIproblem\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIproblem\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string describing the problem\&. This is a convenience function, it is a shorthand for calling findproblemrule(), then ruleinfo() on the problem rule and problemstr() on the ruleinfo object\&.
-.SH "THE RULE CLASS"
-.sp
-Rules are the basic block of sat solving\&. Each package dependency gets translated into one or multiple rules\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolver *solv;\fR                           /* read only */
-\fI$rule\fR\fB\->{solv}\fR
-\fIrule\fR\fB\&.solv\fR
-\fIrule\fR\fB\&.solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to solver object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                                  /* read only */
-\fI$rule\fR\fB\->{id}\fR
-\fIrule\fR\fB\&.id\fR
-\fIrule\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of the rule\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint type;\fR                               /* read only */
-\fI$rule\fR\fB\->{type}\fR
-\fIrule\fR\fB\&.type\fR
-\fIrule\fR\fB\&.type\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The basic type of the rule\&. See the constant section of the solver class for the type list\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRuleinfo info()\fR
-my \fI$ruleinfo\fR \fB=\fR \fI$rule\fR\fB\->info()\fR;
-\fIruleinfo\fR \fB=\fR \fIrule\fR\fB\&.info()\fR
-\fIruleinfo\fR \fB=\fR \fIrule\fR\fB\&.info()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a Ruleinfo object that contains information about why the rule was created\&. But see the allinfos() method below\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRuleinfo *allinfos()\fR
-my \fI@ruleinfos\fR \fB=\fR \fI$rule\fR\fB\->allinfos()\fR;
-\fIruleinfos\fR \fB=\fR \fIrule\fR\fB\&.allinfos()\fR
-\fIruleinfos\fR \fB=\fR \fIrule\fR\fB\&.allinfos()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-As the same dependency rule can get created because of multiple dependencies, one Ruleinfo is not enough to describe the reason\&. Thus the allinfos() method returns an array of all infos about a rule\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$rule1\fR \fB==\fR \fI$rule2\fR\fB)\fR
-\fBif\fR \fIrule1\fR \fB==\fR \fIrule2\fR\fB:\fR
-\fBif\fR \fIrule1\fR \fB==\fR \fIrule2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Two rules are equal if they belong to the same solver and have the same id\&.
-.SH "THE RULEINFO CLASS"
-.sp
-A Ruleinfo describes one reason why a rule was created\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolver *solv;\fR                           /* read only */
-\fI$ruleinfo\fR\fB\->{solv}\fR
-\fIruleinfo\fR\fB\&.solv\fR
-\fIruleinfo\fR\fB\&.solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to solver object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint type;\fR                               /* read only */
-\fI$ruleinfo\fR\fB\->{type}\fR
-\fIruleinfo\fR\fB\&.type\fR
-\fIruleinfo\fR\fB\&.type\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The type of the ruleinfo\&. See the constant section of the solver class for the rule type list and the special type list\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDep *dep;\fR                               /* read only */
-\fI$ruleinfo\fR\fB\->{dep}\fR
-\fIruleinfo\fR\fB\&.dep\fR
-\fIruleinfo\fR\fB\&.dep\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The dependency leading to the creation of the rule\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDep *dep_id;\fR                            /* read only */
-\fI$ruleinfo\fR\fB\->{\*(Aqdep_id\*(Aq}\fR
-\fIruleinfo\fR\fB\&.dep_id\fR
-\fIruleinfo\fR\fB\&.dep_id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The Id of the dependency leading to the creation of the rule, or zero\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *solvable;\fR                     /* read only */
-\fI$ruleinfo\fR\fB\->{solvable}\fR
-\fIruleinfo\fR\fB\&.solvable\fR
-\fIruleinfo\fR\fB\&.solvable\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The involved Solvable, e\&.g\&. the one containing the dependency\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *othersolvable;\fR                /* read only */
-\fI$ruleinfo\fR\fB\->{othersolvable}\fR
-\fIruleinfo\fR\fB\&.othersolvable\fR
-\fIruleinfo\fR\fB\&.othersolvable\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The other involved Solvable (if any), e\&.g\&. the one containing providing the dependency for conflicts\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *problemstr()\fR;
-my \fI$str\fR \fB=\fR \fI$ruleinfo\fR\fB\->problemstr()\fR;
-\fIstr\fR \fB=\fR \fIruleinfo\fR\fB\&.problemstr()\fR
-\fIstr\fR \fB=\fR \fIruleinfo\fR\fB\&.problemstr()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-A string describing the ruleinfo from a problem perspective\&. This probably only makes sense if the rule is part of a problem\&.
-.SH "THE SOLUTION CLASS"
-.sp
-A solution solves one specific problem\&. It consists of multiple solution elements that all need to be executed\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolver *solv;\fR                           /* read only */
-\fI$solution\fR\fB\->{solv}\fR
-\fIsolution\fR\fB\&.solv\fR
-\fIsolution\fR\fB\&.solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to solver object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId problemid;\fR                           /* read only */
-\fI$solution\fR\fB\->{problemid}\fR
-\fIsolution\fR\fB\&.problemid\fR
-\fIsolution\fR\fB\&.problemid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id of the problem the solution solves\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                                  /* read only */
-\fI$solution\fR\fB\->{id}\fR
-\fIsolution\fR\fB\&.id\fR
-\fIsolution\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id of the solution\&. The first solution has Id 1, they are numbered consecutively\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolutionelement *elements(bool\fR \fIexpandreplaces\fR \fB= 0)\fR
-my \fI@solutionelements\fR \fB=\fR \fI$solution\fR\fB\->elements()\fR;
-\fIsolutionelements\fR \fB=\fR \fIsolution\fR\fB\&.elements()\fR
-\fIsolutionelements\fR \fB=\fR \fIsolution\fR\fB\&.elements()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return an array containing the elements describing what needs to be done to implement the specific solution\&. If expandreplaces is true, elements of type SOLVER_SOLUTION_REPLACE will be replaced by one or more elements replace elements describing the policy mismatches\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint element_count()\fR
-my \fI$cnt\fR \fB=\fR \fI$solution\fR\fB\->solution_count()\fR;
-\fIcnt\fR \fB=\fR \fIsolution\fR\fB\&.element_count()\fR
-\fIcnt\fR \fB=\fR \fIsolution\fR\fB\&.element_count()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the number of solution elements without creating objects\&. Note that the count does not match the number of objects returned by the elements() method of expandreplaces is set to true\&.
-.SH "THE SOLUTIONELEMENT CLASS"
-.sp
-A solution element describes a single action of a solution\&. The action is always either to remove one specific job or to add a new job that installs or erases a single specific package\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolver *solv;\fR                           /* read only */
-\fI$solutionelement\fR\fB\->{solv}\fR
-\fIsolutionelement\fR\fB\&.solv\fR
-\fIsolutionelement\fR\fB\&.solv\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to solver object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId problemid;\fR                           /* read only */
-\fI$solutionelement\fR\fB\->{problemid}\fR
-\fIsolutionelement\fR\fB\&.problemid\fR
-\fIsolutionelement\fR\fB\&.problemid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id of the problem the element (partly) solves\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId solutionid;\fR                          /* read only */
-\fI$solutionelement\fR\fB\->{solutionid}\fR
-\fIsolutionelement\fR\fB\&.solutionid\fR
-\fIsolutionelement\fR\fB\&.solutionid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id of the solution the element is a part of\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                                  /* read only */
-\fI$solutionelement\fR\fB\->{id}\fR
-\fIsolutionelement\fR\fB\&.id\fR
-\fIsolutionelement\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Id of the solution element\&. The first element has Id 1, they are numbered consecutively\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId type;\fR                                /* read only */
-\fI$solutionelement\fR\fB\->{type}\fR
-\fIsolutionelement\fR\fB\&.type\fR
-\fIsolutionelement\fR\fB\&.type\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Type of the solution element\&. See the constant section of the solver class for the existing types\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *solvable;\fR                     /* read only */
-\fI$solutionelement\fR\fB\->{solvable}\fR
-\fIsolutionelement\fR\fB\&.solvable\fR
-\fIsolutionelement\fR\fB\&.solvable\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The installed solvable that needs to be replaced for replacement elements\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *replacement;\fR                  /* read only */
-\fI$solutionelement\fR\fB\->{replacement}\fR
-\fIsolutionelement\fR\fB\&.replacement\fR
-\fIsolutionelement\fR\fB\&.replacement\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The solvable that needs to be installed to fix the problem\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint jobidx;\fR                             /* read only */
-\fI$solutionelement\fR\fB\->{jobidx}\fR
-\fIsolutionelement\fR\fB\&.jobidx\fR
-\fIsolutionelement\fR\fB\&.jobidx\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The index of the job that needs to be removed to fix the problem, or \-1 if the element is of another type\&. Note that it\(cqs better to change the job to SOLVER_NOOP type so that the numbering of other elements does not get disturbed\&. This method works both for types SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolutionelement *replaceelements()\fR
-my \fI@solutionelements\fR \fB=\fR \fI$solutionelement\fR\fB\->replaceelements()\fR;
-\fIsolutionelements\fR \fB=\fR \fIsolutionelement\fR\fB\&.replaceelements()\fR
-\fIsolutionelements\fR \fB=\fR \fIsolutionelement\fR\fB\&.replaceelements()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-If the solution element is of type SOLVER_SOLUTION_REPLACE, return an array of elements describing the policy mismatches, otherwise return a copy of the element\&. See also the \(lqexpandreplaces\(rq option in the solution\(cqs elements() method\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint illegalreplace()\fR
-my \fI$illegal\fR \fB=\fR \fI$solutionelement\fR\fB\->illegalreplace()\fR;
-\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.illegalreplace()\fR
-\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.illegalreplace()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return an integer that contains the policy mismatch bits or\-ed together, or zero if there was no policy mismatch\&. See the policy error constants in the solver class\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBJob Job()\fR
-my \fI$job\fR \fB=\fR \fI$solutionelement\fR\fB\->Job()\fR;
-\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.Job()\fR
-\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.Job()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a job that implements the solution element\&. Add this job to the array of jobs for all elements of type different to SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&. For the later two, a SOLVER_NOOB Job is created, you should replace the old job with the new one\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *str()\fR
-my \fI$str\fR \fB=\fR \fI$solutionelement\fR\fB\->str()\fR;
-\fIstr\fR \fB=\fR \fIsolutionelement\fR\fB\&.str()\fR
-\fIstr\fR \fB=\fR \fIsolutionelement\fR\fB\&.str()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-A string describing the change the solution element consists of\&.
-.SH "THE TRANSACTION CLASS"
-.sp
-Transactions describe the output of a solver run\&. A transaction contains a number of transaction elements, each either the installation of a new package or the removal of an already installed package\&. The Transaction class supports a classify() method that puts the elements into different groups so that a transaction can be presented to the user in a meaningful way\&.
-.SS "CONSTANTS"
-.sp
-Transaction element types, both active and passive
-.PP
-\fBSOLVER_TRANSACTION_IGNORE\fR
-.RS 4
-This element does nothing\&. Used to map element types that do not match the view mode\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_INSTALL\fR
-.RS 4
-This element installs a package\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_ERASE\fR
-.RS 4
-This element erases a package\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_MULTIINSTALL\fR
-.RS 4
-This element installs a package with a different version keeping the other versions installed\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_MULTIREINSTALL\fR
-.RS 4
-This element reinstalls an installed package keeping the other versions installed\&.
-.RE
-.sp
-Transaction element types, active view
-.PP
-\fBSOLVER_TRANSACTION_REINSTALL\fR
-.RS 4
-This element re\-installs a package, i\&.e\&. installs the same package again\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_CHANGE\fR
-.RS 4
-This element installs a package with same name, version, architecture but different content\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_UPGRADE\fR
-.RS 4
-This element installs a newer version of an installed package\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_DOWNGRADE\fR
-.RS 4
-This element installs an older version of an installed package\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_OBSOLETES\fR
-.RS 4
-This element installs a package that obsoletes an installed package\&.
-.RE
-.sp
-Transaction element types, passive view
-.PP
-\fBSOLVER_TRANSACTION_REINSTALLED\fR
-.RS 4
-This element re\-installs a package, i\&.e\&. installs the same package again\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_CHANGED\fR
-.RS 4
-This element replaces an installed package with one of the same name, version, architecture but different content\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_UPGRADED\fR
-.RS 4
-This element replaces an installed package with a new version\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_DOWNGRADED\fR
-.RS 4
-This element replaces an installed package with an old version\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_OBSOLETED\fR
-.RS 4
-This element replaces an installed package with a package that obsoletes it\&.
-.RE
-.sp
-Pseudo element types for showing extra information used by classify()
-.PP
-\fBSOLVER_TRANSACTION_ARCHCHANGE\fR
-.RS 4
-This element replaces an installed package with a package of a different architecture\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_VENDORCHANGE\fR
-.RS 4
-This element replaces an installed package with a package of a different vendor\&.
-.RE
-.sp
-Transaction mode flags
-.PP
-\fBSOLVER_TRANSACTION_SHOW_ACTIVE\fR
-.RS 4
-Filter for active view types\&. The default is to return passive view type, i\&.e\&. to show how the installed packages get changed\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_SHOW_OBSOLETES\fR
-.RS 4
-Do not map the obsolete view type into INSTALL/ERASE elements\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_SHOW_ALL\fR
-.RS 4
-If multiple packages replace an installed package, only the best of them is kept as OBSOLETE element, the other ones are mapped to INSTALL/ERASE elements\&. This is because most applications want to show just one package replacing the installed one\&. The SOLVER_TRANSACTION_SHOW_ALL makes the library keep all OBSOLETE elements\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_SHOW_MULTIINSTALL\fR
-.RS 4
-The library maps MULTIINSTALL elements to simple INSTALL elements\&. This flag can be used to disable the mapping\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_CHANGE_IS_REINSTALL\fR
-.RS 4
-Use this flag if you want to map CHANGE elements to the REINSTALL type\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE\fR
-.RS 4
-Use this flag if you want to map OBSOLETE elements to the UPGRADE type\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_MERGE_ARCHCHANGES\fR
-.RS 4
-Do not add extra categories for every architecture change, instead cumulate them in one category\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_MERGE_VENDORCHANGES\fR
-.RS 4
-Do not add extra categories for every vendor change, instead cumulate them in one category\&.
-.RE
-.PP
-\fBSOLVER_TRANSACTION_RPM_ONLY\fR
-.RS 4
-Special view mode that just returns IGNORE, ERASE, INSTALL, MULTIINSTALL elements\&. Useful if you want to find out what to feed to the underlying package manager\&.
-.RE
-.sp
-Transaction order flags
-.PP
-\fBSOLVER_TRANSACTION_KEEP_ORDERDATA\fR
-.RS 4
-Do not throw away the dependency graph used for ordering the transaction\&. This flag is needed if you want to do manual ordering\&.
-.RE
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool;\fR                             /* read only */
-\fI$trans\fR\fB\->{pool}\fR
-\fItrans\fR\fB\&.pool\fR
-\fItrans\fR\fB\&.pool\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to pool\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool isempty()\fR;
-\fI$trans\fR\fB\->isempty()\fR
-\fItrans\fR\fB\&.isempty()\fR
-\fItrans\fR\fB\&.isempty?\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Returns true if the transaction does not do anything, i\&.e\&. has no elements\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *newsolvables()\fR;
-my \fI@newsolvables\fR \fB=\fR \fI$trans\fR\fB\->newsolvables()\fR;
-\fInewsolvables\fR \fB=\fR \fItrans\fR\fB\&.newsolvables()\fR
-\fInewsolvables\fR \fB=\fR \fItrans\fR\fB\&.newsolvables()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return all packages that are to be installed by the transaction\&. These are the packages that need to be downloaded from the repositories\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *keptsolvables()\fR;
-my \fI@keptsolvables\fR \fB=\fR \fI$trans\fR\fB\->keptsolvables()\fR;
-\fIkeptsolvables\fR \fB=\fR \fItrans\fR\fB\&.keptsolvables()\fR
-\fIkeptsolvables\fR \fB=\fR \fItrans\fR\fB\&.keptsolvables()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return all installed packages that the transaction will keep installed\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *steps()\fR;
-my \fI@steps\fR \fB=\fR \fI$trans\fR\fB\->steps()\fR;
-\fIsteps\fR \fB=\fR \fItrans\fR\fB\&.steps()\fR
-\fIsteps\fR \fB=\fR \fItrans\fR\fB\&.steps()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return all solvables that need to be installed (if the returned solvable is not already installed) or erased (if the returned solvable is installed)\&. A step is also called a transaction element\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint steptype(Solvable *\fR\fIsolvable\fR\fB, int\fR \fImode\fR\fB)\fR
-my \fI$type\fR \fB=\fR \fI$trans\fR\fB\->steptype(\fR\fI$solvable\fR\fB,\fR \fI$mode\fR\fB)\fR;
-\fItype\fR \fB=\fR \fItrans\fR\fB\&.steptype(\fR\fIsolvable\fR\fB,\fR \fImode\fR\fB)\fR
-\fItype\fR \fB=\fR \fItrans\fR\fB\&.steptype(\fR\fIsolvable\fR\fB,\fR \fImode\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the transaction type of the specified solvable\&. See the CONSTANTS sections for the mode argument flags and the list of returned types\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBTransactionClass *classify(int\fR \fImode\fR \fB= 0)\fR
-my \fI@classes\fR \fB=\fR \fI$trans\fR\fB\->classify()\fR;
-\fIclasses\fR \fB=\fR \fItrans\fR\fB\&.classify()\fR
-\fIclasses\fR \fB=\fR \fItrans\fR\fB\&.classify()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Group the transaction elements into classes so that they can be displayed in a structured way\&. You can use various mapping mode flags to tweak the result to match your preferences, see the mode argument flag in the CONSTANTS section\&. See the TransactionClass class for how to deal with the returned objects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable othersolvable(Solvable *\fR\fIsolvable\fR\fB)\fR;
-my \fI$other\fR \fB=\fR \fI$trans\fR\fB\->othersolvable(\fR\fI$solvable\fR\fB)\fR;
-\fIother\fR \fB=\fR \fItrans\fR\fB\&.othersolvable(\fR\fIsolvable\fR\fB)\fR
-\fIother\fR \fB=\fR \fItrans\fR\fB\&.othersolvable(\fR\fIsolvable\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the \(lqother\(rq solvable for a given solvable\&. For installed packages the other solvable is the best package with the same name that replaces the installed package, or the best package of the obsoleting packages if the package does not get replaced by one with the same name\&.
-.sp
-For to be installed packages, the \(lqother\(rq solvable is the best installed package with the same name that will be replaced, or the best packages of all the packages that are obsoleted if the new package does not replace a package with the same name\&.
-.sp
-Thus, the \(lqother\(rq solvable is normally the package that is also shown for a given package\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *allothersolvables(Solvable *\fR\fIsolvable\fR\fB)\fR;
-my \fI@others\fR \fB=\fR \fI$trans\fR\fB\->allothersolvables(\fR\fI$solvable\fR\fB)\fR;
-\fIothers\fR \fB=\fR \fItrans\fR\fB\&.allothersolvables(\fR\fIsolvable\fR\fB)\fR
-\fIothers\fR \fB=\fR \fItrans\fR\fB\&.allothersolvables(\fR\fIsolvable\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-For installed packages, returns all of the packages that replace us\&. For to be installed packages, returns all of the packages that the new package replaces\&. The special \(lqother\(rq solvable is always the first entry of the returned array\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint calc_installsizechange()\fR;
-my \fI$change\fR \fB=\fR \fI$trans\fR\fB\->calc_installsizechange()\fR;
-\fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR
-\fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the size change of the installed system in kilobytes (kibibytes)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid order(int\fR \fIflags\fR \fB= 0)\fR;
-\fI$trans\fR\fB\->order()\fR;
-\fItrans\fR\fB\&.order()\fR
-\fItrans\fR\fB\&.order()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Order the steps in the transactions so that dependent packages are updated before packages that depend on them\&. For rpm, you can also use rpmlib\(cqs ordering functionality, debian\(cqs dpkg does not provide a way to order a transaction\&.
-.SS "ACTIVE/PASSIVE VIEW"
-.sp
-Active view lists what new packages get installed, while passive view shows what happens to the installed packages\&. Most often there\(cqs not much difference between the two modes, but things get interesting if multiple packages get replaced by one new package\&. Say you have installed packages A\-1\-1 and B\-1\-1, and now install A\-2\-1 which has a new dependency that obsoletes B\&. The transaction elements will be
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-updated   A\-1\-1 (other: A\-2\-1)
-obsoleted B\-1\-1 (other: A\-2\-1)
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-in passive mode, but
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-update A\-2\-1 (other: A\-1\-1)
-erase  B
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-in active mode\&. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the passive mode list will be unchanged but the active mode list will just contain A\-2\-1\&.
-.SH "THE TRANSACTIONCLASS CLASS"
-.sp
-Objects of this type are returned by the classify() Transaction method\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBTransaction *transaction;\fR               /* read only */
-\fI$class\fR\fB\->{transaction}\fR
-\fIclass\fR\fB\&.transaction\fR
-\fIclass\fR\fB\&.transaction\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to transaction object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint type;\fR                               /* read only */
-\fI$class\fR\fB\->{type}\fR
-\fIclass\fR\fB\&.type\fR
-\fIclass\fR\fB\&.type\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The type of the transaction elements in the class\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint count;\fR                              /* read only */
-\fI$class\fR\fB\->{count}\fR
-\fIclass\fR\fB\&.count\fR
-\fIclass\fR\fB\&.count\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The number of elements in the class\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *\fR\fIfromstr\fR;
-\fI$class\fR\fB\->{fromstr}\fR
-\fIclass\fR\fB\&.fromstr\fR
-\fIclass\fR\fB\&.fromstr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The old vendor or architecture\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *\fR\fItostr\fR;
-\fI$class\fR\fB\->{tostr}\fR
-\fIclass\fR\fB\&.tostr\fR
-\fIclass\fR\fB\&.tostr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The new vendor or architecture\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId\fR \fIfromid\fR;
-\fI$class\fR\fB\->{fromid}\fR
-\fIclass\fR\fB\&.fromid\fR
-\fIclass\fR\fB\&.fromid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of the old vendor or architecture\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId\fR \fItoid\fR;
-\fI$class\fR\fB\->{toid}\fR
-\fIclass\fR\fB\&.toid\fR
-\fIclass\fR\fB\&.toid\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of the new vendor or architecture\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid solvables()\fR;
-my \fI@solvables\fR \fB=\fR \fI$class\fR\fB\->solvables()\fR;
-\fIsolvables\fR \fB=\fR \fIclass\fR\fB\&.solvables()\fR
-\fIsolvables\fR \fB=\fR \fIclass\fR\fB\&.solvables()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the solvables for all transaction elements in the class\&.
-.SH "CHECKSUMS"
-.sp
-Checksums (also called hashes) are used to make sure that downloaded data is not corrupt and also as a fingerprint mechanism to check if data has changed\&.
-.SS "CLASS METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum Chksum(Id\fR \fItype\fR\fB)\fR
-my \fI$chksum\fR \fB= solv::Chksum\->new(\fR\fI$type\fR\fB)\fR;
-\fIchksum\fR \fB= solv\&.Chksum(\fR\fItype\fR\fB)\fR
-\fIchksum\fR \fB= Solv::Chksum\&.new(\fR\fItype\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a checksum object\&. Currently the following types are supported:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBREPOKEY_TYPE_MD5\fR
-\fBREPOKEY_TYPE_SHA1\fR
-\fBREPOKEY_TYPE_SHA256\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-These keys are constants in the \fBsolv\fR class\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum Chksum(Id\fR \fItype\fR\fB, const char *\fR\fIhex\fR\fB)\fR
-my \fI$chksum\fR \fB= solv::Chksum\->new(\fR\fI$type\fR\fB,\fR \fI$hex\fR\fB)\fR;
-\fIchksum\fR \fB= solv\&.Chksum(\fR\fItype\fR\fB,\fR \fIhex\fR\fB)\fR
-\fIchksum\fR \fB= Solv::Chksum\&.new(\fR\fItype\fR\fB,\fR \fIhex\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create an already finalized checksum object from a hex string\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum Chksum_from_bin(Id\fR \fItype\fR\fB, char *\fR\fIbin\fR\fB)\fR
-my \fI$chksum\fR \fB= solv::Chksum\->from_bin(\fR\fI$type\fR\fB,\fR \fI$bin\fR\fB)\fR;
-\fIchksum\fR \fB= solv\&.Chksum\&.from_bin(\fR\fItype\fR\fB,\fR \fIbin\fR\fB)\fR
-\fIchksum\fR \fB= Solv::Chksum\&.from_bin(\fR\fItype\fR\fB,\fR \fIbin\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create an already finalized checksum object from a binary checksum\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId type;\fR                        /* read only */
-\fI$chksum\fR\fB\->{type}\fR
-\fIchksum\fR\fB\&.type\fR
-\fIchksum\fR\fB\&.type\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the type of the checksum object\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add(const char *\fR\fIstr\fR\fB)\fR
-\fI$chksum\fR\fB\->add(\fR\fI$str\fR\fB)\fR;
-\fIchksum\fR\fB\&.add(\fR\fIstr\fR\fB)\fR
-\fIchksum\fR\fB\&.add(\fR\fIstr\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a (binary) string to the checksum\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_fp(FILE *\fR\fIfp\fR\fB)\fR
-\fI$chksum\fR\fB\->add_fp(\fR\fI$file\fR\fB)\fR;
-\fIchksum\fR\fB\&.add_fp(\fR\fIfile\fR\fB)\fR
-\fIchksum\fR\fB\&.add_fp(\fR\fIfile\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of a file to the checksum\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_stat(const char *\fR\fIfilename\fR\fB)\fR
-\fI$chksum\fR\fB\->add_stat(\fR\fI$filename\fR\fB)\fR;
-\fIchksum\fR\fB\&.add_stat(\fR\fIfilename\fR\fB)\fR
-\fIchksum\fR\fB\&.add_stat(\fR\fIfilename\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Stat the file and add the dev/ino/size/mtime member to the checksum\&. If the stat fails, the members are zeroed\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_fstat(int\fR \fIfd\fR\fB)\fR
-\fI$chksum\fR\fB\->add_fstat(\fR\fI$fd\fR\fB)\fR;
-\fIchksum\fR\fB\&.add_fstat(\fR\fIfd\fR\fB)\fR
-\fIchksum\fR\fB\&.add_fstat(\fR\fIfd\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as add_stat, but instead of the filename a file descriptor is used\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned char *raw()\fR
-my \fI$raw\fR \fB=\fR \fI$chksum\fR\fB\->raw()\fR;
-\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.raw()\fR
-\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.raw()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Finalize the checksum and return the result as raw bytes\&. This means that the result can contain NUL bytes or unprintable characters\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *hex()\fR
-my \fI$raw\fR \fB=\fR \fI$chksum\fR\fB\->hex()\fR;
-\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.hex()\fR
-\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.hex()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Finalize the checksum and return the result as hex string\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *typestr()\fR
-my \fI$typestr\fR \fB=\fR \fI$chksum\fR\fB\->typestr()\fR;
-\fItypestr\fR \fB=\fR \fIchksum\fR\fB\&.typestr\fR
-\fItypestr\fR \fB=\fR \fIchksum\fR\fB\&.typestr\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the type of the checksum as a string, e\&.g\&. "sha256"\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$chksum1\fR \fB==\fR \fI$chksum2\fR\fB)\fR
-\fBif\fR \fIchksum1\fR \fB==\fR \fIchksum2\fR\fB:\fR
-\fBif\fR \fIchksum1\fR \fB==\fR \fIchksum2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Checksums are equal if they are of the same type and the finalized results are the same\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<stringification>\fR
-my \fI$str\fR \fB=\fR \fI$chksum\fR\fB\->str\fR;
-\fIstr\fR \fB= str(\fR\fIchksum\fR\fB)\fR
-\fIstr\fR \fB=\fR \fIchksum\fR\fB\&.to_s\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-If the checksum is finished, the checksum is returned as "<type>:<hex>" string\&. Otherwise "<type>:unfinished" is returned\&.
-.SH "FILE MANAGEMENT"
-.sp
-This functions were added because libsolv uses standard \fBFILE\fR pointers to read/write files, but languages like perl have their own implementation of files\&. The libsolv functions also support decompression and compression, the algorithm is selected by looking at the file name extension\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBFILE *xfopen(char *\fR\fIfn\fR\fB, char *\fR\fImode\fR \fB= "r")\fR
-my \fI$file\fR \fB= solv::xfopen(\fR\fI$path\fR\fB)\fR;
-\fIfile\fR \fB= solv\&.xfopen(\fR\fIpath\fR\fB)\fR
-\fIfile\fR \fB= Solv::xfopen(\fR\fIpath\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Open a file at the specified path\&. The mode argument is passed on to the stdio library\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBFILE *xfopen_fd(char *\fR\fIfn\fR\fB, int\fR \fIfileno\fR\fB)\fR
-my \fI$file\fR \fB= solv::xfopen_fd(\fR\fI$path\fR\fB,\fR \fI$fileno\fR\fB)\fR;
-\fIfile\fR \fB= solv\&.xfopen_fd(\fR\fIpath\fR\fB,\fR \fIfileno\fR\fB)\fR
-\fIfile\fR \fB= Solv::xfopen_fd(\fR\fIpath\fR\fB,\fR \fIfileno\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a file handle from the specified file descriptor\&. The path argument is only used to select the correct (de\-)compression algorithm, use an empty path if you want to make sure to read/write raw data\&. The file descriptor is dup()ed before the file handle is created\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint fileno()\fR
-my \fI$fileno\fR \fB=\fR \fI$file\fR\fB\->fileno()\fR;
-\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.fileno()\fR
-\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.fileno()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return file file descriptor of the file\&. If the file is not open, \-1 is returned\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid cloexec(bool\fR \fIstate\fR\fB)\fR
-\fI$file\fR\fB\->cloexec(\fR\fI$state\fR\fB)\fR
-\fIfile\fR\fB\&.cloexec(\fR\fIstate\fR\fB)\fR
-\fIfile\fR\fB\&.cloexec(\fR\fIstate\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the close\-on\-exec flag of the file descriptor\&. The xfopen function returns files with close\-on\-exec turned on, so if you want to pass a file to some other process you need to call cloexec(0) before calling exec\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint dup()\fR
-my \fI$fileno\fR \fB=\fR \fI$file\fR\fB\->dup()\fR;
-\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.dup()\fR
-\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.dup()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a copy of the descriptor of the file\&. If the file is not open, \-1 is returned\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool flush()\fR
-\fI$file\fR\fB\->flush()\fR;
-\fIfile\fR\fB\&.flush()\fR
-\fIfile\fR\fB\&.flush()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Flush the file\&. Returns false if there was an error\&. Flushing a closed file always returns true\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool close()\fR
-\fI$file\fR\fB\->close()\fR;
-\fIfile\fR\fB\&.close()\fR
-\fIfile\fR\fB\&.close()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Close the file\&. This is needed for languages like Ruby that do not destruct objects right after they are no longer referenced\&. In that case, it is good style to close open files so that the file descriptors are freed right away\&. Returns false if there was an error\&.
-.SH "THE REPODATA CLASS"
-.sp
-The Repodata stores attributes for packages and the repository itself, each repository can have multiple repodata areas\&. You normally only need to directly access them if you implement lazy downloading of repository data\&. Repodata areas are created by calling the repository\(cqs add_repodata() method or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING flag\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo *repo;\fR                     /* read only */
-\fI$data\fR\fB\->{repo}\fR
-\fIdata\fR\fB\&.repo\fR
-\fIdata\fR\fB\&.repo\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to repository object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId id;\fR                                  /* read only */
-\fI$data\fR\fB\->{id}\fR
-\fIdata\fR\fB\&.id\fR
-\fIdata\fR\fB\&.id\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-The id of the repodata area\&. Repodata ids of different repositories overlap\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBinternalize()\fR;
-\fI$data\fR\fB\->internalize()\fR;
-\fIdata\fR\fB\&.internalize()\fR
-\fIdata\fR\fB\&.internalize()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Internalize newly added data\&. The lookup functions will only see the new data after it has been internalized\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool write(FILE *\fR\fIfp\fR\fB)\fR;
-\fI$data\fR\fB\->write(\fR\fI$fp\fR\fB)\fR;
-\fIdata\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
-\fIdata\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Write the contents of the repodata area as solv file\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR;
-\fI$data\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR;
-\fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
-\fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Replace a stub repodata object with the data from a solv file\&. This method automatically adds the REPO_USE_LOADING flag\&. It should only be used from a load callback\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid create_stubs()\fR;
-\fI$data\fR\fB\->create_stubs()\fR
-\fIdata\fR\fB\&.create_stubs()\fR
-\fIdata\fR\fB\&.create_stubs()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create stub repodatas from the information stored in the repodata meta area\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid extend_to_repo()\fR;
-\fI$data\fR\fB\->extend_to_repo()\fR;
-\fIdata\fR\fB\&.extend_to_repo()\fR
-\fIdata\fR\fB\&.extend_to_repo()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Extend the repodata so that it has the same size as the repo it belongs to\&. This method is only needed when switching to a just written repodata extension to make the repodata match the written extension (which is always of the size of the repo)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fB<equality>\fR
-\fBif (\fR\fI$data1\fR \fB==\fR \fI$data2\fR\fB)\fR
-\fBif\fR \fIdata1\fR \fB==\fR \fIdata2\fR\fB:\fR
-\fBif\fR \fIdata1\fR \fB==\fR \fIdata2\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Two repodata objects are equal if they belong to the same repository and have the same id\&.
-.SS "DATA RETRIEVAL METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *lookup_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI@ids\fR \fB=\fR \fI$data\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum lookup_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$chksum\fR \fB=\fR \fI$data\fR\fB\->lookup_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
-\fIchksum\fR \fB=\fR \fIdata\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-\fIchksum\fR \fB=\fR \fIdata\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Lookup functions\&. Return the data element stored in the specified solvable\&. The methods probably only make sense to retrieve data from the special SOLVID_META solvid that stores repodata meta information\&.
-.SS "DATA STORAGE METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid set_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR;
-\fI$data\fR\fB\->set_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR;
-\fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
-\fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid set_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR;
-\fI$data\fR\fB\->set_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR;
-\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
-\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid set_poolstr(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR;
-\fI$data\fR\fB\->set_poolstr(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR;
-\fIdata\fR\fB\&.set_poolstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
-\fIdata\fR\fB\&.set_poolstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid set_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Chksum *\fR\fIchksum\fR\fB)\fR;
-\fI$data\fR\fB\->set_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$chksum\fR\fB)\fR;
-\fIdata\fR\fB\&.set_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIchksum\fR\fB)\fR
-\fIdata\fR\fB\&.set_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIchksum\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR;
-\fI$data\fR\fB\->add_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR;
-\fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
-\fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId new_handle()\fR;
-my \fI$handle\fR \fB=\fR \fI$data\fR\fB\->new_handle()\fR;
-\fIhandle\fR \fB=\fR \fIdata\fR\fB\&.new_handle()\fR
-\fIhandle\fR \fB=\fR \fIdata\fR\fB\&.new_handle()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid add_flexarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fIhandle\fR\fB)\fR;
-\fI$data\fR\fB\->add_flexarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$handle\fR\fB)\fR;
-\fIdata\fR\fB\&.add_flexarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIhandle\fR\fB)\fR
-\fIdata\fR\fB\&.add_flexarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIhandle\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Data storage methods\&. Probably only useful to store data in the special SOLVID_META solvid that stores repodata meta information\&. Note that repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag), so be careful if you need to store ids\&. Arrays are created by calling the add function for every element\&. A flexarray is an array of sub\-structures, call new_handle to create a new structure, use the handle as solvid to fill the structure with data and call add_flexarray to put the structure in an array\&.
-.SH "THE DATAPOS CLASS"
-.sp
-Datapos objects describe a specific position in the repository data area\&. Thus they are only valid until the repository is modified in some way\&. Datapos objects can be created by the pos() and parentpos() methods of a Datamatch object or by accessing the \(lqmeta\(rq attribute of a repository\&.
-.SS "ATTRIBUTES"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBRepo *repo;\fR                     /* read only */
-\fI$data\fR\fB\->{repo}\fR
-\fIdata\fR\fB\&.repo\fR
-\fIdata\fR\fB\&.repo\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Back pointer to repository object\&.
-.SS "METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR
-my \fI$di\fR \fB=\fR \fI$datapos\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a Dataiterator at the position of the datapos object\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_deltalocation(unsigned int *\fR\fIOUTPUT\fR\fB)\fR;
-my \fB(\fR\fI$location\fR\fB,\fR \fI$medianr\fR\fB) =\fR \fI$datapos\fR\fB\->lookup_deltalocation()\fR;
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a tuple containing the on\-media location and an optional media number for a delta rpm\&. This obviously only works if the data position points to structure describing a delta rpm\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_deltaseq()\fR;
-my \fI$seq\fR \fB=\fR \fI$datapos\fR\fB\->lookup_deltaseq()\fR;
-\fIseq\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltaseq()\fR;
-\fIseq\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltaseq()\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the delta rpm sequence from the structure describing a delta rpm\&.
-.SS "DATA RETRIEVAL METHODS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *lookup_str(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$string\fR \fB=\fR \fI$datapos\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\fR;
-\fIstring\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
-\fIstring\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
-my \fI$id\fR \fB=\fR \fI$datapos\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
-\fIid\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned long long lookup_num(Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
-my \fI$num\fR \fB=\fR \fI$datapos\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR;
-\fInum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
-\fInum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBbool lookup_void(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$bool\fR \fB=\fR \fI$datapos\fR\fB\->lookup_void(\fR\fI$keyname\fR\fB)\fR;
-\fIbool\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
-\fIbool\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *lookup_idarray(Id\fR \fIkeyname\fR\fB)\fR
-my \fI@ids\fR \fB=\fR \fI$datapos\fR\fB\->lookup_idarray(\fR\fI$keyname\fR\fB)\fR;
-\fIids\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
-\fIids\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBChksum lookup_checksum(Id\fR \fIkeyname\fR\fB)\fR
-my \fI$chksum\fR \fB=\fR \fI$datapos\fR\fB\->lookup_checksum(\fR\fI$keyname\fR\fB)\fR;
-\fIchksum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
-\fIchksum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Lookup functions\&. Note that the returned Ids are always translated into the Ids of the global pool even if the repodata area contains its own pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
-my \fI$di\fR \fB=\fR \fI$datapos\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
-\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
-\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Iterate over the matching data elements\&. See the Dataiterator class for more information\&.
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/libsolv-bindings.txt b/libsolv-0.6.15/doc/libsolv-bindings.txt
deleted file mode 100644 (file)
index 1ee699d..0000000
+++ /dev/null
@@ -1,3489 +0,0 @@
-Libsolv-Bindings(3)
-===================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-libsolv-bindings - access libsolv from perl/python/ruby
-
-
-Description
------------
-Libsolv's language bindings offer an abstract, object orientated interface
-to the library. The supported languages are currently perl, python, and ruby.
-All example code (except in the specifics sections, of course) lists first
-the ``C-ish'' interface, then the syntax for perl, python, and ruby (in that
-order).
-
-
-Perl Specifics
---------------
-Libsolv's perl bindings can be loaded with the following statement:
-
-       use solv;
-
-Objects are either created by calling the new() method on a class or they
-are returned by calling methods on other objects.
-
-       my $pool = solv::Pool->new();
-       my $repo = $pool->add_repo("my_first_repo");
-
-Swig encapsulates all objects as tied hashes, thus the attributes can be
-accessed by treating the object as standard hash reference:
-
-       $pool->{appdata} = 42;
-       printf "appdata is %d\n", $pool->{appdata};
-
-A special exception to this are iterator objects, they are encapsulated as
-tied arrays so that it is possible to iterate with a for() statement:
-
-       my $iter = $pool->solvables_iter();
-       for my $solvable (@$iter) { ... };
-
-As a downside of this approach, iterator objects cannot have attributes.
-
-If an array needs to be passed to a method it is usually done by reference,
-if a method returns an array it returns it on the stack:
-
-       my @problems = $solver->solve(\@jobs);
-
-Due to a bug in swig, stringification does not work for libsolv's objects.
-Instead, you have to call the object's str() method.
-
-       print $dep->str() . "\n";
-
-Swig implements all constants as numeric variables (instead of the more
-natural constant subs), so don't forget the leading ``$'' when accessing a
-constant. Also do not forget to prepend the namespace of the constant:
-
-       $pool->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1);
-       
-
-Python Specifics
-----------------
-The python bindings can be loaded with:
-
-       import solv
-
-Objects are either created by calling the constructor method for a class or they
-are returned by calling methods on other objects.
-
-       pool = solv.Pool()
-       repo = pool.add_repo("my_first_repo")
-
-Attributes can be accessed as usual:
-
-       pool.appdata = 42
-       print "appdata is %d" % (pool.appdata)
-
-Iterators also work as expected:
-
-       for solvable in pool.solvables_iter():
-
-Arrays are passed and returned as list objects:
-
-       jobs = []
-       problems = solver.solve(jobs)
-
-The bindings define stringification for many classes, some also have a
-__repr__ method to ease debugging.
-
-       print dep
-       print repr(repo)
-
-Constants are attributes of the classes:
-
-       pool.set_flag(solv.Pool.POOL_FLAG_OBSOLETEUSESCOLORS, 1);
-
-
-Ruby Specifics
---------------
-The ruby bindings can be loaded with:
-
-       require 'solv'
-
-Objects are either created by calling the new method on a class or they
-are returned by calling methods on other objects. Note that all classes start
-with an uppercase letter in ruby, so the class is called ``Solv''.
-
-       pool = Solv::Pool.new
-       repo = pool.add_repo("my_first_repo")
-
-Attributes can be accessed as usual:
-
-       pool.appdata = 42
-       puts "appdata is #{pool.appdata}"
-
-Iterators also work as expected:
-
-       for solvable in pool.solvables_iter() do ...
-
-Arrays are passed and returned as array objects:
-
-       jobs = []
-       problems = solver.solve(jobs)
-
-Most classes define a to_s method, so objects can be easily stringified.
-Many also define an inspect() method.
-
-       puts dep
-       puts repo.inspect
-
-Constants live in the namespace of the class they belong to:
-
-       pool.set_flag(Solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1);
-
-Note that boolean methods have an added trailing ``?'', to be consistent with
-other ruby modules:
-
-       puts "empty" if repo.isempty?
-
-
-Tcl Specifics
--------------
-Libsolv's tcl bindings can be loaded with the following statement:
-
-       TCL package require solv
-
-Objects are either created by calling class name prefixed with ``new_'',
-or they are returned by calling methods on other objects.
-
-       TCL set pool [solv::new_Pool]
-       TCL set repo [$pool add_repo "my_first_repo"]
-
-Swig provides a ``cget'' method to read object attributes, and a
-``configure'' method to write them:
-
-       TCL $pool configure -appdata 42
-       TCL puts "appdata is [$pool cget -appdata]"
-
-The tcl bindings provide a little helper to work with iterators in
-a foreach style:
-
-       TCL set iter [$pool solvables_iter]
-       TCL solv::iter s $iter { ... }
-
-libsolv's arrays are mapped to tcl's lists:
-
-        TCL set jobs [list $job1 $job2]
-       TCL set problems [$solver solve $jobs]
-       TCL puts "We have [llength $problems] problems..."
-
-Stringification is done by calling the object's ``str'' method.
-
-       TCL puts [$dep str]
-
-There is one exception: you have to use ``stringify'' for Datamatch
-objects, as swig reports a clash with the ``str'' attribute.
-Some objects also support a ``=='' method for equality tests, and a
-``!='' method.
-
-Swig implements all constants as numeric variables, constants belonging
-to a libsolv class are prefixed with the class name:
-
-       TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS  1
-       TCL puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY]
-       
-
-The Solv Class
---------------
-This is the main namespace of the library, you cannot create objects of this
-type but it contains some useful constants.
-
-=== CONSTANTS ===
-
-Relational flag constants, the first three can be or-ed together
-
-*REL_LT*::
-the ``less than'' bit
-
-*REL_EQ*::
-the ``equals to'' bit
-
-*REL_GT*::
-the ``greater than'' bit
-
-*REL_ARCH*::
-used for relations that describe an extra architecture filter, the
-version part of the relation is interpreted as architecture.
-
-Special Solvable Ids
-
-*SOLVID_META*::
-Access the meta section of a repository or repodata area. This is
-like an extra Solvable that has the Id SOLVID_META.
-
-*SOLVID_POS*::
-Use the data position stored inside of the pool instead of accessing
-some solvable by Id. The bindings have the Datapos objects as an
-abstraction mechanism, so you do not need this constant.
-
-Constant string Ids
-  
-*ID_NULL*::
-Always zero
-
-*ID_EMPTY*::
-Always one, describes the empty string
-
-*SOLVABLE_NAME*::
-The keyname Id of the name of the solvable.
-
-*...*::
-see the libsolv-constantids manpage for a list of fixed Ids.
-
-
-The Pool Class
---------------
-The pool is libsolv's central resource manager. A pool consists of Solvables,
-Repositories, Dependencies, each indexed by Ids.
-
-=== CLASS METHODS ===
-
-       Pool *Pool()
-       my $pool = solv::Pool->new();
-       pool = solv.Pool()
-       pool = Solv::Pool.new()
-
-Create a new pool instance. In most cases you just need one pool.
-Note that the returned object "owns" the pool, i.e. if the object is 
-freed, the pool is also freed. You can use the disown method to
-break this ownership relation.
-
-=== ATTRIBUTES ===
-
-       void *appdata;                  /* read/write */
-       $pool->{appdata}
-       pool.appdata
-       pool.appdata
-
-Application specific data that may be used in any way by the code using the
-pool.
-
-       Solvable solvables[];           /* read only */
-       my $solvable = $pool->{solvables}->[$solvid];
-       solvable = pool.solvables[solvid]
-       solvable = pool.solvables[solvid]
-
-Look up a Solvable by its id.
-
-       Repo repos[];                   /* read only */
-       my $repo = $pool->{repos}->[$repoid];
-       repo = pool.repos[repoid]
-       repo = pool.repos[repoid]
-
-Look up a Repository by its id.
-
-       Repo *installed;                /* read/write */
-       $pool->{installed} = $repo;
-       pool.installed = repo
-       pool.installed = repo
-
-Define which repository contains all the installed packages.
-
-       const char *errstr;             /* read only */
-       my $err = $pool->{errstr};
-       err = pool.errstr
-       err = pool.errstr
-
-Return the last error string that was stored in the pool.
-
-=== CONSTANTS ===
-
-*POOL_FLAG_PROMOTEEPOCH*::
-Promote the epoch of the providing dependency to the requesting
-dependency if it does not contain an epoch. Used at some time
-in old rpm versions, modern systems should never need this.
-
-*POOL_FLAG_FORBIDSELFCONFLICTS*::
-Disallow the installation of packages that conflict with themselves.
-Debian always allows self-conflicting packages, rpm used to forbid
-them but switched to also allowing them recently.
-
-*POOL_FLAG_OBSOLETEUSESPROVIDES*::
-Make obsolete type dependency match against provides instead of
-just the name and version of packages. Very old versions of rpm
-used the name/version, then it got switched to provides and later
-switched back again to just name/version.
-
-*POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES*::
-An implicit obsoletes is the internal mechanism to remove the
-old package on an update. The default is to remove all packages
-with the same name, rpm-5 switched to also removing packages
-providing the same name.
-
-*POOL_FLAG_OBSOLETEUSESCOLORS*::
-Rpm's multilib implementation (used in RedHat and Fedora)
-distinguishes between 32bit and 64bit packages (the terminology
-is that they have a different color). If obsoleteusescolors is
-set, packages with different colors will not obsolete each other.
-
-*POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*::
-Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if
-packages of the same name can be installed in parallel. For
-current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be
-false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true
-(this is the default if FEDORA is defined when libsolv is compiled).
-
-*POOL_FLAG_NOINSTALLEDOBSOLETES*::
-New versions of rpm consider the obsoletes of installed packages
-when checking for dependency, thus you may not install a package
-that is obsoleted by some other installed package, unless you
-also erase the other package.
-
-*POOL_FLAG_HAVEDISTEPOCH*::
-Mandriva added a new field called distepoch that gets checked in
-version comparison if the epoch/version/release of two packages
-are the same.
-
-*POOL_FLAG_NOOBSOLETESMULTIVERSION*::
-If a package is installed in multiversionmode, rpm used to ignore
-both the implicit obsoletes and the obsolete dependency of a
-package. This was changed to ignoring just the implicit obsoletes,
-thus you may install multiple versions of the same name, but
-obsoleted packages still get removed.
-
-*POOL_FLAG_ADDFILEPROVIDESFILTERED*::
-Make the addfileprovides method only add files from the standard
-locations (i.e. the ``bin'' and ``etc'' directories). This is
-useful if you have only few packages that use non-standard file
-dependencies, but you still want the fast speed that addfileprovides()
-generates.
-
-=== METHODS ===
-
-       void free()
-       $pool->free();
-       pool.free()
-       pool.free()
-
-Force a free of the pool. After this call, you must not access any object
-that still references the pool.
-
-       void disown()
-       $pool->disown();
-       pool.disown()
-       pool.disown()
-
-Break the ownership relation between the binding object and the pool. After
-this call, the pool will not get freed even if the object goes out of
-scope. This also means that you must manually call the free method to free
-the pool data.
-
-       void setdebuglevel(int level)
-       $pool->setdebuglevel($level);
-       pool.setdebuglevel(level)
-       pool.setdebuglevel(level)
-
-Set the debug level. A value of zero means no debug output, the higher the
-value, the more output is generated.
-
-       int set_flag(int flag, int value)
-       my $oldvalue = $pool->set_flag($flag, $value);
-       oldvalue = pool.set_flag(flag, value)
-       oldvalue = pool.set_flag(flag, value)
-
-       int get_flag(int flag)
-       my $value = $pool->get_flag($flag);
-       value = pool.get_flag(flag)
-       value = pool.get_flag(flag)
-
-Set/get a pool specific flag. The flags define how the system works, e.g. how
-the package manager treats obsoletes. The default flags should be sane for most
-applications, but in some cases you may want to tweak a flag, for example if
-you want to solv package dependencies for some other system than yours.
-
-       void set_rootdir(const char *rootdir)
-       $pool->set_rootdir(rootdir);
-       pool.set_rootdir(rootdir)
-       pool.set_rootdir(rootdir)
-
-       const char *get_rootdir()
-       my $rootdir = $pool->get_rootdir();
-       rootdir = pool.get_rootdir()
-       rootdir = pool.get_rootdir()
-
-Set/get the rootdir to use. This is useful if you want package management
-to work only in some directory, for example if you want to setup a chroot
-jail. Note that the rootdir will only be prepended to file paths if the
-*REPO_USE_ROOTDIR* flag is used.
-
-       void setarch(const char *arch = 0)
-       $pool->setarch();
-       pool.setarch()
-       pool.setarch()
-
-Set the architecture for your system. The architecture is used to determine
-which packages are installable. It defaults to the result of ``uname -m''.
-
-       Repo add_repo(const char *name)
-       $repo = $pool->add_repo($name);
-       repo = pool.add_repo(name)
-       repo = pool.add_repo(name)
-
-Add a Repository with the specified name to the pool. The repository is empty
-on creation, use the repository methods to populate it with packages.
-
-       Repoiterator repos_iter()
-       for my $repo (@{$pool->repos_iter()})
-       for repo in pool.repos_iter():
-       for repo in pool.repos_iter()
-
-Iterate over the existing repositories.
-
-       Solvableiterator solvables_iter()
-       for my $solvable (@{$pool->solvables_iter()})
-       for solvable in pool.solvables_iter():
-       for solvable in pool.solvables_iter()
-
-Iterate over the existing solvables.
-
-       Dep Dep(const char *str, bool create = 1)
-       my $dep = $pool->Dep($string);
-       dep = pool.Dep(string)
-       dep = pool.Dep(string)
-
-Create an object describing a string or dependency. If the string is currently
-not in the pool and _create_ is false, *undef*/*None*/*nil* is returned.
-
-       void addfileprovides()
-       $pool->addfileprovides();
-       pool.addfileprovides()
-       pool.addfileprovides()
-
-       Id *addfileprovides_queue()
-       my @ids = $pool->addfileprovides_queue();
-       ids = pool.addfileprovides_queue()
-       ids = pool.addfileprovides_queue()
-
-Some package managers like rpm allow dependencies on files contained in other
-packages. To allow libsolv to deal with those dependencies in an efficient way,
-you need to call the addfileprovides method after creating and reading all
-repositories. This method will scan all dependency for file names and then scan
-all packages for matching files. If a filename has been matched, it will be
-added to the provides list of the corresponding package. The
-addfileprovides_queue variant works the same way but returns an array
-containing all file dependencies. This information can be stored in the
-meta section of the repositories to speed up the next time the
-repository is loaded and addfileprovides is called.
-
-       void createwhatprovides()
-       $pool->createwhatprovides();
-       pool.createwhatprovides()
-       pool.createwhatprovides()
-
-Create the internal ``whatprovides'' hash over all of the provides of all
-packages. This method must be called before doing any lookups on provides.
-It's encouraged to do it right after all repos are set up, usually right after
-the call to addfileprovides().
-
-       Solvable *whatprovides(DepId dep)
-       my @solvables = $pool->whatprovides($dep);
-       solvables = pool.whatprovides(dep)
-       solvables = pool.whatprovides(dep)
-
-Return all solvables that provide the specified dependency. You can use either
-a Dep object or a simple Id as argument.
-
-       Id *matchprovidingids(const char *match, int flags)
-       my @ids = $pool->matchprovidingids($match, $flags);
-       ids = pool.matchprovidingids(match, flags)
-       ids = pool.matchprovidingids(match, flags)
-
-Search the names of all provides and return the ones matching the specified
-string. See the Dataiterator class for the allowed flags.
-
-       Id towhatprovides(Id *ids)
-       my $offset = $pool->towhatprovides(\@ids);
-       offset = pool.towhatprovides(ids)
-       offset = pool.towhatprovides(ids)
-
-``Internalize'' an array containing Ids. The returned value can be used to
-create solver jobs working on a specific set of packages. See the Solver class
-for more information.
-
-       bool isknownarch(DepId id)
-       my $bool = $pool->isknownarch($id);
-       bool = pool.isknownarch(id)
-       bool = pool.isknownarch?(id)
-
-Return true if the specified Id describes a known architecture.
-
-       Solver Solver()
-       my $solver = $pool->Solver();
-       solver = pool.Solver()
-       solver = pool.Solver()
-
-Create a new solver object.
-
-       Job Job(int how, Id what)
-       my $job = $pool->Job($how, $what);
-       job = pool.Job(how, what)
-       job = pool.Job(how, what)
-
-Create a new Job object. Kind of low level, in most cases you would use a
-Selection or Dep job constructor instead.
-
-       Selection Selection()
-       my $sel = $pool->Selection();
-       sel = pool.Selection()
-       sel = pool.Selection()
-
-Create an empty selection. Useful as a starting point for merging other
-selections.
-
-       Selection Selection_all()
-       my $sel = $pool->Selection_all();
-       sel = pool.Selection_all()
-       sel = pool.Selection_all()
-       
-Create a selection containing all packages. Useful as starting point for
-intersecting other selections or for update/distupgrade jobs.
-
-       Selection select(const char *name, int flags)
-       my $sel = $pool->select($name, $flags);
-       sel = pool.select(name, flags)
-       sel = pool.select(name, flags)
-
-Create a selection by matching packages against the specified string. See the
-Selection class for a list of flags and how to create solver jobs from a
-selection.
-
-       void setpooljobs(Jobs *jobs)
-       $pool->setpooljobs(\@jobs);
-       pool.setpooljobs(jobs)
-       pool.setpooljobs(jobs)
-
-       Job *getpooljobs()
-       @jobs = $pool->getpooljobs();
-       jobs = pool.getpooljobs()
-       jobs = pool.getpooljobs()
-
-Get/Set fixed jobs stored in the pool. Those jobs are automatically appended to
-all solver jobs, they are meant for fixed configurations like which packages
-can be multiversion installed, which packages were userinstalled or must not be
-erased.
-
-       void set_loadcallback(Callable *callback)
-       $pool->setloadcallback(\&callbackfunction);
-       pool.setloadcallback(callbackfunction)
-       pool.setloadcallback { |repodata| ... }
-
-Set the callback function called when repository metadata needs to be loaded on
-demand. To make use of this feature, you need to create repodata stubs that
-tell the library which data is available but not loaded. If later on the data
-needs to be accessed, the callback function is called with a repodata argument.
-You can then load the data (maybe fetching it first from a remote server).
-The callback should return true if the data has been made available.
-
-       /* bindings only */
-       $pool->appdata_disown()
-       pool.appdata_disown()
-       pool.appdata_disown()
-
-Decrement the reference count of the appdata object. This can be used to break
-circular references (e.g. if the pool's appdata value points to some meta data
-structure that contains a pool handle). If used incorrectly, this method can
-lead to application crashes, so beware. (This method is a no-op for ruby and tcl.)
-
-=== DATA RETRIEVAL METHODS ===
-
-In the following functions, the _keyname_ argument describes what to retrieve.
-For the standard cases you can use the available Id constants. For example,
-
-       $solv::SOLVABLE_SUMMARY
-       solv.SOLVABLE_SUMMARY
-       Solv::SOLVABLE_SUMMARY
-
-selects the ``Summary'' entry of a solvable. The _solvid_ argument selects the
-desired solvable by Id.
-
-       const char *lookup_str(Id solvid, Id keyname)
-       my $string = $pool->lookup_str($solvid, $keyname);
-       string = pool.lookup_str(solvid, keyname)
-       string = pool.lookup_str(solvid, keyname)
-
-       Id lookup_id(Id solvid, Id keyname)
-       my $id = $pool->lookup_id($solvid, $keyname);
-       id = pool.lookup_id(solvid, keyname)
-       id = pool.lookup_id(solvid, keyname)
-
-       unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0)
-       my $num = $pool->lookup_num($solvid, $keyname);
-       num = pool.lookup_num(solvid, keyname)
-       num = pool.lookup_num(solvid, keyname)
-
-       bool lookup_void(Id solvid, Id keyname)
-       my $bool = $pool->lookup_void($solvid, $keyname);
-       bool = pool.lookup_void(solvid, keyname)
-       bool = pool.lookup_void(solvid, keyname)
-
-       Id *lookup_idarray(Id solvid, Id keyname)
-       my @ids = $pool->lookup_idarray($solvid, $keyname);
-       ids = pool.lookup_idarray(solvid, keyname)
-       ids = pool.lookup_idarray(solvid, keyname)
-
-       Chksum lookup_checksum(Id solvid, Id keyname)
-       my $chksum = $pool->lookup_checksum($solvid, $keyname);
-       chksum = pool.lookup_checksum(solvid, keyname)
-       chksum = pool.lookup_checksum(solvid, keyname)
-
-Lookup functions. Return the data element stored in the specified solvable.
-You should probably use the methods of the Solvable class instead.
-
-       Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0)
-       my $di = $pool->Dataiterator($keyname, $match, $flags);
-       di = pool.Dataiterator(keyname, match, flags)
-       di = pool.Dataiterator(keyname, match, flags)
-
-       Dataiterator Dataiterator_solvid(Id solvid, Id keyname, const char *match = 0, int flags = 0)
-       my $di = $pool->Dataiterator($solvid, $keyname, $match, $flags);
-       di = pool.Dataiterator(solvid, keyname, match, flags)
-       di = pool.Dataiterator(solvid, keyname, match, flags)
-
-       for my $d (@$di)
-       for d in di:
-       for d in di
-
-Iterate over the matching data elements. See the Dataiterator class for more
-information. The Dataiterator method iterates over all solvables in the pool,
-whereas the Dataiterator_solvid only iterates over the specified solvable.
-
-=== ID METHODS ===
-
-The following methods deal with Ids, i.e. integers representing objects in the
-pool. They are considered ``low level'', in most cases you would not use them
-but instead the object orientated methods.
-
-       Repo id2repo(Id id)
-       $repo = $pool->id2repo($id);
-       repo = pool.id2repo(id)
-       repo = pool.id2repo(id)
-
-Lookup an existing Repository by id. You can also do this by using the *repos*
-attribute.
-
-       Solvable id2solvable(Id id)
-       $solvable = $pool->id2solvable($id);
-       solvable = pool.id2solvable(id)
-       solvable = pool.id2solvable(id)
-
-Lookup an existing Repository by id. You can also do this by using the
-*solvables* attribute.
-
-       const char *solvid2str(Id id)
-       my $str = $pool->solvid2str($id);
-       str = pool.solvid2str(id)
-       str = pool.solvid2str(id)
-
-Return a string describing the Solvable with the specified id. The string
-consists of the name, version, and architecture of the Solvable.
-
-       Id str2id(const char *str, bool create = 1)
-       my $id = pool->str2id($string);
-       id = pool.str2id(string)
-       id = pool.str2id(string)
-
-       const char *id2str(Id id)
-       $string = pool->id2str($id);
-       string = pool.id2str(id)
-       string = pool.id2str(id)
-
-Convert a string into an Id and back. If the string is currently not in the
-pool and _create_ is false, zero is returned.
-
-       Id rel2id(Id name, Id evr, int flags, bool create = 1)
-       my $id = pool->rel2id($nameid, $evrid, $flags);
-       id = pool.rel2id(nameid, evrid, flags)
-       id = pool.rel2id(nameid, evrid, flags)
-
-Create a ``relational'' dependency. Such dependencies consist of a name part,
-the _flags_ describing the relation, and a version part. The flags are:
-
-       $solv::REL_EQ | $solv::REL_GT | $solv::REL_LT
-       solv.REL_EQ | solv.REL_GT | solv.REL_LT
-       Solv::REL_EQ | Solv::REL_GT | Solv::REL_LT
-
-Thus, if you want a ``\<='' relation, you would use *REL_LT | REL_EQ*.
-
-       Id id2langid(Id id, const char *lang, bool create = 1)
-       my $id = $pool->id2langid($id, $language);
-       id = pool.id2langid(id, language)
-       id = pool.id2langid(id, language)
-
-Create a language specific Id from some other id. This function simply converts
-the id into a string, appends a dot and the specified language to the string
-and converts the result back into an Id.
-
-       const char *dep2str(Id id)
-       $string = pool->dep2str($id);
-       string = pool.dep2str(id)
-       string = pool.dep2str(id)
-
-Convert a dependency id into a string. If the id is just a string, this
-function has the same effect as id2str(). For relational dependencies, the
-result is the correct ``name relation evr'' string.
-
-
-The Dependency Class
---------------------
-The dependency class is an object orientated way to work with strings and
-dependencies. Internally, dependencies are represented as Ids, i.e. simple
-numbers. Dependency objects can be constructed by using the Pool's Dep()
-method.
-
-=== ATTRIBUTES ===
-
-       Pool *pool;             /* read only */
-       $dep->{pool}
-       dep.pool
-       dep.pool
-
-Back reference to the pool this dependency belongs to.
-
-       Id id;          /* read only */
-       $dep->{id}
-       dep.id
-       dep.id
-
-The id of this dependency.
-
-== Methods ==
-
-       Dep Rel(int flags, DepId evrid, bool create = 1)
-       my $reldep = $dep->Rel($flags, $evrdep);
-       reldep = dep.Rel(flags, evrdep)
-       reldep = dep.Rel(flags, evrdep)
-
-Create a relational dependency from to string dependencies and a flags
-argument. See the pool's rel2id method for a description of the flags.
-
-       Selection Selection_name(int setflags = 0)
-       my $sel = $dep->Selection_name();
-       sel = dep.Selection_name()
-       sel = dep.Selection_name()
-
-Create a Selection from a dependency. The selection consists of all packages
-that have a name equal to the dependency. If the dependency is of a relational
-type, the packages version must also fulfill the dependency.
-
-       Selection Selection_provides(int setflags = 0)
-       my $sel = $dep->Selection_provides();
-       sel = dep.Selection_provides()
-       sel = dep.Selection_provides()
-
-Create a Selection from a dependency. The selection consists of all packages
-that have at least one provides matching the dependency.
-
-       const char *str()
-       my $str = $dep->str();
-       str = $dep.str()
-       str = $dep.str()
-
-Return a string describing the dependency.
-
-       <stringification>
-       my $str = $dep->str;
-       str = str(dep)
-       str = dep.to_s
-
-Same as calling the str() method.
-
-       <equality>
-       if ($dep1 == $dep2)
-       if dep1 == dep2:
-       if dep1 == dep2
-
-The dependencies are equal if they are part of the same pool and have the same
-ids.
-
-
-The Repository Class
---------------------
-A Repository describes a group of packages, normally coming from the same
-source. Repositories are created by the Pool's add_repo() method.
-
-=== ATTRIBUTES ===
-
-       Pool *pool;                     /* read only */
-       $repo->{pool}
-       repo.pool
-       repo.pool
-
-Back reference to the pool this dependency belongs to.
-
-       Id id;                          /* read only */
-       $repo->{id}
-       repo.id
-       repo.id
-
-The id of the repository.
-
-       const char *name;               /* read/write */
-       $repo->{name}
-       repo.name
-       repo.name
-       
-The repositories name. To libsolv, the name is just a string with no specific
-meaning.
-
-       int priority;                   /* read/write */
-       $repo->{priority}
-       repo.priority
-       repo.priority
-
-The priority of the repository. A higher number means that packages of this
-repository will be chosen over other repositories, even if they have a greater
-package version.
-
-       int subpriority;                /* read/write */
-       $repo->{subpriority}
-       repo.subpriority
-       repo.subpriority
-
-The sub-priority of the repository. This value is compared when the priorities
-of two repositories are the same. It is useful to make the library prefer
-on-disk repositories to remote ones.
-
-       int nsolvables;                 /* read only */
-       $repo->{nsolvables}
-       repo.nsolvables
-       repo.nsolvables
-
-The number of solvables in this repository.
-
-       void *appdata;                  /* read/write */
-       $repo->{appdata}
-       repo.appdata
-       repo.appdata
-
-Application specific data that may be used in any way by the code using the
-repository.
-
-       Datapos *meta;                  /* read only */
-       $repo->{meta}
-       repo.meta
-       repo.meta
-
-Return a Datapos object of the repodata's metadata. You can use the lookup
-methods of the Datapos class to lookup metadata attributes, like the repository
-timestamp.
-
-=== CONSTANTS ===
-
-*REPO_REUSE_REPODATA*::
-Reuse the last repository data area (``repodata'') instead of creating a
-new one.
-
-*REPO_NO_INTERNALIZE*::
-Do not internalize the added repository data. This is useful if
-you plan to add more data because internalization is a costly
-operation.
-
-*REPO_LOCALPOOL*::
-Use the repodata's pool for Id storage instead of the global pool. Useful
-if you don't want to pollute the global pool with many unneeded ids, like
-when storing the filelist.
-
-*REPO_USE_LOADING*::
-Use the repodata that is currently being loaded instead of creating a new
-one. This only makes sense if used in a load callback.
-
-*REPO_EXTEND_SOLVABLES*::
-Do not create new solvables for the new data, but match existing solvables
-and add the data to them. Repository metadata is often split into multiple
-parts, with one primary file describing all packages and other parts
-holding information that is normally not needed, like the changelog.
-
-*REPO_USE_ROOTDIR*::
-Prepend the pool's rootdir to the path when doing file operations.
-
-*REPO_NO_LOCATION*::
-Do not add a location element to the solvables. Useful if the solvables
-are not in the final position, so you can add the correct location later
-in your code.
-
-*SOLV_ADD_NO_STUBS*::
-Do not create stubs for repository parts that can be downloaded on demand.
-
-*SUSETAGS_RECORD_SHARES*::
-This is specific to the add_susetags() method. Susetags allows one to refer to
-already read packages to save disk space. If this data sharing needs to
-work over multiple calls to add_susetags, you need to specify this flag so
-that the share information is made available to subsequent calls.
-
-=== METHODS ===
-
-       void free(bool reuseids = 0)
-       $repo->free();
-       repo.free()
-       repo.free()
-
-Free the repository and all solvables it contains. If _reuseids_ is set to
-true, the solvable ids and the repository id may be reused by the library when
-added new solvables. Thus you should leave it false if you are not sure that
-somebody holds a reference.
-
-       void empty(bool reuseids = 0)
-       $repo->empty();
-       repo.empty()
-       repo.empty()
-
-Free all the solvables in a repository. The repository will be empty after this
-call. See the free() method for the meaning of _reuseids_.
-
-       bool isempty()
-       $repo->isempty()
-       repo.empty()
-       repo.empty?
-
-Return true if there are no solvables in this repository.
-
-       void internalize()
-       $repo->internalize();
-       repo.internalize()
-       repo.internalize()
-
-Internalize added data. Data must be internalized before it is available to the
-lookup and data iterator functions.
-
-       bool write(FILE *fp)
-       $repo->write($fp)
-       repo.write(fp)
-       repo.write(fp)
-
-Write a repo as a ``solv'' file. These files can be read very fast and thus are
-a good way to cache repository data. Returns false if there was some error
-writing the file.
-
-       Solvableiterator solvables_iter()
-       for my $solvable (@{$repo->solvables_iter()})
-       for solvable in repo.solvables_iter():
-       for solvable in repo.solvables_iter()
-
-Iterate over all solvables in a repository.
-
-       Repodata add_repodata(int flags = 0)
-       my $repodata = $repo->add_repodata();
-       repodata = repo.add_repodata()
-       repodata = repo.add_repodata()
-
-Add a new repodata area to the repository. This is normally automatically
-done by the repo_add methods, so you need this method only in very
-rare circumstances.
-
-       void create_stubs()
-       $repo->create_stubs();
-       repo.create_stubs()
-       repo.create_stubs()
-
-Calls the create_stubs() repodata method for the last repodata of the
-repository.
-
-       bool iscontiguous()
-       $repo->iscontiguous()
-       repo.iscontiguous()
-       repo.iscontiguous?
-
-Return true if the solvables of this repository are all in a single block with
-no holes, i.e. they have consecutive ids.
-
-       Repodata first_repodata()
-       my $repodata = $repo->first_repodata();
-       repodata = repo.first_repodata()
-       repodata = repo.first_repodata()
-
-Checks if all repodatas but the first repodata are extensions, and return the
-first repodata if this is the case. Useful if you want to do a store/retrieve
-sequence on the repository to reduce the memory using and enable paging, as
-this does not work if the repository contains multiple non-extension repodata
-areas.
-
-       Selection Selection(int setflags = 0)
-       my $sel = $repo->Selection();
-       sel = repo.Selection()
-       sel = repo.Selection()
-
-Create a Selection consisting of all packages in the repository.
-
-       Dataiterator Dataiterator(Id key, const char *match = 0, int flags = 0)
-       my $di = $repo->Dataiterator($keyname, $match, $flags);
-       di = repo.Dataiterator(keyname, match, flags)
-       di = repo.Dataiterator(keyname, match, flags)
-
-       Dataiterator Dataiterator_meta(Id key, const char *match = 0, int flags = 0)
-       my $di = $repo->Dataiterator_meta($keyname, $match, $flags);
-       di = repo.Dataiterator_meta(keyname, match, flags)
-       di = repo.Dataiterator_meta(keyname, match, flags)
-
-       for my $d (@$di)
-       for d in di:
-       for d in di
-
-Iterate over the matching data elements in this repository. See the
-Dataiterator class for more information. The Dataiterator() method
-iterates over all solvables in a repository, whereas the Dataiterator_meta
-method only iterates over the repository's meta data.
-
-       <stringification>
-       my $str = $repo->str;
-       str = str(repo)
-       str = repo.to_s
-
-Return the name of the repository, or "Repo#<id>" if no name is set.
-
-       <equality>
-       if ($repo1 == $repo2)
-       if repo1 == repo2:
-       if repo1 == repo2
-
-Two repositories are equal if they belong to the same pool and have the same id.
-
-=== DATA ADD METHODS ===
-
-       Solvable add_solvable()
-       $repo->add_solvable();
-       repo.add_solvable()
-       repo.add_solvable()
-
-Add a single empty solvable to the repository. Returns a Solvable object, see
-the Solvable class for more information.
-
-       bool add_solv(const char *name, int flags = 0)
-       $repo->add_solv($name);
-       repo.add_solv(name)
-       repo.add_solv(name)
-
-       bool add_solv(FILE *fp, int flags = 0)
-       $repo->add_solv($fp);
-       repo.add_solv(fp)
-       repo.add_solv(fp)
-
-Read a ``solv'' file and add its contents to the repository. These files can be
-written with the write() method and are normally used as fast cache for
-repository metadata.
-
-       bool add_rpmdb(int flags = 0)
-       $repo->add_rpmdb();
-       repo.add_rpmdb()
-       repo.add_rpmdb()
-
-       bool add_rpmdb_reffp(FILE *reffp, int flags = 0)
-       $repo->add_rpmdb_reffp($reffp);
-       repo.add_rpmdb_reffp(reffp)
-       repo.add_rpmdb_reffp(reffp)
-
-Add the contents of the rpm database to the repository. If a solv file
-containing an old version of the database is available, it can be passed as
-reffp to speed up reading.
-
-       Solvable add_rpm(const char *filename, int flags = 0)
-       my $solvable = $repo->add_rpm($filename);
-       solvable = repo.add_rpm(filename)
-       solvable = repo.add_rpm(filename)
-
-Add the metadata of a single rpm package to the repository.
-
-       bool add_rpmdb_pubkeys(int flags = 0)
-       $repo->add_rpmdb_pubkeys();
-       repo.add_rpmdb_pubkeys()
-       repo.add_rpmdb_pubkeys()
-
-Add all pubkeys contained in the rpm database to the repository. Note that
-newer rpm versions also allow to store the pubkeys in some directory instead
-of the rpm database.
-
-       Solvable add_pubkey(const char *keyfile, int flags = 0)
-       my $solvable = $repo->add_pubkey($keyfile);
-       solvable = repo.add_pubkey(keyfile)
-       solvable = repo.add_pubkey(keyfile)
-
-Add a pubkey from a file to the repository.
-
-       bool add_rpmmd(FILE *fp, const char *language, int flags = 0)
-       $repo->add_rpmmd($fp, undef);
-       repo.add_rpmmd(fp, None)
-       repo.add_rpmmd(fp, nil)
-
-Add metadata stored in the "rpm-md" format (i.e. from files in the ``repodata''
-directory) to a repository. Supported files are "primary", "filelists",
-"other", "suseinfo". Do not forget to specify the *REPO_EXTEND_SOLVABLES* for
-extension files like "filelists" and "other". Use the _language_ parameter if
-you have language extension files, otherwise simply use a *undef*/*None*/*nil*
-parameter.
-
-       bool add_repomdxml(FILE *fp, int flags = 0)
-       $repo->add_repomdxml($fp);
-       repo.add_repomdxml(fp)
-       repo.add_repomdxml(fp)
-
-Add the repomd.xml meta description from the "rpm-md" format to the repository.
-This file contains information about the repository like keywords, and also a
-list of all database files with checksums. The data is added to the "meta"
-section of the repository, i.e. no package gets created.
-
-       bool add_updateinfoxml(FILE *fp, int flags = 0)
-       $repo->add_updateinfoxml($fp);
-       repo.add_updateinfoxml(fp)
-       repo.add_updateinfoxml(fp)
-
-Add the updateinfo.xml file containing available maintenance updates to the
-repository. All updates are created as special packages that have a "patch:"
-prefix in their name.
-
-       bool add_deltainfoxml(FILE *fp, int flags = 0)
-       $repo->add_deltainfoxml($fp);
-       repo.add_deltainfoxml(fp)
-       repo.add_deltainfoxml(fp)
-
-Add the deltainfo.xml file (also called prestodelta.xml) containing available
-delta-rpms to the repository. The data is added to the "meta" section, i.e. no
-package gets created.
-
-       bool add_debdb(int flags = 0)
-       $repo->add_debdb();
-       repo.add_debdb()
-       repo.add_debdb()
-
-Add the contents of the debian installed package database to the repository.
-
-       bool add_debpackages(FILE *fp, int flags = 0)
-       $repo->add_debpackages($fp);
-       repo.add_debpackages($fp)
-       repo.add_debpackages($fp)
-
-Add the contents of the debian repository metadata (the "packages" file)
-to the repository.
-
-       Solvable add_deb(const char *filename, int flags = 0)
-       my $solvable = $repo->add_deb($filename);
-       solvable = repo.add_deb(filename)
-       solvable = repo.add_deb(filename)
-
-Add the metadata of a single deb package to the repository.
-
-       bool add_mdk(FILE *fp, int flags = 0)
-       $repo->add_mdk($fp);
-       repo.add_mdk(fp)
-       repo.add_mdk(fp)
-
-Add the contents of the mageia/mandriva repository metadata (the
-"synthesis.hdlist" file) to the repository.
-
-       bool add_mdk_info(FILE *fp, int flags = 0)
-       $repo->add_mdk($fp);
-       repo.add_mdk(fp)
-       repo.add_mdk(fp)
-
-Extend the packages from the synthesis file with the info.xml and files.xml
-data. Do not forget to specify *REPO_EXTEND_SOLVABLES*.
-
-       bool add_arch_repo(FILE *fp, int flags = 0)
-       $repo->add_arch_repo($fp);
-       repo.add_arch_repo(fp)
-       repo.add_arch_repo(fp)
-
-Add the contents of the archlinux repository metadata (the ".db.tar" file) to
-the repository.
-
-       bool add_arch_local(const char *dir, int flags = 0)
-       $repo->add_arch_local($dir);
-       repo.add_arch_local(dir)
-       repo.add_arch_local(dir)
-
-Add the contents of the archlinux installed package database to the repository.
-The _dir_ parameter is usually set to "/var/lib/pacman/local".
-
-       bool add_content(FILE *fp, int flags = 0)
-       $repo->add_content($fp);
-       repo.add_content(fp)
-       repo.add_content(fp)
-
-Add the ``content'' meta description from the susetags format to the repository.
-This file contains information about the repository like keywords, and also
-a list of all database files with checksums. The data is added to the "meta"
-section of the repository, i.e. no package gets created.
-
-       bool add_susetags(FILE *fp, Id defvendor, const char *language, int flags = 0)
-       $repo->add_susetags($fp, $defvendor, $language);
-       repo.add_susetags(fp, defvendor, language)
-       repo.add_susetags(fp, defvendor, language)
-
-Add repository metadata in the susetags format to the repository. Like with
-add_rpmmd, you can specify a language if you have language extension files. The
-_defvendor_ parameter provides a default vendor for packages with missing
-vendors, it is usually provided in the content file.
-
-       bool add_products(const char *dir, int flags = 0)
-       $repo->add_products($dir);
-       repo.add_products(dir)
-       repo.add_products(dir)
-
-Add the installed SUSE products database to the repository. The _dir_ parameter
-is usually "/etc/products.d".
-
-
-The Solvable Class
-------------------
-A solvable describes all the information of one package. Each solvable
-belongs to one repository, it can be added and filled manually but in
-most cases solvables will get created by the repo_add methods.
-
-=== ATTRIBUTES ===
-
-       Repo *repo;                     /* read only */
-       $solvable->{repo}
-       solvable.repo
-       solvable.repo
-
-The repository this solvable belongs to.
-
-       Pool *pool;                     /* read only */
-       $solvable->{pool}
-       solvable.pool
-       solvable.pool
-
-The pool this solvable belongs to, same as the pool of the repo.
-
-       Id id;                          /* read only */
-       $solvable->{id}
-       solvable.id
-       solvable.id
-
-The specific id of the solvable.
-
-       char *name;                     /* read/write */
-       $solvable->{name}
-       solvable.name
-       solvable.name
-
-       char *evr;                      /* read/write */
-       $solvable->{evr}
-       solvable.evr
-       solvable.evr
-
-       char *arch;                     /* read/write */
-       $solvable->{arch}
-       solvable.arch
-       solvable.arch
-
-       char *vendor;                   /* read/write */
-       $solvable->{vendor}
-       solvable.vendor
-       solvable.vendor
-
-Easy access to often used attributes of solvables. They are
-internally stored as Ids.
-
-       Id nameid;                      /* read/write */
-       $solvable->{nameid}
-       solvable.nameid
-       solvable.nameid
-
-       Id evrid;                       /* read/write */
-       $solvable->{evrid}
-       solvable.evrid
-       solvable.evrid
-
-       Id archid;                      /* read/write */
-       $solvable->{archid}
-       solvable.archid
-       solvable.archid
-
-       Id vendorid;                    /* read/write */
-       $solvable->{vendorid}
-       solvable.vendorid
-       solvable.vendorid
-
-Raw interface to the ids. Useful if you want to search for
-a specific id and want to avoid the string compare overhead.
-
-=== METHODS ===
-
-       const char *lookup_str(Id keyname)
-       my $string = $solvable->lookup_str($keyname);
-       string = solvable.lookup_str(keyname)
-       string = solvable.lookup_str(keyname)
-
-       Id lookup_id(Id keyname)
-       my $id = $solvable->lookup_id($keyname);
-       id = solvable.lookup_id(solvid)
-       id = solvable.lookup_id(solvid)
-
-       unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0)
-       my $num = $solvable->lookup_num($keyname);
-       num = solvable.lookup_num(keyname)
-       num = solvable.lookup_num(keyname)
-
-       bool lookup_void(Id keyname)
-       my $bool = $solvable->lookup_void($keyname);
-       bool = solvable.lookup_void(keyname)
-       bool = solvable.lookup_void(keyname)
-
-       Chksum lookup_checksum(Id keyname)
-       my $chksum = $solvable->lookup_checksum($keyname);
-       chksum = solvable.lookup_checksum(keyname)
-       chksum = solvable.lookup_checksum(keyname)
-
-       Id *lookup_idarray(Id keyname, Id marker = -1)
-       my @ids = $solvable->lookup_idarray($keyname);
-       ids = solvable.lookup_idarray(keyname)
-       ids = solvable.lookup_idarray(keyname)
-
-       Dep *lookup_deparray(Id keyname, Id marker = -1)
-       my @deps = $solvable->lookup_deparray($keyname);
-       deps = solvable.lookup_deparray(keyname)
-       deps = solvable.lookup_deparray(keyname)
-       
-Generic lookup methods. Retrieve data stored for the specific keyname.
-The lookup_idarray() method will return an array of Ids, use
-lookup_deparray if you want an array of Dependency objects instead.
-Some Id arrays contain two parts of data divided by a specific marker,
-for example the provides array uses the SOLVABLE_FILEMARKER id to
-store both the ids provided by the package and the ids added by
-the addfileprovides method. The default, -1, translates to the
-correct marker for the keyname and returns the first part of the
-array, use 1 to select the second part or 0 to retrieve all ids
-including the marker.
-
-       const char *lookup_location(unsigned int *OUTPUT);
-       my ($location, $medianr) = $solvable->lookup_location();
-       location, medianr = solvable.lookup_location()
-       location, medianr = solvable.lookup_location()
-
-Return a tuple containing the on-media location and an optional
-media number for multi-part repositories (e.g. repositories
-spawning multiple DVDs).
-
-       Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0)
-       my $di = $solvable->Dataiterator($keyname, $match, $flags);
-       di = solvable.Dataiterator(keyname, match, flags)
-       di = solvable.Dataiterator(keyname, match, flags)
-
-       for my $d (@$di)
-       for d in di:
-       for d in di
-
-Iterate over the matching data elements. See the Dataiterator class for more
-information.
-
-       void add_deparray(Id keyname, DepId dep, Id marker = -1);
-       $solvable->add_deparray($keyname, $dep);
-       solvable.add_deparray(keyname, dep)
-       solvable.add_deparray(keyname, dep)
-
-Add a new dependency to the attributes stored in keyname.
-
-       void unset(Id keyname);
-       $solvable->unset($keyname);
-       solvable.unset(keyname)
-       solvable.unset(keyname)
-
-Delete data stored for the specific keyname.
-
-       bool installable();
-       $solvable->installable()
-       solvable.installable()
-       solvable.installable?
-
-Return true if the solvable is installable on the system. Solvables
-are not installable if the system does not support their architecture.
-
-       bool isinstalled();
-       $solvable->isinstalled()
-       solvable.isinstalled()
-       solvable.isinstalled?
-
-Return true if the solvable is installed on the system.
-
-       bool identical(Solvable *other)
-       $solvable->identical($other)
-       $solvable.identical(other)
-       $solvable.identical?(other)
-
-Return true if the two solvables are identical.
-
-       int evrcmp(Solvable *other)
-       $solvable->evrcmp(other)
-       $solvable.evrcmp(other)
-       $solvable.evrcmp(other)
-
-Returns -1 if the epoch/version/release of the solvable is less than the
-one from the other solvable, 1 if it is greater, and 0 if they are equal.
-Note that "equal" does not mean that the evr is identical.
-
-       Selection Selection(int setflags = 0)
-       my $sel = $solvable->Selection();
-       sel = solvable.Selection()
-       sel = solvable.Selection()
-
-Create a Selection containing just the single solvable.
-
-       const char *str()
-       my $str = $solvable->str();
-       str = $solvable.str()
-       str = $solvable.str()
-
-Return a string describing the solvable. The string consists of the name,
-version, and architecture of the Solvable.
-
-       <stringification>
-       my $str = $solvable->str;
-       str = str(solvable)
-       str = solvable.to_s
-
-Same as calling the str() method.
-
-       <equality>
-       if ($solvable1 == $solvable2)
-       if solvable1 == solvable2:
-       if solvable1 == solvable2
-
-Two solvables are equal if they are part of the same pool and have the same
-ids.
-
-
-The Dataiterator Class
-----------------------
-Dataiterators can be used to do complex string searches or
-to iterate over arrays. They can be created via the
-constructors in the Pool, Repo, and Solvable classes. The
-Repo and Solvable constructors will limit the search to
-the repository or the specific package.
-
-=== CONSTANTS ===
-
-*SEARCH_STRING*::
-Return a match if the search string matches the value.
-
-*SEARCH_STRINGSTART*::
-Return a match if the value starts with the search string.
-
-*SEARCH_STRINGEND*::
-Return a match if the value ends with the search string.
-
-*SEARCH_SUBSTRING*::
-Return a match if the search string can be matched somewhere in the value.
-
-*SEARCH_GLOB*::
-Do a glob match of the search string against the value.
-
-*SEARCH_REGEX*::
-Do a regular expression match of the search string against the value.
-
-*SEARCH_NOCASE*::
-Ignore case when matching strings. Works for all the above match types.
-
-*SEARCH_FILES*::
-Match the complete filenames of the file list, not just the base name.
-
-*SEARCH_COMPLETE_FILELIST*::
-When matching the file list, check every file of the package not just the
-subset from the primary metadata.
-
-*SEARCH_CHECKSUMS*::
-Allow the matching of checksum entries.
-
-=== METHODS ===
-
-       void prepend_keyname(Id keyname);
-       $di->prepend_keyname($keyname);
-       di.prepend_keyname(keyname)
-       di.prepend_keyname(keyname)
-
-Do a sub-search in the array stored in keyname.
-
-       void skip_solvable();
-       $di->kip_solvable();
-       di.skip_solvable()
-       di.skip_solvable()
-
-Stop matching the current solvable and advance to the next
-one.
-
-       <iteration>
-       for my $d (@$di)
-       for d in di:
-       for d in di
-
-Iterate through the matches. If there is a match, the object
-in d will be of type Datamatch.
-
-The Datamatch Class
--------------------
-Objects of this type will be created for every value matched
-by a dataiterator.
-
-=== ATTRIBUTES ===
-
-       Pool *pool;                             /* read only */
-       $d->{pool}
-       d.pool
-       d.pool
-
-Back pointer to pool.
-
-       Repo *repo;                             /* read only */
-       $d->{repo}
-       d.repo
-       d.repo
-
-The repository containing the matched object.
-
-       Solvable *solvable;                     /* read only */
-       $d->{solvable}
-       d.solvable
-       d.solvable
-
-The solvable containing the value that was matched.
-
-       Id solvid;                              /* read only */
-       $d->{solvid}
-       d.solvid
-       d.solvid
-
-The id of the solvable that matched.
-
-       Id key_id;
-       $d->{key_id}
-       d.key_id
-       d.key_id
-
-       const char *key_idstr;
-       $d->{key_idstr}
-       d.key_idstr
-       d.key_idstr
-
-The keyname that matched, either as id or string.
-
-       Id type_id;
-       $d->{type_id}
-       d.type_id
-       d.type_id
-
-       const char *type_idstr;
-       $d->{type_idstr};
-       d.type_idstr
-       d.type_idstr
-
-The key type of the value that was matched, either as id or string.
-
-       Id id;
-       $d->{id}
-       d.id
-       d.id
-
-       Id idstr;
-       $d->{idstr}
-       d.idstr
-       d.idstr
-
-The Id of the value that was matched (only valid for id types),
-either as id or string.
-
-       const char *str;
-       $d->{str}
-       d.str
-       d.str
-
-The string value that was matched (only valid for string types).
-
-       unsigned long long num;
-       $d->{num}
-       d.num
-       d.num
-
-The numeric value that was matched (only valid for numeric types).
-
-       unsigned int num2;
-       $d->{num2}
-       d.num2
-       d.num2
-
-The secondary numeric value that was matched (only valid for types
-containing two values).
-
-       unsigned int binary;
-       $d->{binary}
-       d.binary
-       d.binary
-
-The value in binary form, useful for checksums and other data
-that cannot be represented as a string.
-
-=== METHODS ===
-
-       Datapos pos();
-       my $pos = $d->pos();
-       pos = d.pos()
-       pos = d.pos()
-
-The position object of the current match. It can be used to do
-sub-searches starting at the match (if it is of an array type).
-See the Datapos class for more information.
-
-       Datapos parentpos();
-       my $pos = $d->parentpos();
-       pos = d.parentpos()
-       pos = d.parentpos()
-
-The position object of the array containing the current match.
-It can be used to do sub-searches, see the Datapos class for more
-information.
-
-       <stringification>
-       my $str = $d->str;
-       str = str(d)
-       str = d.to_s
-
-Return the stringification of the matched value. Stringification
-depends on the search flags, for file list entries it will return
-just the base name unless SEARCH_FILES is used, for checksums
-it will return an empty string unless SEARCH_CHECKSUMS is used.
-Numeric values are currently stringified to an empty string.
-
-
-The Selection Class
--------------------
-Selections are a way to easily deal with sets of packages.
-There are multiple constructors to create them, the most useful
-is probably the select() method in the Pool class.
-
-=== CONSTANTS ===
-
-*SELECTION_NAME*::
-Create the selection by matching package names.
-
-*SELECTION_PROVIDES*::
-Create the selection by matching package provides.
-
-*SELECTION_FILELIST*::
-Create the selection by matching package files.
-
-*SELECTION_CANON*::
-Create the selection by matching the canonical representation
-of the package. This is normally a combination of the name,
-the version, and the architecture of a package.
-
-*SELECTION_DOTARCH*::
-Allow an ``.<architecture>'' suffix when matching names or
-provides.
-*SELECTION_REL*::
-Allow the specification of a relation when matching names
-or provides, e.g. "name >= 1.2".
-
-*SELECTION_INSTALLED_ONLY*::
-Limit the package search to installed packages.
-
-*SELECTION_SOURCE_ONLY*::
-Limit the package search to source packages only.
-
-*SELECTION_WITH_SOURCE*::
-Extend the package search to also match source packages. The default is
-only to match binary packages.
-
-*SELECTION_GLOB*::
-Allow glob matching for package names, package provides, and file names.
-
-*SELECTION_NOCASE*::
-Ignore case when matching package names, package provides, and file names.
-
-*SELECTION_FLAT*::
-Return only one selection element describing the selected packages.
-The default is to create multiple elements for all globbed packages.
-Multiple elements are useful if you want to turn the selection into
-an install job, in that case you want an install job for every
-globbed package.
-
-=== ATTRIBUTES ===
-
-       Pool *pool;                             /* read only */
-       $d->{pool}
-       d.pool
-       d.pool
-
-Back pointer to pool.
-
-=== METHODS ===
-
-       int flags();
-       my $flags = $sel->flags();
-       flags = sel.flags()
-       flags = sel.flags()
-
-Return the result flags of the selection. The flags are a subset
-of the ones used when creating the selection, they describe which
-method was used to get the result. For example, if you create the
-selection with ``SELECTION_NAME | SELECTION_PROVIDES'', the resulting
-flags will either be SELECTION_NAME or SELECTION_PROVIDES depending
-if there was a package that matched the name or not. If there was
-no match at all, the flags will be zero.
-
-       bool isempty();
-       $sel->isempty()
-       sel.isempty()
-       sel.isempty?
-
-Return true if the selection is empty, i.e. no package could be matched.
-
-       void filter(Selection *other)
-       $sel->filter($other);
-       sel.filter(other)
-       sel.filter(other)
-
-Intersect two selections. Packages will only stay in the selection if there
-are also included in the other selecting. Does an in-place modification.
-
-       void add(Selection *other)
-       $sel->add($other);
-       sel.add(other)
-       sel.add(other)
-
-Build the union of two selections. All packages of the other selection will
-be added to the set of packages of the selection object. Does an in-place
-modification. Note that the selection flags are no longer meaningful after the
-add operation.
-
-       void add_raw(Id how, Id what)
-       $sel->add_raw($how, $what);
-       sel.add_raw(how, what)
-       sel.add_raw(how, what)
-
-Add a raw element to the selection. Check the Job class for information about
-the how and what parameters.
-
-       Job *jobs(int action)
-       my @jobs = $sel->jobs($action);
-       jobs = sel.jobs(action)
-       jobs = sel.jobs(action)
-
-Convert a selection into an array of Job objects. The action parameter is or-ed
-to the ``how'' part of the job, it describes the type of job (e.g. install,
-erase). See the Job class for the action and action modifier constants.
-
-       Solvable *solvables()
-       my @solvables = $sel->solvables();
-       solvables = sel.solvables()
-       solvables = sel.solvables()
-
-Convert a selection into an array of Solvable objects.
-
-       <stringification>
-       my $str = $sel->str;
-       str = str(sel)
-       str = sel.to_s
-
-Return a string describing the selection.
-
-The Job Class
--------------
-Jobs are the way to specify to the dependency solver what to do.
-Most of the times jobs will get created by calling the jobs() method
-on a Selection object, but there is also a Job() constructor in the
-Pool class.
-
-=== CONSTANTS ===
-
-Selection constants:
-
-*SOLVER_SOLVABLE*::
-The ``what'' part is the id of a solvable.
-
-*SOLVER_SOLVABLE_NAME*::
-The ``what'' part is the id of a package name.
-
-*SOLVER_SOLVABLE_PROVIDES*::
-The ``what'' part is the id of a package provides.
-
-*SOLVER_SOLVABLE_ONE_OF*::
-The ``what'' part is an offset into the ``whatprovides'' data, created
-by calling the towhatprovides() pool method.
-
-*SOLVER_SOLVABLE_REPO*::
-The ``what'' part is the id of a repository.
-
-*SOLVER_SOLVABLE_ALL*::
-The ``what'' part is ignored, all packages are selected.
-
-*SOLVER_SOLVABLE_SELECTMASK*::
-A mask containing all the above selection bits.
-
-Action constants:
-
-*SOLVER_NOOP*::
-Do nothing.
-
-*SOLVER_INSTALL*::
-Install a package of the specified set of packages. It tries to install
-the best matching package (i.e. the highest version of the packages from
-the repositories with the highest priority).
-
-*SOLVER_ERASE*::
-Erase all of the packages from the specified set. If a package is not
-installed, erasing it will keep it from getting installed.
-
-*SOLVER_UPDATE*::
-Update the matching installed packages to their best version. If none
-of the specified packages are installed, try to update the installed
-packages to the specified versions. See the section about targeted
-updates about more information.
-*SOLVER_WEAKENDEPS*::
-Allow to break the dependencies of the matching packages. Handle with care.
-
-*SOLVER_MULTIVERSION*::
-Mark the matched packages for multiversion install. If they get to be
-installed because of some other job, the installation will keep the old
-version of the package installed (for rpm this is done by using ``-i''
-instead of ``-U'').
-
-*SOLVER_LOCK*::
-Do not change the state of the matched packages, i.e. when they are
-installed they stay installed, if not they are not selected for
-installation.
-
-*SOLVER_DISTUPGRADE*::
-Update the matching installed packages to the best version included in one
-of the repositories. After this operation, all come from one of the available
-repositories except orphaned packages. Orphaned packages are packages that
-have no relation to the packages in the repositories, i.e. no package in the
-repositories have the same name or obsolete the orphaned package.
-This action brings the installed packages in sync with the ones in the
-repository. By default it also turns of arch/vendor/version locking for the
-affected packages to simulate a fresh installation. This means that distupgrade can
-actually downgrade packages if only lower versions of a package are available
-in the repositories. You can tweak this behavior with the SOLVER_FLAG_DUP_
-solver flags.
-
-*SOLVER_DROP_ORPHANED*::
-Erase all the matching installed packages if they are orphaned. This only makes
-sense if there is a ``distupgrade all packages'' job. The default is to erase
-orphaned packages only if they block the installation of other packages.
-
-*SOLVER_VERIFY*::
-Fix dependency problems of matching installed packages. The default is to ignore
-dependency problems for installed packages.
-
-*SOLVER_USERINSTALLED*::
-The matching installed packages are considered to be installed by a user,
-thus not installed to fulfill some dependency. This is needed input for
-the calculation of unneeded packages for jobs that have the
-SOLVER_CLEANDEPS flag set.
-
-*SOLVER_ALLOWUNINSTALL*::
-Allow the solver to deinstall the matching installed packages if they get
-into the way of resolving a dependency. This is like the
-SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages.
-
-*SOLVER_JOBMASK*::
-A mask containing all the above action bits.
-
-Action modifier constants:
-
-*SOLVER_WEAK*::
-Makes the job a weak job. The solver tries to fulfill weak jobs, but does
-not report a problem if it is not possible to do so.
-
-*SOLVER_ESSENTIAL*::
-Makes the job an essential job. If there is a problem with the job, the
-solver will not propose to remove the job as one solution (unless all
-other solutions are also to remove essential jobs).
-
-*SOLVER_CLEANDEPS*::
-The solver will try to also erase all packages dragged in through
-dependencies when erasing the package. This needs SOLVER_USERINSTALLED
-jobs to maximize user satisfaction.
-
-*SOLVER_FORCEBEST*::
-Insist on the best package for install, update, and distupgrade jobs. If
-this flag is not used, the solver will use the second-best package if the
-best package cannot be installed for some reason. When this flag is used,
-the solver will generate a problem instead.
-
-*SOLVER_TARGETED*::
-Forces targeted operation update and distupgrade jobs. See the section
-about targeted updates about more information.
-
-Set constants.
-
-*SOLVER_SETEV*::
-The job specified the exact epoch and version of the package set.
-
-*SOLVER_SETEVR*::
-The job specified the exact epoch, version, and release of the package set.
-
-*SOLVER_SETARCH*::
-The job specified the exact architecture of the packages from the set.
-
-*SOLVER_SETVENDOR*::
-The job specified the exact vendor of the packages from the set.
-
-*SOLVER_SETREPO*::
-The job specified the exact repository of the packages from the set.
-
-*SOLVER_SETNAME*::
-The job specified the exact name of the packages from the set.
-
-*SOLVER_NOAUTOSET*::
-Turn of automatic set flag generation for SOLVER_SOLVABLE jobs.
-
-*SOLVER_SETMASK*::
-A mask containing all the above set bits.
-
-See the section about set bits for more information.
-
-=== ATTRIBUTES ===
-
-       Pool *pool;                             /* read only */
-       $job->{pool}
-       d.pool
-       d.pool
-
-Back pointer to pool.
-
-       Id how;                                 /* read/write */
-       $job->{how}
-       d.how
-       d.how
-
-Union of the selection, action, action modifier, and set flags.
-The selection part describes the semantics of the ``what'' Id.
-
-       Id what;                                /* read/write */
-       $job->{what}
-       d.what
-       d.what
-
-Id describing the set of packages, the meaning depends on the
-selection part of the ``how'' attribute.
-
-=== METHODS ===
-
-       Solvable *solvables()
-       my @solvables = $job->solvables();
-       solvables = job.solvables()
-       solvables = job.solvables()
-
-Return the set of solvables of the job as an array of Solvable
-objects.
-
-       bool isemptyupdate();
-       $job->isemptyupdate()
-       job.isemptyupdate()
-       job.isemptyupdate?
-
-Convenience function to find out if the job describes an update
-job with no matching packages, i.e. a job that does nothing.
-Some package managers like ``zypper'' like to turn those jobs
-into install jobs, i.e. an update of a not-installed package
-will result into the installation of the package.
-
-       <stringification>
-       my $str = $job->str;
-       str = str(job)
-       str = job.to_s
-
-Return a string describing the job.
-
-       <equality>
-       if ($job1 == $job2)
-       if job1 == job2:
-       if job1 == job2
-
-Two jobs are equal if they belong to the same pool and both the
-``how'' and the ``what'' attributes are the same.
-
-=== TARGETED UPDATES ===
-Libsolv has two modes for upgrades and distupgrade: targeted and
-untargeted. Untargeted mode means that the installed packages from
-the specified set will be updated to the best version. Targeted means
-that packages that can be updated to a package in the specified set
-will be updated to the best package of the set.
-
-Here's an example to explain the subtle difference. Suppose that
-you have package A installed in version "1.1", "A-1.2" is available
-in one of the repositories and there is also package "B" that
-obsoletes package A.
-
-An untargeted update of "A" will update the installed "A-1.1" to
-package "B", because that is the newest version (B obsoletes A and
-is thus newer).
-
-A targeted update of "A" will update "A-1.1" to "A-1.2", as the
-set of packages contains both "A-1.1" and "A-1.2", and "A-1.2" is
-the newer one.
-
-An untargeted update of "B" will do nothing, as "B" is not installed.
-
-An targeted update of "B" will update "A-1.1" to "B".
-
-Note that the default is to do "auto-targeting", thus if the specified
-set of packages does not include an installed package, the solver
-will assume targeted operation even if SOLVER_TARGETED is not used.
-
-This mostly matches the intent of the user, with one exception: In
-the example above, an update of "A-1.2" will update "A-1.1" to
-"A-1.2" (targeted mode), but a second update of "A-1.2" will suddenly
-update to "B", as untargeted mode is chosen because "A-1.2" is now
-installed.
-
-If you want to have full control over when targeting mode is chosen,
-turn off auto-targeting with the SOLVER_FLAG_NO_AUTOTARGET solver option.
-In that case, all updates are considered to be untargeted unless they
-include the SOLVER_TARGETED flag.
-
-=== SET BITS ===
-Set bits specify which parts of the specified packages where specified
-by the user. It is used by the solver when checking if an operation is
-allowed or not. For example, the solver will normally not allow the
-downgrade of an installed package. But it will not report a problem if
-the SOLVER_SETEVR flag is used, as it then assumes that the user specified
-the exact version and thus knows what he is doing.
-
-So if a package "screen-1-1" is installed for the x86_64 architecture and
-version "2-1" is only available for the i586 architecture, installing
-package "screen-2.1" will ask the user for confirmation because of the
-different architecture. When using the Selection class to create jobs
-the set bits are automatically added, e.g. selecting ``screen.i586'' will
-automatically add SOLVER_SETARCH, and thus no problem will be reported.
-
-The Solver Class
-----------------
-Dependency solving is what this library is about. A solver object is needed
-for solving to store the result of the solver run. The solver object can be
-used multiple times for different jobs, reusing it allows the solver to
-re-use the dependency rules it already computed.
-
-=== CONSTANTS ===
-
-Flags to modify some of the solver's behavior:
-
-*SOLVER_FLAG_ALLOW_DOWNGRADE*::
-Allow the solver to downgrade packages without asking for confirmation
-(i.e. reporting a problem).
-
-*SOLVER_FLAG_ALLOW_ARCHCHANGE*::
-Allow the solver to change the architecture of an installed package
-without asking for confirmation. Note that changes to/from noarch
-are always considered to be allowed.
-  
-*SOLVER_FLAG_ALLOW_VENDORCHANGE*::
-Allow the solver to change the vendor of an installed package
-without asking for confirmation. Each vendor is part of one or more
-vendor equivalence classes, normally installed packages may only
-change their vendor if the new vendor shares at least one equivalence
-class.
-
-*SOLVER_FLAG_ALLOW_NAMECHANGE*::
-Allow the solver to change the name of an installed package, i.e.
-install a package with a different name that obsoletes the installed
-package. This option is on by default.
-
-*SOLVER_FLAG_ALLOW_UNINSTALL*::
-Allow the solver to erase installed packages to fulfill the jobs.
-This flag also includes the above flags. You may want to set this
-flag if you only have SOLVER_ERASE jobs, as in that case it's
-better for the user to check the transaction overview instead of
-approving every single package that needs to be erased.
-
-*SOLVER_FLAG_DUP_ALLOW_DOWNGRADE*::
-Like SOLVER_FLAG_ALLOW_DOWNGRADE, but used in distupgrade mode.
-
-*SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE*::
-Like SOLVER_FLAG_ALLOW_ARCHCHANGE, but used in distupgrade mode.
-
-*SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE*::
-Like SOLVER_FLAG_ALLOW_VENDORCHANGE, but used in distupgrade mode.
-
-*SOLVER_FLAG_DUP_ALLOW_NAMECHANGE*::
-Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode.
-
-*SOLVER_FLAG_NO_UPDATEPROVIDE*::
-If multiple packages obsolete an installed package, the solver checks
-the provides of every such package and ignores all packages that
-do not provide the installed package name. Thus, you can have an
-official update candidate that provides the old name, and other
-packages that also obsolete the package but are not considered for
-updating. If you cannot use this feature, you can turn it off
-by setting this flag.
-
-*SOLVER_FLAG_SPLITPROVIDES*::
-Make the solver aware of special provides of the form
-``<packagename>:<path>'' used in SUSE systems to support package
-splits.
-
-*SOLVER_FLAG_IGNORE_RECOMMENDED*::
-Do not process optional (aka weak) dependencies.
-
-*SOLVER_FLAG_ADD_ALREADY_RECOMMENDED*::
-Install recommended or supplemented packages even if they have no
-connection to the current transaction. You can use this feature
-to implement a simple way for the user to install new recommended
-packages that were not available in the past.
-  
-*SOLVER_FLAG_NO_INFARCHCHECK*::
-Turn off the inferior architecture checking that is normally done
-by the solver. Normally, the solver allows only the installation
-of packages from the "best" architecture if a package is available
-for multiple architectures.
-
-*SOLVER_FLAG_BEST_OBEY_POLICY*::
-Make the SOLVER_FORCEBEST job option consider only packages that
-meet the policies for installed packages, i.e. no downgrades,
-no architecture change, no vendor change (see the first flags
-of this section). If the flag is not specified, the solver will
-enforce the installation of the best package ignoring the
-installed packages, which may conflict with the set policy.
-
-*SOLVER_FLAG_NO_AUTOTARGET*::
-Do not enable auto-targeting up update and distupgrade jobs. See
-the section on targeted updates for more information.
-
-*SOLVER_FLAG_KEEP_ORPHANS*::
-Do not allow orphaned packages to be deinstalled if they get
-in the way of resolving other packages.
-
-*SOLVER_FLAG_BREAK_ORPHANS*::
-Ignore dependencies of orphaned packages that get in the way
-of resolving non-orphaned ones. Setting the flag might result
-in no longer working packages in case they are orphaned.
-
-*SOLVER_FLAG_FOCUS_INSTALLED*::
-Resolve installed packages before resolving the given job.
-Setting this flag means that the solver will prefer picking
-a package version that fits the other installed packages
-over updating installed packages.
-
-Basic rule types:
-
-*SOLVER_RULE_UNKNOWN*::
-A rule of an unknown class. You should never encounter those.
-
-*SOLVER_RULE_PKG*::
-A package dependency rule.
-
-*SOLVER_RULE_UPDATE*::
-A rule to implement the update policy of installed packages. Every
-installed package has an update rule that consists of the packages
-that may replace the installed package.
-
-*SOLVER_RULE_FEATURE*::
-Feature rules are fallback rules used when an update rule is disabled. They
-include all packages that may replace the installed package ignoring the
-update policy, i.e. they contain downgrades, arch changes and so on.
-Without them, the solver would simply erase installed packages if their
-update rule gets disabled.
-
-*SOLVER_RULE_JOB*::
-Job rules implement the job given to the solver.
-
-*SOLVER_RULE_DISTUPGRADE*::
-These are simple negative assertions that make sure that only packages
-are kept that are also available in one of the repositories.
-
-*SOLVER_RULE_INFARCH*::
-Infarch rules are also negative assertions, they disallow the installation
-of packages when there are packages of the same name but with a better
-architecture.
-
-*SOLVER_RULE_CHOICE*::
-Choice rules are used to make sure that the solver prefers updating to
-installing different packages when some dependency is provided by
-multiple packages with different names. The solver may always break
-choice rules, so you will not see them when a problem is found.
-
-*SOLVER_RULE_LEARNT*::
-These rules are generated by the solver to keep it from running into
-the same problem multiple times when it has to backtrack. They are
-the main reason why a sat solver is faster than other dependency solver
-implementations.
-
-Special dependency rule types:
-
-*SOLVER_RULE_PKG_NOT_INSTALLABLE*::
-This rule was added to prevent the installation of a package of an
-architecture that does not work on the system.
-
-*SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP*::
-The package contains a required dependency which was not provided by
-any package.
-
-*SOLVER_RULE_PKG_REQUIRES*::
-Similar to SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, but in this case
-some packages provided the dependency but none of them could be
-installed due to other dependency issues.
-
-*SOLVER_RULE_PKG_SELF_CONFLICT*::
-The package conflicts with itself. This is not allowed by older rpm
-versions.
-
-*SOLVER_RULE_PKG_CONFLICTS*::
-To fulfill the dependencies two packages need to be installed, but
-one of the packages contains a conflict with the other one.
-
-*SOLVER_RULE_PKG_SAME_NAME*::
-The dependencies can only be fulfilled by multiple versions of
-a package, but installing multiple versions of the same package
-is not allowed.
-
-*SOLVER_RULE_PKG_OBSOLETES*::
-To fulfill the dependencies two packages need to be installed, but
-one of the packages obsoletes the other one.
-
-*SOLVER_RULE_PKG_IMPLICIT_OBSOLETES*::
-To fulfill the dependencies two packages need to be installed, but
-one of the packages has provides a dependency that is obsoleted
-by the other one. See the POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES
-flag.
-
-*SOLVER_RULE_PKG_INSTALLED_OBSOLETES*::
-To fulfill the dependencies a package needs to be installed that is
-obsoleted by an installed package. See the POOL_FLAG_NOINSTALLEDOBSOLETES
-flag.
-
-*SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP*::
-The user asked for installation of a package providing a specific
-dependency, but no available package provides it.
-
-*SOLVER_RULE_JOB_UNKNOWN_PACKAGE*::
-The user asked for installation of a package with a specific name,
-but no available package has that name.
-
-*SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM*::
-The user asked for the erasure of a dependency that is provided by the
-system (i.e. for special hardware or language dependencies), this
-cannot be done with a job.
-
-*SOLVER_RULE_JOB_UNSUPPORTED*::
-The user asked for something that is not yet implemented, e.g. the
-installation of all packages at once.
-
-Policy error constants
-
-*POLICY_ILLEGAL_DOWNGRADE*::
-The solver ask for permission before downgrading packages.
-
-*POLICY_ILLEGAL_ARCHCHANGE*::
-The solver ask for permission before changing the architecture of installed
-packages.
-
-*POLICY_ILLEGAL_VENDORCHANGE*::
-The solver ask for permission before changing the vendor of installed
-packages.
-
-*POLICY_ILLEGAL_NAMECHANGE*::
-The solver ask for permission before replacing an installed packages with
-a package that has a different name.
-
-Solution element type constants
-
-*SOLVER_SOLUTION_JOB*::
-The problem can be solved by removing the specified job.
-
-*SOLVER_SOLUTION_POOLJOB*::
-The problem can be solved by removing the specified job that is defined
-in the pool.
-
-*SOLVER_SOLUTION_INFARCH*::
-The problem can be solved by allowing the installation of the specified
-package with an inferior architecture.
-
-*SOLVER_SOLUTION_DISTUPGRADE*::
-The problem can be solved by allowing to keep the specified package
-installed.
-
-*SOLVER_SOLUTION_BEST*::
-The problem can be solved by allowing to install the specified package
-that is not the best available package.
-
-*SOLVER_SOLUTION_ERASE*::
-The problem can be solved by allowing to erase the specified package.
-
-*SOLVER_SOLUTION_REPLACE*::
-The problem can be solved by allowing to replace the package with some
-other package.
-
-*SOLVER_SOLUTION_REPLACE_DOWNGRADE*::
-The problem can be solved by allowing to replace the package with some
-other package that has a lower version.
-
-*SOLVER_SOLUTION_REPLACE_ARCHCHANGE*::
-The problem can be solved by allowing to replace the package with some
-other package that has a different architecture.
-
-*SOLVER_SOLUTION_REPLACE_VENDORCHANGE*::
-The problem can be solved by allowing to replace the package with some
-other package that has a different vendor.
-
-*SOLVER_SOLUTION_REPLACE_NAMECHANGE*::
-The problem can be solved by allowing to replace the package with some
-other package that has a different name.
-
-
-Reason constants
-
-*SOLVER_REASON_UNRELATED*::
-The package status did not change as it was not related to any job.
-
-*SOLVER_REASON_UNIT_RULE*::
-The package was installed/erased/kept because of a unit rule, i.e. a rule
-where all literals but one were false.
-
-*SOLVER_REASON_KEEP_INSTALLED*::
-The package was chosen when trying to keep as many packages installed as
-possible.
-
-*SOLVER_REASON_RESOLVE_JOB*::
-The decision happened to fulfill a job rule.
-
-*SOLVER_REASON_UPDATE_INSTALLED*::
-The decision happened to fulfill a package update request.
-
-*SOLVER_REASON_CLEANDEPS_ERASE*::
-The package was erased when cleaning up dependencies from other erased
-packages.
-
-*SOLVER_REASON_RESOLVE*::
-The package was installed to fulfill package dependencies.
-
-*SOLVER_REASON_WEAKDEP*::
-The package was installed because of a weak dependency (Recommends or
-Supplements).
-
-*SOLVER_REASON_RESOLVE_ORPHAN*::
-The decision about the package was made when deciding the fate of orphaned
-packages.
-
-*SOLVER_REASON_RECOMMENDED*::
-This is a special case of SOLVER_REASON_WEAKDEP.
-
-*SOLVER_REASON_SUPPLEMENTED*::
-This is a special case of SOLVER_REASON_WEAKDEP.
-
-
-=== ATTRIBUTES ===
-
-       Pool *pool;                             /* read only */
-       $job->{pool}
-       d.pool
-       d.pool
-
-Back pointer to pool.
-
-=== METHODS ===
-
-       int set_flag(int flag, int value)
-       my $oldvalue = $solver->set_flag($flag, $value);
-       oldvalue = solver.set_flag(flag, value)
-       oldvalue = solver.set_flag(flag, value)
-
-       int get_flag(int flag)
-       my $value = $solver->get_flag($flag);
-       value = solver.get_flag(flag)
-       value = solver.get_flag(flag)
-
-Set/get a solver specific flag. The flags define the policies the solver has
-to obey. The flags are explained in the CONSTANTS section of this class.
-
-       Problem *solve(Job *jobs)
-       my @problems = $solver->solve(\@jobs);
-       problems = solver.solve(jobs)
-       problems = solver.solve(jobs)
-
-Solve a problem specified in the job list (plus the jobs defined in the pool).
-Returns an array of problems that need user interaction, or an empty array
-if no problems were encountered. See the Problem class on how to deal with
-problems.
-
-       Transaction transaction()
-       my $trans = $solver->transaction();
-       trans = solver.transaction()
-       trans = solver.transaction()
-
-Return the transaction to implement the calculated package changes. A transaction
-is available even if problems were found, this is useful for interactive user
-interfaces that show both the job result and the problems.
-
-       int reason = describe_decision(Solvable *s, Rule *OUTPUT)
-       my ($reason, $rule) = $solver->describe_decision($solvable);
-       (reason, rule) = solver.describe_decision(solvable)
-       (reason, rule) = solver.describe_decision(solvable)
-
-Return the reason why a specific solvable was installed or erased. For most of
-the reasons the rule that triggered the decision is also returned.
-
-The Problem Class
------------------
-Problems are the way of the solver to interact with the user. You can simply list
-all problems and terminate your program, but a better way is to present solutions to
-the user and let him pick the ones he likes.
-
-=== ATTRIBUTES ===
-
-       Solver *solv;                           /* read only */
-       $problem->{solv}
-       problem.solv
-       problem.solv
-
-Back pointer to solver object.
-
-       Id id;                                  /* read only */
-       $problem->{id}
-       problem.id
-       problem.id
-
-Id of the problem. The first problem has Id 1, they are numbered consecutively.
-
-=== METHODS ===
-
-       Rule findproblemrule()
-       my $probrule = $problem->findproblemrule();
-       probrule = problem.findproblemrule()
-       probrule = problem.findproblemrule()
-
-Return the rule that caused the problem. Of course in most situations there is no
-single responsible rule, but many rules that interconnect with each created the
-problem. Nevertheless, the solver uses some heuristic approach to find a rule
-that somewhat describes the problem best to the user.
-
-       Rule *findallproblemrules(bool unfiltered = 0)
-       my @probrules = $problem->findallproblemrules();
-       probrules = problem.findallproblemrule()
-       probrules = problem.findallproblemrule()
-
-Return all rules responsible for the problem. The returned set of rules contains
-all the needed information why there was a problem, but it's hard to present
-them to the user in a sensible way. The default is to filter out all update and
-job rules (unless the returned rules only consist of those types).
-
-       Solution *solutions()
-       my @solutions = $problem->solutions();
-       solutions = problem.solutions()
-       solutions = problem.solutions()
-
-Return an array containing multiple possible solutions to fix the problem. See
-the solution class for more information.
-
-       int solution_count()
-       my $cnt = $problem->solution_count();
-       cnt = problem.solution_count()
-       cnt = problem.solution_count()
-
-Return the number of solutions without creating solution objects.
-
-       <stringification>
-       my $str = $problem->str;
-       str = str(problem)
-       str = problem.to_s
-
-Return a string describing the problem. This is a convenience function, it is
-a shorthand for calling findproblemrule(), then ruleinfo() on the problem
-rule and problemstr() on the ruleinfo object.
-
-The Rule Class
---------------
-Rules are the basic block of sat solving. Each package dependency gets translated
-into one or multiple rules.
-
-=== ATTRIBUTES ===
-
-       Solver *solv;                           /* read only */
-       $rule->{solv}
-       rule.solv
-       rule.solv
-
-Back pointer to solver object.
-
-       Id id;                                  /* read only */
-       $rule->{id}
-       rule.id
-       rule.id
-
-The id of the rule.
-
-       int type;                               /* read only */
-       $rule->{type}
-       rule.type
-       rule.type
-
-The basic type of the rule. See the constant section of the solver class for the type list.
-
-=== METHODS ===
-
-       Ruleinfo info()
-       my $ruleinfo = $rule->info();
-       ruleinfo = rule.info()
-       ruleinfo = rule.info()
-
-Return a Ruleinfo object that contains information about why the rule was created. But
-see the allinfos() method below.
-
-       Ruleinfo *allinfos()
-       my @ruleinfos = $rule->allinfos();
-       ruleinfos = rule.allinfos()
-       ruleinfos = rule.allinfos()
-
-As the same dependency rule can get created because of multiple dependencies, one
-Ruleinfo is not enough to describe the reason. Thus the allinfos() method returns
-an array of all infos about a rule.
-
-       <equality>
-       if ($rule1 == $rule2)
-       if rule1 == rule2:
-       if rule1 == rule2
-
-Two rules are equal if they belong to the same solver and have the same id.
-
-The Ruleinfo Class
-------------------
-A Ruleinfo describes one reason why a rule was created.
-
-=== ATTRIBUTES ===
-
-       Solver *solv;                           /* read only */
-       $ruleinfo->{solv}
-       ruleinfo.solv
-       ruleinfo.solv
-
-Back pointer to solver object.
-
-       int type;                               /* read only */
-       $ruleinfo->{type}
-       ruleinfo.type
-       ruleinfo.type
-
-The type of the ruleinfo. See the constant section of the solver class for the
-rule type list and the special type list.
-
-       Dep *dep;                               /* read only */
-       $ruleinfo->{dep}
-       ruleinfo.dep
-       ruleinfo.dep
-
-The dependency leading to the creation of the rule.
-
-       Dep *dep_id;                            /* read only */
-       $ruleinfo->{'dep_id'}
-       ruleinfo.dep_id
-       ruleinfo.dep_id
-
-The Id of the dependency leading to the creation of the rule, or zero.
-
-       Solvable *solvable;                     /* read only */
-       $ruleinfo->{solvable}
-       ruleinfo.solvable
-       ruleinfo.solvable
-
-The involved Solvable, e.g. the one containing the dependency.
-
-       Solvable *othersolvable;                /* read only */
-       $ruleinfo->{othersolvable}
-       ruleinfo.othersolvable
-       ruleinfo.othersolvable
-
-The other involved Solvable (if any), e.g. the one containing providing
-the dependency for conflicts.
-
-       const char *problemstr();
-       my $str = $ruleinfo->problemstr();
-       str = ruleinfo.problemstr()
-       str = ruleinfo.problemstr()
-
-A string describing the ruleinfo from a problem perspective. This probably
-only makes sense if the rule is part of a problem.
-
-The Solution Class
-------------------
-A solution solves one specific problem. It consists of multiple solution elements
-that all need to be executed.
-
-=== ATTRIBUTES ===
-
-       Solver *solv;                           /* read only */
-       $solution->{solv}
-       solution.solv
-       solution.solv
-
-Back pointer to solver object.
-
-       Id problemid;                           /* read only */
-       $solution->{problemid}
-       solution.problemid
-       solution.problemid
-
-Id of the problem the solution solves.
-
-       Id id;                                  /* read only */
-       $solution->{id}
-       solution.id
-       solution.id
-
-Id of the solution. The first solution has Id 1, they are numbered consecutively.
-
-=== METHODS ===
-
-       Solutionelement *elements(bool expandreplaces = 0)
-       my @solutionelements = $solution->elements();
-       solutionelements = solution.elements()
-       solutionelements = solution.elements()
-
-Return an array containing the elements describing what needs to be done to
-implement the specific solution. If expandreplaces is true, elements of type
-SOLVER_SOLUTION_REPLACE will be replaced by one or more elements replace
-elements describing the policy mismatches.
-
-       int element_count()
-       my $cnt = $solution->solution_count();
-       cnt = solution.element_count()
-       cnt = solution.element_count()
-
-Return the number of solution elements without creating objects. Note that the
-count does not match the number of objects returned by the elements() method
-of expandreplaces is set to true.
-
-
-The Solutionelement Class
--------------------------
-A solution element describes a single action of a solution. The action is always
-either to remove one specific job or to add a new job that installs or erases
-a single specific package.
-
-=== ATTRIBUTES ===
-
-       Solver *solv;                           /* read only */
-       $solutionelement->{solv}
-       solutionelement.solv
-       solutionelement.solv
-
-Back pointer to solver object.
-
-       Id problemid;                           /* read only */
-       $solutionelement->{problemid}
-       solutionelement.problemid
-       solutionelement.problemid
-
-Id of the problem the element (partly) solves.
-
-       Id solutionid;                          /* read only */
-       $solutionelement->{solutionid}
-       solutionelement.solutionid
-       solutionelement.solutionid
-
-Id of the solution the element is a part of.
-
-       Id id;                                  /* read only */
-       $solutionelement->{id}
-       solutionelement.id
-       solutionelement.id
-
-Id of the solution element. The first element has Id 1, they are numbered consecutively.
-
-       Id type;                                /* read only */
-       $solutionelement->{type}
-       solutionelement.type
-       solutionelement.type
-
-Type of the solution element. See the constant section of the solver class for the
-existing types.
-
-       Solvable *solvable;                     /* read only */
-       $solutionelement->{solvable}
-       solutionelement.solvable
-       solutionelement.solvable
-
-The installed solvable that needs to be replaced for replacement elements.
-
-       Solvable *replacement;                  /* read only */
-       $solutionelement->{replacement}
-       solutionelement.replacement
-       solutionelement.replacement
-
-The solvable that needs to be installed to fix the problem.
-
-       int jobidx;                             /* read only */
-       $solutionelement->{jobidx}
-       solutionelement.jobidx
-       solutionelement.jobidx
-
-The index of the job that needs to be removed to fix the problem, or -1 if the
-element is of another type. Note that it's better to change the job to SOLVER_NOOP
-type so that the numbering of other elements does not get disturbed. This
-method works both for types SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB.
-
-=== METHODS ===
-
-       Solutionelement *replaceelements()
-       my @solutionelements = $solutionelement->replaceelements();
-       solutionelements = solutionelement.replaceelements()
-       solutionelements = solutionelement.replaceelements()
-
-If the solution element is of type SOLVER_SOLUTION_REPLACE, return an array of
-elements describing the policy mismatches, otherwise return a copy of the
-element. See also the ``expandreplaces'' option in the solution's elements()
-method.
-
-       int illegalreplace()
-       my $illegal = $solutionelement->illegalreplace();
-       illegal = solutionelement.illegalreplace()
-       illegal = solutionelement.illegalreplace()
-
-Return an integer that contains the policy mismatch bits or-ed together, or
-zero if there was no policy mismatch. See the policy error constants in
-the solver class.
-
-       Job Job()
-       my $job = $solutionelement->Job();
-       illegal = solutionelement.Job()
-       illegal = solutionelement.Job()
-
-Create a job that implements the solution element. Add this job to the array
-of jobs for all elements of type different to SOLVER_SOLUTION_JOB and
-SOLVER_SOLUTION_POOLJOB. For the later two, a SOLVER_NOOB Job is created,
-you should replace the old job with the new one.
-
-       const char *str()
-       my $str = $solutionelement->str();
-       str = solutionelement.str()
-       str = solutionelement.str()
-
-A string describing the change the solution element consists of.
-
-The Transaction Class
----------------------
-Transactions describe the output of a solver run. A transaction contains
-a number of transaction elements, each either the installation of a new
-package or the removal of an already installed package. The Transaction
-class supports a classify() method that puts the elements into different
-groups so that a transaction can be presented to the user in a meaningful
-way.
-
-=== CONSTANTS ===
-
-Transaction element types, both active and passive
-
-*SOLVER_TRANSACTION_IGNORE*::
-This element does nothing. Used to map element types that do not match
-the view mode.
-
-*SOLVER_TRANSACTION_INSTALL*::
-This element installs a package.
-
-*SOLVER_TRANSACTION_ERASE*::
-This element erases a package.
-
-*SOLVER_TRANSACTION_MULTIINSTALL*::
-This element installs a package with a different version keeping the other
-versions installed.
-
-*SOLVER_TRANSACTION_MULTIREINSTALL*::
-This element reinstalls an installed package keeping the other versions
-installed.
-
-Transaction element types, active view
-
-*SOLVER_TRANSACTION_REINSTALL*::
-This element re-installs a package, i.e. installs the same package again.
-
-*SOLVER_TRANSACTION_CHANGE*::
-This element installs a package with same name, version, architecture but
-different content.
-
-*SOLVER_TRANSACTION_UPGRADE*::
-This element installs a newer version of an installed package.
-
-*SOLVER_TRANSACTION_DOWNGRADE*::
-This element installs an older version of an installed package.
-
-*SOLVER_TRANSACTION_OBSOLETES*::
-This element installs a package that obsoletes an installed package.
-
-Transaction element types, passive view
-
-*SOLVER_TRANSACTION_REINSTALLED*::
-This element re-installs a package, i.e. installs the same package again.
-
-*SOLVER_TRANSACTION_CHANGED*::
-This element replaces an installed package with one of the same name,
-version, architecture but different content.
-
-*SOLVER_TRANSACTION_UPGRADED*::
-This element replaces an installed package with a new version.
-
-*SOLVER_TRANSACTION_DOWNGRADED*::
-This element replaces an installed package with an old version.
-
-*SOLVER_TRANSACTION_OBSOLETED*::
-This element replaces an installed package with a package that obsoletes
-it.
-
-Pseudo element types for showing extra information used by classify()
-
-*SOLVER_TRANSACTION_ARCHCHANGE*::
-This element replaces an installed package with a package of a different
-architecture.
-
-*SOLVER_TRANSACTION_VENDORCHANGE*::
-This element replaces an installed package with a package of a different
-vendor.
-
-Transaction mode flags
-
-*SOLVER_TRANSACTION_SHOW_ACTIVE*::
-Filter for active view types. The default is to return passive view type,
-i.e. to show how the installed packages get changed.
-
-*SOLVER_TRANSACTION_SHOW_OBSOLETES*::
-Do not map the obsolete view type into INSTALL/ERASE elements.
-
-*SOLVER_TRANSACTION_SHOW_ALL*::
-If multiple packages replace an installed package, only the best of them
-is kept as OBSOLETE element, the other ones are mapped to INSTALL/ERASE
-elements. This is because most applications want to show just one package
-replacing the installed one. The SOLVER_TRANSACTION_SHOW_ALL makes the
-library keep all OBSOLETE elements.
-
-*SOLVER_TRANSACTION_SHOW_MULTIINSTALL*::
-The library maps MULTIINSTALL elements to simple INSTALL elements. This
-flag can be used to disable the mapping.
-
-*SOLVER_TRANSACTION_CHANGE_IS_REINSTALL*::
-Use this flag if you want to map CHANGE elements to the REINSTALL type.
-
-*SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE*::
-Use this flag if you want to map OBSOLETE elements to the UPGRADE type.
-
-*SOLVER_TRANSACTION_MERGE_ARCHCHANGES*::
-Do not add extra categories for every architecture change, instead cumulate
-them in one category.
-  
-*SOLVER_TRANSACTION_MERGE_VENDORCHANGES*::
-Do not add extra categories for every vendor change, instead cumulate
-them in one category.
-
-*SOLVER_TRANSACTION_RPM_ONLY*::
-Special view mode that just returns IGNORE, ERASE, INSTALL, MULTIINSTALL
-elements. Useful if you want to find out what to feed to the underlying
-package manager.
-
-Transaction order flags
-
-*SOLVER_TRANSACTION_KEEP_ORDERDATA*::
-Do not throw away the dependency graph used for ordering the transaction.
-This flag is needed if you want to do manual ordering.
-
-=== ATTRIBUTES ===
-
-       Pool *pool;                             /* read only */
-       $trans->{pool}
-       trans.pool
-       trans.pool
-
-Back pointer to pool.
-
-=== METHODS ===
-
-       bool isempty();
-       $trans->isempty()
-       trans.isempty()
-       trans.isempty?
-
-Returns true if the transaction does not do anything, i.e. has no elements.
-
-       Solvable *newsolvables();
-       my @newsolvables = $trans->newsolvables();
-       newsolvables = trans.newsolvables()
-       newsolvables = trans.newsolvables()
-
-Return all packages that are to be installed by the transaction. These are
-the packages that need to be downloaded from the repositories.
-
-       Solvable *keptsolvables();
-       my @keptsolvables = $trans->keptsolvables();
-       keptsolvables = trans.keptsolvables()
-       keptsolvables = trans.keptsolvables()
-
-Return all installed packages that the transaction will keep installed.
-
-       Solvable *steps();
-       my @steps = $trans->steps();
-       steps = trans.steps()
-       steps = trans.steps()
-
-Return all solvables that need to be installed (if the returned solvable
-is not already installed) or erased (if the returned solvable is installed).
-A step is also called a transaction element.
-
-       int steptype(Solvable *solvable, int mode)
-       my $type = $trans->steptype($solvable, $mode);
-       type = trans.steptype(solvable, mode)
-       type = trans.steptype(solvable, mode)
-
-Return the transaction type of the specified solvable. See the CONSTANTS
-sections for the mode argument flags and the list of returned types.
-
-       TransactionClass *classify(int mode = 0)
-       my @classes = $trans->classify();
-       classes = trans.classify()
-       classes = trans.classify()
-
-Group the transaction elements into classes so that they can be displayed
-in a structured way. You can use various mapping mode flags to tweak
-the result to match your preferences, see the mode argument flag in
-the CONSTANTS section. See the TransactionClass class for how to deal
-with the returned objects.
-
-       Solvable othersolvable(Solvable *solvable);
-       my $other = $trans->othersolvable($solvable);
-       other = trans.othersolvable(solvable)
-       other = trans.othersolvable(solvable)
-
-Return the ``other'' solvable for a given solvable. For installed packages
-the other solvable is the best package with the same name that replaces
-the installed package, or the best package of the obsoleting packages if
-the package does not get replaced by one with the same name.
-
-For to be installed packages, the ``other'' solvable is the best installed
-package with the same name that will be replaced, or the best packages
-of all the packages that are obsoleted if the new package does not replace
-a package with the same name.
-
-Thus, the ``other'' solvable is normally the package that is also shown
-for a given package.
-
-       Solvable *allothersolvables(Solvable *solvable);
-       my @others = $trans->allothersolvables($solvable);
-       others = trans.allothersolvables(solvable)
-       others = trans.allothersolvables(solvable)
-
-For installed packages, returns all of the packages that replace us. For to
-be installed packages, returns all of the packages that the new package
-replaces. The special ``other'' solvable is always the first entry of the
-returned array.
-
-       int calc_installsizechange();
-       my $change = $trans->calc_installsizechange();
-       change = trans.calc_installsizechange()
-       change = trans.calc_installsizechange()
-
-Return the size change of the installed system in kilobytes (kibibytes).
-
-       void order(int flags = 0);
-       $trans->order();
-       trans.order()
-       trans.order()
-
-Order the steps in the transactions so that dependent packages are updated
-before packages that depend on them. For rpm, you can also use rpmlib's
-ordering functionality, debian's dpkg does not provide a way to order a
-transaction.
-
-=== ACTIVE/PASSIVE VIEW ===
-
-Active view lists what new packages get installed, while passive view shows
-what happens to the installed packages. Most often there's not much
-difference between the two modes, but things get interesting if multiple
-packages get replaced by one new package. Say you have installed packages
-A-1-1 and B-1-1, and now install A-2-1 which has a new dependency that
-obsoletes B. The transaction elements will be
-
-  updated   A-1-1 (other: A-2-1)
-  obsoleted B-1-1 (other: A-2-1)
-
-in passive mode, but
-
-  update A-2-1 (other: A-1-1)
-  erase  B
-
-in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the 
-passive mode list will be unchanged but the active mode list will just
-contain A-2-1.
-
-The Transactionclass Class
---------------------------
-Objects of this type are returned by the classify() Transaction method.
-
-=== ATTRIBUTES ===
-
-       Transaction *transaction;               /* read only */
-       $class->{transaction}
-       class.transaction
-       class.transaction
-
-Back pointer to transaction object.
-
-       int type;                               /* read only */
-       $class->{type}
-       class.type
-       class.type
-
-The type of the transaction elements in the class.
-
-       int count;                              /* read only */
-       $class->{count}
-       class.count
-       class.count
-
-The number of elements in the class.
-
-       const char *fromstr;
-       $class->{fromstr}
-       class.fromstr
-       class.fromstr
-
-The old vendor or architecture.
-
-       const char *tostr;
-       $class->{tostr}
-       class.tostr
-       class.tostr
-
-The new vendor or architecture.
-
-       Id fromid;
-       $class->{fromid}
-       class.fromid
-       class.fromid
-
-The id of the old vendor or architecture.
-
-       Id toid;
-       $class->{toid}
-       class.toid
-       class.toid
-
-The id of the new vendor or architecture.
-
-=== METHODS ===
-
-       void solvables();
-       my @solvables = $class->solvables();
-       solvables = class.solvables()
-       solvables = class.solvables()
-
-Return the solvables for all transaction elements in the class.
-
-Checksums
----------
-Checksums (also called hashes) are used to make sure that downloaded data is
-not corrupt and also as a fingerprint mechanism to check if data has changed.
-
-=== CLASS METHODS ===
-
-       Chksum Chksum(Id type)
-       my $chksum = solv::Chksum->new($type);
-       chksum = solv.Chksum(type)
-       chksum = Solv::Chksum.new(type)
-
-Create a checksum object. Currently the following types are supported:
-
-       REPOKEY_TYPE_MD5
-       REPOKEY_TYPE_SHA1
-       REPOKEY_TYPE_SHA256
-
-These keys are constants in the *solv* class.
-
-       Chksum Chksum(Id type, const char *hex)
-       my $chksum = solv::Chksum->new($type, $hex);
-       chksum = solv.Chksum(type, hex)
-       chksum = Solv::Chksum.new(type, hex)
-
-Create an already finalized checksum object from a hex string.
-
-       Chksum Chksum_from_bin(Id type, char *bin)
-       my $chksum = solv::Chksum->from_bin($type, $bin);
-       chksum = solv.Chksum.from_bin(type, bin)
-       chksum = Solv::Chksum.from_bin(type, bin)
-
-Create an already finalized checksum object from a binary checksum.
-
-=== ATTRIBUTES ===
-
-       Id type;                        /* read only */
-       $chksum->{type}
-       chksum.type
-       chksum.type
-
-Return the type of the checksum object.
-
-=== METHODS ===
-
-       void add(const char *str)
-       $chksum->add($str);
-       chksum.add(str)
-       chksum.add(str)
-
-Add a (binary) string to the checksum.
-
-       void add_fp(FILE *fp)
-       $chksum->add_fp($file);
-       chksum.add_fp(file)
-       chksum.add_fp(file)
-
-Add the contents of a file to the checksum.
-       
-       void add_stat(const char *filename)
-       $chksum->add_stat($filename);
-       chksum.add_stat(filename)
-       chksum.add_stat(filename)
-
-Stat the file and add the dev/ino/size/mtime member to the checksum. If the
-stat fails, the members are zeroed.
-
-       void add_fstat(int fd)
-       $chksum->add_fstat($fd);
-       chksum.add_fstat(fd)
-       chksum.add_fstat(fd)
-
-Same as add_stat, but instead of the filename a file descriptor is used.
-
-       unsigned char *raw()
-       my $raw = $chksum->raw();
-       raw = chksum.raw()
-       raw = chksum.raw()
-
-Finalize the checksum and return the result as raw bytes. This means that the
-result can contain NUL bytes or unprintable characters.
-
-       const char *hex()
-       my $raw = $chksum->hex();
-       raw = chksum.hex()
-       raw = chksum.hex()
-
-Finalize the checksum and return the result as hex string.
-
-       const char *typestr()
-       my $typestr = $chksum->typestr();
-       typestr = chksum.typestr
-       typestr = chksum.typestr
-
-Return the type of the checksum as a string, e.g. "sha256".
-
-       <equality>
-       if ($chksum1 == $chksum2)
-       if chksum1 == chksum2:
-       if chksum1 == chksum2
-
-Checksums are equal if they are of the same type and the finalized results are
-the same.
-
-       <stringification>
-       my $str = $chksum->str;
-       str = str(chksum)
-       str = chksum.to_s
-
-If the checksum is finished, the checksum is returned as "<type>:<hex>" string.
-Otherwise "<type>:unfinished" is returned.
-
-
-File Management
----------------
-This functions were added because libsolv uses standard *FILE* pointers to
-read/write files, but languages like perl have their own implementation of
-files. The libsolv functions also support decompression and compression, the
-algorithm is selected by looking at the file name extension.
-
-       FILE *xfopen(char *fn, char *mode = "r")
-       my $file = solv::xfopen($path);
-       file = solv.xfopen(path)
-       file = Solv::xfopen(path)
-
-Open a file at the specified path. The `mode` argument is passed on to the
-stdio library.
-
-       FILE *xfopen_fd(char *fn, int fileno)
-       my $file = solv::xfopen_fd($path, $fileno);
-       file = solv.xfopen_fd(path, fileno)
-       file = Solv::xfopen_fd(path, fileno)
-
-Create a file handle from the specified file descriptor. The path argument is
-only used to select the correct (de-)compression algorithm, use an empty path
-if you want to make sure to read/write raw data. The file descriptor is dup()ed
-before the file handle is created.
-
-=== METHODS ===
-
-       int fileno()
-       my $fileno = $file->fileno();
-       fileno = file.fileno()
-       fileno = file.fileno()
-
-Return file file descriptor of the file. If the file is not open, `-1` is
-returned.
-
-       void cloexec(bool state)
-       $file->cloexec($state)
-       file.cloexec(state)
-       file.cloexec(state)
-
-Set the close-on-exec flag of the file descriptor. The xfopen function
-returns files with close-on-exec turned on, so if you want to pass
-a file to some other process you need to call cloexec(0) before calling
-exec.
-
-       int dup()
-       my $fileno = $file->dup();
-       fileno = file.dup()
-       fileno = file.dup()
-
-Return a copy of the descriptor of the file. If the file is not open, `-1` is
-returned.
-
-       bool flush()
-       $file->flush();
-       file.flush()
-       file.flush()
-
-Flush the file. Returns false if there was an error. Flushing a closed file
-always returns true.
-
-       bool close()
-       $file->close();
-       file.close()
-       file.close()
-
-Close the file. This is needed for languages like Ruby that do not destruct
-objects right after they are no longer referenced. In that case, it is good
-style to close open files so that the file descriptors are freed right away.
-Returns false if there was an error.
-
-
-The Repodata Class
-------------------
-The Repodata stores attributes for packages and the repository itself, each
-repository can have multiple repodata areas. You normally only need to
-directly access them if you implement lazy downloading of repository data.
-Repodata areas are created by calling the repository's add_repodata() method 
-or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING
-flag.
-
-=== ATTRIBUTES ===
-
-       Repo *repo;                     /* read only */
-       $data->{repo}
-       data.repo
-       data.repo
-
-Back pointer to repository object.
-
-       Id id;                                  /* read only */
-       $data->{id}
-       data.id
-       data.id
-
-The id of the repodata area. Repodata ids of different repositories overlap.
-
-=== METHODS ===
-
-       internalize();
-       $data->internalize();
-       data.internalize()
-       data.internalize()
-
-Internalize newly added data. The lookup functions will only see the new data
-after it has been internalized.
-
-       bool write(FILE *fp);
-       $data->write($fp);
-       data.write(fp)
-       data.write(fp)
-
-Write the contents of the repodata area as solv file.
-
-       bool add_solv(FILE *fp, int flags = 0);
-       $data->add_solv($fp);
-       data.add_solv(fp)
-       data.add_solv(fp)
-
-Replace a stub repodata object with the data from a solv file. This method
-automatically adds the REPO_USE_LOADING flag. It should only be used from
-a load callback.
-
-       void create_stubs();
-       $data->create_stubs()
-       data.create_stubs()
-       data.create_stubs()
-
-Create stub repodatas from the information stored in the repodata meta
-area.
-
-       void extend_to_repo();
-       $data->extend_to_repo();
-       data.extend_to_repo()
-       data.extend_to_repo()
-
-Extend the repodata so that it has the same size as the repo it belongs to.
-This method is only needed when switching to a just written repodata extension
-to make the repodata match the written extension (which is always of the
-size of the repo).
-
-       <equality>
-       if ($data1 == $data2)
-       if data1 == data2:
-       if data1 == data2
-
-Two repodata objects are equal if they belong to the same repository and have
-the same id.
-
-=== DATA RETRIEVAL METHODS ===
-
-       const char *lookup_str(Id solvid, Id keyname)
-       my $string = $data->lookup_str($solvid, $keyname);
-       string = data.lookup_str(solvid, keyname)
-       string = data.lookup_str(solvid, keyname)
-
-       Id *lookup_idarray(Id solvid, Id keyname)
-       my @ids = $data->lookup_idarray($solvid, $keyname);
-       ids = data.lookup_idarray(solvid, keyname)
-       ids = data.lookup_idarray(solvid, keyname)
-
-       Chksum lookup_checksum(Id solvid, Id keyname)
-       my $chksum = $data->lookup_checksum($solvid, $keyname);
-       chksum = data.lookup_checksum(solvid, keyname)
-       chksum = data.lookup_checksum(solvid, keyname)
-
-Lookup functions. Return the data element stored in the specified solvable.
-The methods probably only make sense to retrieve data from the special
-SOLVID_META solvid that stores repodata meta information.
-
-=== DATA STORAGE METHODS ===
-
-       void set_id(Id solvid, Id keyname, DepId id);
-       $data->set_id($solvid, $keyname, $id);
-       data.set_id(solvid, keyname, id)
-       data.set_id(solvid, keyname, id)
-
-       void set_str(Id solvid, Id keyname, const char *str);
-       $data->set_str($solvid, $keyname, $str);
-       data.set_str(solvid, keyname, str)
-       data.set_str(solvid, keyname, str)
-
-       void set_poolstr(Id solvid, Id keyname, const char *str);
-       $data->set_poolstr($solvid, $keyname, $str);
-       data.set_poolstr(solvid, keyname, str)
-       data.set_poolstr(solvid, keyname, str)
-
-       void set_checksum(Id solvid, Id keyname, Chksum *chksum);
-       $data->set_checksum($solvid, $keyname, $chksum);
-       data.set_checksum(solvid, keyname, chksum)
-       data.set_checksum(solvid, keyname, chksum)
-
-       void add_idarray(Id solvid, Id keyname, DepId id);
-       $data->add_idarray($solvid, $keyname, $id);
-       data.add_idarray(solvid, keyname, id)
-       data.add_idarray(solvid, keyname, id)
-
-       Id new_handle();
-       my $handle = $data->new_handle();
-       handle = data.new_handle()
-       handle = data.new_handle()
-
-       void add_flexarray(Id solvid, Id keyname, Id handle);
-       $data->add_flexarray($solvid, $keyname, $handle);
-       data.add_flexarray(solvid, keyname, handle)
-       data.add_flexarray(solvid, keyname, handle)
-
-Data storage methods. Probably only useful to store data in the special
-SOLVID_META solvid that stores repodata meta information. Note that
-repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag),
-so be careful if you need to store ids. Arrays are created by calling
-the add function for every element. A flexarray is an array of
-sub-structures, call new_handle to create a new structure, use the
-handle as solvid to fill the structure with data and call add_flexarray
-to put the structure in an array.
-
-
-The Datapos Class
------------------
-Datapos objects describe a specific position in the repository data area.
-Thus they are only valid until the repository is modified in some way.
-Datapos objects can be created by the pos() and parentpos() methods of
-a Datamatch object or by accessing the ``meta'' attribute of a repository.
-
-=== ATTRIBUTES ===
-
-       Repo *repo;                     /* read only */
-       $data->{repo}
-       data.repo
-       data.repo
-
-Back pointer to repository object.
-
-=== METHODS ===
-
-       Dataiterator(Id keyname, const char *match, int flags)
-       my $di = $datapos->Dataiterator($keyname, $match, $flags);
-       di = datapos.Dataiterator(keyname, match, flags)
-       di = datapos.Dataiterator(keyname, match, flags)
-
-Create a Dataiterator at the position of the datapos object.
-
-       const char *lookup_deltalocation(unsigned int *OUTPUT);
-       my ($location, $medianr) = $datapos->lookup_deltalocation();
-       location, medianr = datapos.lookup_deltalocation()
-       location, medianr = datapos.lookup_deltalocation()
-
-Return a tuple containing the on-media location and an optional media number
-for a delta rpm. This obviously only works if the data position points to
-structure describing a delta rpm.
-
-       const char *lookup_deltaseq();
-       my $seq = $datapos->lookup_deltaseq();
-       seq = datapos.lookup_deltaseq();
-       seq = datapos.lookup_deltaseq();
-
-Return the delta rpm sequence from the structure describing a delta rpm.
-
-=== DATA RETRIEVAL METHODS ===
-
-       const char *lookup_str(Id keyname)
-       my $string = $datapos->lookup_str($keyname);
-       string = datapos.lookup_str(keyname)
-       string = datapos.lookup_str(keyname)
-
-       Id lookup_id(Id solvid, Id keyname)
-       my $id = $datapos->lookup_id($keyname);
-       id = datapos.lookup_id(keyname)
-       id = datapos.lookup_id(keyname)
-
-       unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0)
-       my $num = $datapos->lookup_num($keyname);
-       num = datapos.lookup_num(keyname)
-       num = datapos.lookup_num(keyname)
-
-       bool lookup_void(Id keyname)
-       my $bool = $datapos->lookup_void($keyname);
-       bool = datapos.lookup_void(keyname)
-       bool = datapos.lookup_void(keyname)
-
-       Id *lookup_idarray(Id keyname)
-       my @ids = $datapos->lookup_idarray($keyname);
-       ids = datapos.lookup_idarray(keyname)
-       ids = datapos.lookup_idarray(keyname)
-
-       Chksum lookup_checksum(Id keyname)
-       my $chksum = $datapos->lookup_checksum($keyname);
-       chksum = datapos.lookup_checksum(keyname)
-       chksum = datapos.lookup_checksum(keyname)
-
-Lookup functions. Note that the returned Ids are always translated into
-the Ids of the global pool even if the repodata area contains its own pool.
-
-       Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0)
-       my $di = $datapos->Dataiterator($keyname, $match, $flags);
-       di = datapos.Dataiterator(keyname, match, flags)
-       di = datapos.Dataiterator(keyname, match, flags)
-
-       for my $d (@$di)
-       for d in di:
-       for d in di
-
-Iterate over the matching data elements. See the Dataiterator class for more
-information.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
-
diff --git a/libsolv-0.6.15/doc/libsolv-constantids.3 b/libsolv-0.6.15/doc/libsolv-constantids.3
deleted file mode 100644 (file)
index 327150c..0000000
+++ /dev/null
@@ -1,906 +0,0 @@
-'\" t
-.\"     Title: Libsolv-Constantids
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 12/14/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "LIBSOLV\-CONSTANTIDS" "3" "12/14/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-libsolv-constantids \- fixed Ids for often used strings
-.SH "DESCRIPTION"
-.sp
-Constant Ids are Ids of strings that are often needed\&. They are defined to ease programming and reduce the number of pool_str2id calls\&. The constant Ids are part of the binary ABI of libsolv, a minor version update will only add new constants and not change existing Ids to maintain compatible\&. The on\-disk solv format works does not use the fixed Ids, but instead references the strings, so solv files can still be read when the ABI is broken\&.
-.SH "SPECIAL STRINGS"
-.PP
-\fBID_EMPTY ""\fR
-.RS 4
-The empty string\&. It will always have Id 1\&.
-.RE
-.PP
-\fBSYSTEM_SYSTEM "system:system"\fR
-.RS 4
-The name of the always installed "system" solvable\&.
-.RE
-.SH "SOLVABLE ATTRIBUTES"
-.sp
-These are Ids for keyname of attributes\&. They can be used in the lookup and storage functions to select the correct attribute in the solvable\&. The descriptions below describe the intended semantics of the values stored in the attribute with the keyname\&.
-.PP
-\fBSOLVABLE_NAME "solvable:name"\fR
-.RS 4
-The name of the package\&.
-.RE
-.PP
-\fBSOLVABLE_ARCH "solvable:arch"\fR
-.RS 4
-The architecture of the package\&. See the Solvable Architecture section for predefined architecture Id values\&.
-.RE
-.PP
-\fBSOLVABLE_EVR "solvable:evr"\fR
-.RS 4
-The version of the package\&. It usually consists of some combination of the Epoch, the Version, and the Release of the solvable\&.
-.RE
-.PP
-\fBSOLVABLE_VENDOR "solvable:vendor"\fR
-.RS 4
-A vendor string\&. Usually the company or group that created the binary package\&.
-.RE
-.PP
-\fBSOLVABLE_PROVIDES "solvable:provides"\fR
-.RS 4
-Stores an array of dependency Ids that describe the capabilities that the package provides\&.
-.RE
-.PP
-\fBSOLVABLE_OBSOLETES "solvable:obsoletes"\fR
-.RS 4
-Stores an array of dependency Ids that describe the packages that this package replaces\&.
-.RE
-.PP
-\fBSOLVABLE_CONFLICTS "solvable:conflicts"\fR
-.RS 4
-Stores an array of dependency Ids that describe the capabilities that this package conflicts with, i\&.e\&. that can\(cqt be installed together with this package\&.
-.RE
-.PP
-\fBSOLVABLE_REQUIRES "solvable:requires"\fR
-.RS 4
-Stores an array of dependency Ids that describe the capabilities that also must be installed when this package is installed\&.
-.RE
-.PP
-\fBSOLVABLE_RECOMMENDS "solvable:recommends"\fR
-.RS 4
-Stores an array of dependency Ids that describe the capabilities that also should be installed when this package is installed\&. It\(cqs not an error if not all capabilities can be met\&.
-.RE
-.PP
-\fBSOLVABLE_SUGGESTS "solvable:suggests"\fR
-.RS 4
-Stores an array of dependency Ids that describe the capabilities that also useful to have installed when this package is installed\&. This is intended to provide a hint to the user about other packages\&.
-.RE
-.PP
-\fBSOLVABLE_SUPPLEMENTS "solvable:supplements"\fR
-.RS 4
-Stores an array of dependency Ids that define that this package should be installed if one of the capabilities is met\&. This is like the recommends attribute, but works in the reverse way\&.
-.RE
-.PP
-\fBSOLVABLE_ENHANCES "solvable:enhances"\fR
-.RS 4
-Stores an array of dependency Ids that define that this package is useful to have installed if one of the capabilities is met\&. This is like the suggests attribute, but works in the reverse way\&.
-.RE
-.PP
-\fBSOLVABLE_SUMMARY "solvable:summary"\fR
-.RS 4
-The summary should be a short string without any newlines that describes what a package does\&.
-.RE
-.PP
-\fBSOLVABLE_DESCRIPTION "solvable:description"\fR
-.RS 4
-The description should be a more verbose description about what a package does\&. It may consist of multiple lines\&.
-.RE
-.PP
-\fBSOLVABLE_DISTRIBUTION "solvable:distribution"\fR
-.RS 4
-The distribution is a short string that describes the OS and OS version this package is built for\&.
-.RE
-.PP
-\fBSOLVABLE_AUTHORS "solvable:authors"\fR
-.RS 4
-A list of authors of this package\&. This attribute was used in SUSE packages\&.
-.RE
-.PP
-\fBSOLVABLE_PACKAGER "solvable:packager"\fR
-.RS 4
-The person who created the binary package, see also the vendor attribute\&.
-.RE
-.PP
-\fBSOLVABLE_GROUP "solvable:group"\fR
-.RS 4
-The package group that this package belongs to\&. See also the keywords attribute\&.
-.RE
-.PP
-\fBSOLVABLE_URL "solvable:url"\fR
-.RS 4
-An URL that points to more information about the package\&.
-.RE
-.PP
-\fBSOLVABLE_KEYWORDS "solvable:keywords"\fR
-.RS 4
-list of keyword string IDs used for tagging this package\&.
-.RE
-.PP
-\fBSOLVABLE_LICENSE "solvable:license"\fR
-.RS 4
-The license(s) of this package\&.
-.RE
-.PP
-\fBSOLVABLE_BUILDTIME "solvable:buildtime"\fR
-.RS 4
-The seconds since the unix epoch when the binary package was created\&.
-.RE
-.PP
-\fBSOLVABLE_BUILDHOST "solvable:buildhost"\fR
-.RS 4
-The name of the host on which the binary package was created\&.
-.RE
-.PP
-\fBSOLVABLE_EULA "solvable:eula"\fR
-.RS 4
-If this attribute is present the user should be asked to accept the end user license agreement before the package gets installed\&.
-.RE
-.PP
-\fBSOLVABLE_CPEID "solvable:cpeid"\fR
-.RS 4
-A Common Platform Enumeration string describes the platform this package is intended for\&. See also the distribution attribute\&.
-.RE
-.PP
-\fBSOLVABLE_MESSAGEINS "solvable:messageins"\fR
-.RS 4
-A message that should be displayed to the user when the package gets installed\&.
-.RE
-.PP
-\fBSOLVABLE_MESSAGEDEL "solvable:messagedel"\fR
-.RS 4
-A message that should be displayed to the user when the package gets erased\&.
-.RE
-.PP
-\fBSOLVABLE_INSTALLSIZE "solvable:installsize"\fR
-.RS 4
-The disk space in bytes needed when installing the package\&.
-.RE
-.PP
-\fBSOLVABLE_DISKUSAGE "solvable:diskusage"\fR
-.RS 4
-A SUSE extension that stores for each directory the needed amount of disk space in kilobytes and inodes\&.
-.RE
-.PP
-\fBSOLVABLE_FILELIST "solvable:filelist"\fR
-.RS 4
-A list of files that the package contains\&.
-.RE
-.PP
-\fBSOLVABLE_INSTALLTIME "solvable:installtime"\fR
-.RS 4
-The seconds since the unix epoch when the binary package was installed on the system\&.
-.RE
-.PP
-\fBSOLVABLE_MEDIADIR "solvable:mediadir"\fR
-.RS 4
-The directory on the repository that contains the package\&. If this attribute is set to void, the package architecture is used as directory\&.
-.RE
-.PP
-\fBSOLVABLE_MEDIAFILE "solvable:mediafile"\fR
-.RS 4
-The filename on the repository that contains the package\&. If this attribute is set to void, the canonical file name of the package is used (i\&.e\&. a combination of the name, version, architecture)\&.
-.RE
-.PP
-\fBSOLVABLE_MEDIANR "solvable:medianr"\fR
-.RS 4
-The media number\&. This is an integer describing on which of a multi\-part media set this package is on\&.
-.RE
-.PP
-\fBSOLVABLE_MEDIABASE "solvable:mediabase"\fR
-.RS 4
-This attribute can be used to overwrite the repositories base url\&.
-.RE
-.PP
-\fBSOLVABLE_DOWNLOADSIZE "solvable:downloadsize"\fR
-.RS 4
-The size of the binary package in bytes\&.
-.RE
-.PP
-\fBSOLVABLE_SOURCEARCH "solvable:sourcearch"\fR
-.RS 4
-The architecture of the source package that this package belongs to\&.
-.RE
-.PP
-\fBSOLVABLE_SOURCENAME "solvable:sourcename"\fR
-.RS 4
-The name of the source package that this package belongs to\&. If set to void, the package name attribute is used instead\&.
-.RE
-.PP
-\fBSOLVABLE_SOURCEEVR "solvable:sourceevr"\fR
-.RS 4
-The version of the source package that this package belongs to\&. If set to void, the package version attribute is used instead\&.
-.RE
-.PP
-\fBSOLVABLE_TRIGGERS "solvable:triggers"\fR
-.RS 4
-A list of package triggers for this package\&. Used in the transaction ordering code\&.
-.RE
-.PP
-\fBSOLVABLE_CHECKSUM "solvable:checksum"\fR
-.RS 4
-The checksum of the binary package\&. See the Data Types section for a list of supported algorithms\&.
-.RE
-.PP
-\fBSOLVABLE_PKGID "solvable:pkgid"\fR
-.RS 4
-A string identifying a package\&. For rpm packages, this is the md5sum over the package header and the payload\&.
-.RE
-.PP
-\fBSOLVABLE_HDRID "solvable:hdrid"\fR
-.RS 4
-A string identifying a package\&. For rpm packages, this is the sha1sum over just the package header\&.
-.RE
-.PP
-\fBSOLVABLE_LEADSIGID "solvable:leadsigid"\fR
-.RS 4
-A string identifying the signature part of a package\&. For rpm packages, this is the md5sum from the start of the file up to the package header (i\&.e\&. it includes the lead, the signature header, and the padding)\&.
-.RE
-.PP
-\fBSOLVABLE_HEADEREND "solvable:headerend"\fR
-.RS 4
-The offset of the payload in rpm binary packages\&. You can use this information to download just the header if you want to display information not included in the repository metadata\&.
-.RE
-.PP
-\fBSOLVABLE_CHANGELOG "solvable:changelog"\fR
-.RS 4
-The array containing all the changelog structures\&.
-.RE
-.PP
-\fBSOLVABLE_CHANGELOG_AUTHOR "solvable:changelog:author"\fR
-.RS 4
-The author of a changelog entry\&.
-.RE
-.PP
-\fBSOLVABLE_CHANGELOG_TIME "solvable:changelog:time"\fR
-.RS 4
-The seconds since the unix epoch when the changelog entry was written\&.
-.RE
-.PP
-\fBSOLVABLE_CHANGELOG_TEXT "solvable:changelog:text"\fR
-.RS 4
-The text of a changelog entry\&.
-.RE
-.SH "SPECIAL SOLVABLE ATTRIBUTES"
-.PP
-\fBRPM_RPMDBID "rpm:dbid"\fR
-.RS 4
-The rpm database id of this (installed) package\&. Usually a small integer number\&.
-.RE
-.PP
-\fBSOLVABLE_PATCHCATEGORY "solvable:patchcategory"\fR
-.RS 4
-The category field for patch solvables\&. Should be named \(lqupdate:category\(rq instead\&.
-.RE
-.PP
-\fBUPDATE_REBOOT "update:reboot"\fR
-.RS 4
-If this attribute is present the system should be rebooted after the update is installed\&.
-.RE
-.PP
-\fBUPDATE_RESTART "update:restart"\fR
-.RS 4
-If this attribute is present the software manager should be run again after the update is installed\&.
-.RE
-.PP
-\fBUPDATE_RELOGIN "update:relogin"\fR
-.RS 4
-If this attribute is present the user should log off and on again after the update is installed\&.
-.RE
-.PP
-\fBUPDATE_MESSAGE "update:message"\fR
-.RS 4
-A message that should be shown to the user to warn him about anything non\-standard\&.
-.RE
-.PP
-\fBUPDATE_SEVERITY "update:severity"\fR
-.RS 4
-The severity of the update\&.
-.RE
-.PP
-\fBUPDATE_RIGHTS "update:rights"\fR
-.RS 4
-Any legal or other rights of the update\&.
-.RE
-.PP
-\fBUPDATE_COLLECTION "update:collection"\fR
-.RS 4
-The array containing the package list of the update\&.
-.RE
-.PP
-\fBUPDATE_COLLECTION_NAME "update:collection:name"\fR
-.RS 4
-The name of the updated package\&.
-.RE
-.PP
-\fBUPDATE_COLLECTION_EVR "update:collection:evr"\fR
-.RS 4
-The version of the updated package\&.
-.RE
-.PP
-\fBUPDATE_COLLECTION_ARCH "update:collection:arch"\fR
-.RS 4
-The architecture of the updated package\&.
-.RE
-.PP
-\fBUPDATE_COLLECTION_FILENAME "update:collection:filename"\fR
-.RS 4
-The file name of the updated package\&.
-.RE
-.PP
-\fBUPDATE_REFERENCE "update:reference"\fR
-.RS 4
-The array containing the reference list of the update\&.
-.RE
-.PP
-\fBUPDATE_REFERENCE_TYPE "update:reference:type"\fR
-.RS 4
-The type of the reference, e\&.g\&. bugzilla\&.
-.RE
-.PP
-\fBUPDATE_REFERENCE_HREF "update:reference:href"\fR
-.RS 4
-The URL of the reference\&.
-.RE
-.PP
-\fBUPDATE_REFERENCE_ID "update:reference:id"\fR
-.RS 4
-The identification string of the reference, e\&.g\&. the bug number\&.
-.RE
-.PP
-\fBUPDATE_REFERENCE_TITLE "update:reference:title"\fR
-.RS 4
-The title of the reference, e\&.g\&. the bug summary\&.
-.RE
-.PP
-\fBPRODUCT_REFERENCEFILE "product:referencefile"\fR
-.RS 4
-The basename of the product file in the package\&.
-.RE
-.PP
-\fBPRODUCT_SHORTLABEL "product:shortlabel"\fR
-.RS 4
-An identification string of the product\&.
-.RE
-.PP
-\fBPRODUCT_DISTPRODUCT "product:distproduct"\fR
-.RS 4
-Obsolete, do not use\&. Was a SUSE Code\-10 product name\&.
-.RE
-.PP
-\fBPRODUCT_DISTVERSION "product:distversion"\fR
-.RS 4
-Obsolete, do not use\&. Was a SUSE Code\-10 product version\&.
-.RE
-.PP
-\fBPRODUCT_TYPE "product:type"\fR
-.RS 4
-The type of the product, e\&.g\&. \(lqbase\(rq\&.
-.RE
-.PP
-\fBPRODUCT_URL "product:url"\fR
-.RS 4
-An array of product URLs\&.
-.RE
-.PP
-\fBPRODUCT_URL_TYPE "product:url:type"\fR
-.RS 4
-An array of product URL types\&.
-.RE
-.PP
-\fBPRODUCT_FLAGS "product:flags"\fR
-.RS 4
-An array of product flags\&.
-.RE
-.PP
-\fBPRODUCT_PRODUCTLINE "product:productline"\fR
-.RS 4
-A product line string used for product registering\&.
-.RE
-.PP
-\fBPRODUCT_REGISTER_TARGET "product:regtarget"\fR
-.RS 4
-A target for product registering\&.
-.RE
-.PP
-\fBPRODUCT_REGISTER_RELEASE "product:regrelease"\fR
-.RS 4
-A release string for product registering\&.
-.RE
-.PP
-\fBPUBKEY_KEYID "pubkey:keyid"\fR
-.RS 4
-The keyid of a pubkey, consisting of 8 bytes in hex\&.
-.RE
-.PP
-\fBPUBKEY_FINGERPRINT "pubkey:fingerprint"\fR
-.RS 4
-The fingerprint of a pubkey, usually a sha1sum in hex\&. Old V3 RSA keys use a md5sum instead\&.
-.RE
-.PP
-\fBPUBKEY_EXPIRES "pubkey:expires"\fR
-.RS 4
-The seconds since the unix epoch when the pubkey expires\&.
-.RE
-.PP
-\fBPUBKEY_SUBKEYOF "pubkey:subkeyof"\fR
-.RS 4
-The keyid of the master pubkey for subkeys\&.
-.RE
-.PP
-\fBPUBKEY_DATA "pubkey:data"\fR
-.RS 4
-The MPI data of the pubkey\&.
-.RE
-.PP
-\fBSOLVABLE_ISVISIBLE "solvable:isvisible"\fR
-.RS 4
-An attribute describing if the package should be listed to the user or not\&. Used for SUSE patterns\&.
-.RE
-.PP
-\fBSOLVABLE_CATEGORY "solvable:category"\fR
-.RS 4
-The category of a pattern\&.
-.RE
-.PP
-\fBSOLVABLE_INCLUDES "solvable:includes"\fR
-.RS 4
-A list of other patterns that this pattern includes\&.
-.RE
-.PP
-\fBSOLVABLE_EXTENDS "solvable:extends"\fR
-.RS 4
-A list of other patterns that this pattern extends\&.
-.RE
-.PP
-\fBSOLVABLE_ICON "solvable:icon"\fR
-.RS 4
-The icon name of a pattern\&.
-.RE
-.PP
-\fBSOLVABLE_ORDER "solvable:order"\fR
-.RS 4
-An ordering clue of a pattern\&.
-.RE
-.PP
-\fBSUSETAGS_SHARE_NAME "susetags:share:name"\fR
-.RS 4
-Internal attribute to implement susetags shared records\&. Holds the name of the solvable used for sharing attributes\&.
-.RE
-.PP
-\fBSUSETAGS_SHARE_EVR "susetags:share:evr"\fR
-.RS 4
-Internal attribute to implement susetags shared records\&. Holds the version of the solvable used for sharing attributes\&.
-.RE
-.PP
-\fBSUSETAGS_SHARE_ARCH "susetags:share:arch"\fR
-.RS 4
-Internal attribute to implement susetags shared records\&. Holds the architecture of the solvable used for sharing attributes\&.
-.RE
-.SH "SOLVABLE ARCHITECTURES"
-.sp
-Predefined architecture values for commonly used architectures\&.
-.PP
-\fBARCH_SRC "src"\fR
-.RS 4
-Used for binary packages that contain the package sources\&.
-.RE
-.PP
-\fBARCH_NOSRC "nosrc"\fR
-.RS 4
-Used for binary packages that contain some of the package sources, but not all files (because of restrictions)\&.
-.RE
-.PP
-\fBARCH_NOARCH "noarch"\fR
-.RS 4
-This package can be installed on any architecture\&. Used for rpm\&.
-.RE
-.PP
-\fBARCH_ALL "all"\fR
-.RS 4
-This package can be installed on any architecture\&. Used for Debian\&.
-.RE
-.PP
-\fBARCH_ANY "any"\fR
-.RS 4
-This package can be installed on any architecture\&. Used for Archlinux and Haiku\&.
-.RE
-.SH "DEPENDENCY IDS"
-.sp
-Namespaces are special modifiers that change the meaning of a dependency\&. Namespace dependencies are created with the REL_NAMESPACE flag\&. To make custom namespaces work you have to implement a namespace callback function\&.
-.sp
-The dependency markers partition the dependency array in two parts with different semantics\&.
-.PP
-\fBNAMESPACE_MODALIAS "namespace:modalias"\fR
-.RS 4
-The dependency is a special modalias dependency that matches installed hardware\&.
-.RE
-.PP
-\fBNAMESPACE_SPLITPROVIDES "namespace:splitprovides"\fR
-.RS 4
-The dependency is a special splitprovides dependency used to implement updates that include a package split\&. A splitprovides dependency contains a filename and a package name, it is matched if a package with the provided package name is installed that contains the filename\&. This namespace is implemented in libsolv, so you do not need a callback\&.
-.RE
-.PP
-\fBNAMESPACE_LANGUAGE "namespace:language"\fR
-.RS 4
-The dependency describes a language\&. The callback should return true if the language was selected by the user\&.
-.RE
-.PP
-\fBNAMESPACE_FILESYSTEM "namespace:filesystem"\fR
-.RS 4
-The dependency describes a filesystem\&. The callback should return true if the filesystem is needed\&.
-.RE
-.PP
-\fBNAMESPACE_OTHERPROVIDERS "namespace:otherproviders"\fR
-.RS 4
-This is a hack to allow self\-conflicting packages\&. It is not needed with current rpm version, so do not use this namespace\&.
-.RE
-.PP
-\fBSOLVABLE_PREREQMARKER "solvable:prereqmarker"\fR
-.RS 4
-This marker partitions the normal require dependencies from the prerequires\&. It is not needed for dependency solving, but it is used by the transaction ordering algorithm when a dependency cycle needs to be broken (non\-prereq deps get broken first)\&.
-.RE
-.PP
-\fBSOLVABLE_FILEMARKER "solvable:filemarker"\fR
-.RS 4
-This marker partitions the package provides dependencies from the synthetic file provides dependencies added by pool_addfileprovides()\&.
-.RE
-.SH "DATA TYPES"
-.sp
-Each attribute data is stored with a type, so that the lookup functions know how to interpret the data\&. The following types are available:
-.PP
-\fBREPOKEY_TYPE_VOID "repokey:type:void"\fR
-.RS 4
-No data is stored with this attribute\&. Thus you can only test if the attribute exists or not\&. Useful to store boolean values\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_CONSTANT "repokey:type:constant"\fR
-.RS 4
-The data is a constant 32bit number\&. The number is stored in the key area, so using it does not cost extra storage space (but you need the extra key space)\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_CONSTANTID "repokey:type:constantid"\fR
-.RS 4
-The data is a constant Id\&. The Id is stored in the key area, so using it does not cost extra storage space (but you need the extra key space)\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_ID "repokey:type:id"\fR
-.RS 4
-The data is an Id\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_NUM "repokey:type:num"\fR
-.RS 4
-The data is an unsigned 64bit number\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_U32 "repokey:type:num32"\fR
-.RS 4
-The data is an unsigned 32bit number\&. Obsolete, do not use\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_DIR "repokey:type:dir"\fR
-.RS 4
-The data is an Id of a directory\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_STR "repokey:type:str"\fR
-.RS 4
-The data is a regular string\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_BINARY "repokey:type:binary"\fR
-.RS 4
-The data is a binary blob\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_IDARRAY "repokey:type:idarray"\fR
-.RS 4
-The data is an array of non\-zero Ids\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_REL_IDARRAY "repokey:type:relidarray"\fR
-.RS 4
-The data is an array of non\-zero Ids ordered so that it needs less space\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_DIRSTRARRAY "repokey:type:dirstrarray"\fR
-.RS 4
-The data is a tuple consisting of a directory Id and a basename\&. Used to store file names\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_DIRNUMNUMARRAY "repokey:type:dirnumnumarray"\fR
-.RS 4
-The data is a triple consisting of a directory Id and two 32bit unsigned integers\&. Used to store disk usage information\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_MD5 "repokey:type:md5"\fR
-.RS 4
-The data is a binary md5sum\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_SHA1 "repokey:type:sha1"\fR
-.RS 4
-The data is a binary sha1sum\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_SHA256 "repokey:type:sha256"\fR
-.RS 4
-The data is a binary sha256sum\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_FIXARRAY "repokey:type:fixarray"\fR
-.RS 4
-The data is an array of structures that have all the same layout (i\&.e\&. the same keynames and keytypes in the same order)\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_FLEXARRAY "repokey:type:flexarray"\fR
-.RS 4
-The data is an array of structures that have a different layout\&.
-.RE
-.PP
-\fBREPOKEY_TYPE_DELETED "repokey:type:deleted"\fR
-.RS 4
-The data does not exist\&. Used to mark an attribute that was deleted\&.
-.RE
-.SH "REPOSITORY METADATA"
-.sp
-This attributes contain meta information about the repository\&.
-.PP
-\fBREPOSITORY_SOLVABLES "repository:solvables"\fR
-.RS 4
-This attribute holds the array including all of the solvables\&. It is only used in the on\-disk solv files, internally the solvables are stored in the pool\(cqs solvable array for fast access\&.
-.RE
-.PP
-\fBREPOSITORY_DELTAINFO "repository:deltainfo"\fR
-.RS 4
-This attribute holds the array including all of the delta packages\&.
-.RE
-.PP
-\fBREPOSITORY_EXTERNAL "repository:external"\fR
-.RS 4
-This attribute holds the array including all of the data to construct stub repodata areas to support on\-demand loading of metadata\&.
-.RE
-.PP
-\fBREPOSITORY_KEYS "repository:keys"\fR
-.RS 4
-This should really be named "repository:external:keys", it contains an array if Ids that consists of (keyname, keytype) pairs that describe the keys of the stub\&.
-.RE
-.PP
-\fBREPOSITORY_LOCATION "repository:location"\fR
-.RS 4
-This is used to provide a file name in the stub\&.
-.RE
-.PP
-\fBREPOSITORY_ADDEDFILEPROVIDES "repository:addedfileprovides"\fR
-.RS 4
-This attribute holds an array of filename Ids, that tell the library, that all of the Ids were already added to the solvable provides\&.
-.RE
-.PP
-\fBREPOSITORY_RPMDBCOOKIE "repository:rpmdbcookie"\fR
-.RS 4
-An attribute that stores a sha256sum over the file stats of the Packages database\&. It\(cqs used to detect rebuilds of the database, as in that case the database Ids of every package are newly distributed\&.
-.RE
-.PP
-\fBREPOSITORY_TIMESTAMP "repository:timestamp"\fR
-.RS 4
-The seconds since the unix epoch when the repository was created\&.
-.RE
-.PP
-\fBREPOSITORY_EXPIRE "repository:expire"\fR
-.RS 4
-The seconds after the timestamp when the repository will expire\&.
-.RE
-.PP
-\fBREPOSITORY_UPDATES "repository:updates"\fR
-.RS 4
-An array of structures describing what this repository updates\&.
-.RE
-.PP
-\fBREPOSITORY_DISTROS "repository:distros"\fR
-.RS 4
-Also an array of structures describing what this repository updates\&. Seems to be the newer name of REPOSITORY_UPDATES\&.
-.RE
-.PP
-\fBREPOSITORY_PRODUCT_LABEL "repository:product:label"\fR
-.RS 4
-Should really be called "repository:updates:label"\&. What distribution is updated with this repository\&.
-.RE
-.PP
-\fBREPOSITORY_PRODUCT_CPEID "repository:product:cpeid"\fR
-.RS 4
-The cpeid of the platform updated by this repository\&. Is both used in REPOSITORY_UPDATES and REPOSITORY_DISTROS to maximize confusion\&.
-.RE
-.PP
-\fBREPOSITORY_REPOID "repository:repoid"\fR
-.RS 4
-An array of Id strings describing keywords/tags about the repository itself\&.
-.RE
-.PP
-\fBREPOSITORY_KEYWORDS "repository:keywords"\fR
-.RS 4
-An array of Id strings describing keywords/tags about the content of the repository\&.
-.RE
-.PP
-\fBREPOSITORY_REVISION "repository:revision"\fR
-.RS 4
-An arbitrary string describing the revision of the repository\&.
-.RE
-.PP
-\fBREPOSITORY_TOOLVERSION "repository:toolversion"\fR
-.RS 4
-Some string describing somewhat the version of libsolv used to create the solv file\&.
-.RE
-.SH "REPOSITORY METADATA FOR SUSETAGS REPOS"
-.sp
-Attributes describing repository files in a susetags repository\&. \fBSUSETAGS_DATADIR "susetags:datadir"\fR:: The directory that contains the packages\&.
-.PP
-\fBSUSETAGS_DESCRDIR "susetags:descrdir"\fR
-.RS 4
-The directory that contains the repository file resources\&.
-.RE
-.PP
-\fBSUSETAGS_DEFAULTVENDOR "susetags:defaultvendor"\fR
-.RS 4
-The default vendor used when a package does not specify a vendor\&.
-.RE
-.PP
-\fBSUSETAGS_FILE "susetags:file"\fR
-.RS 4
-An array of file resources of the repository\&.
-.RE
-.PP
-\fBSUSETAGS_FILE_NAME "susetags:file:name"\fR
-.RS 4
-The filename of the resource\&.
-.RE
-.PP
-\fBSUSETAGS_FILE_TYPE "susetags:file:type"\fR
-.RS 4
-The type of the resource, e\&.g\&. \(lqMETA\(rq\&.
-.RE
-.PP
-\fBSUSETAGS_FILE_CHECKSUM "susetags:file:checksum"\fR
-.RS 4
-The file checksum of the resource\&.
-.RE
-.SH "REPOSITORY METADATA FOR RPMMD REPOS"
-.PP
-\fBREPOSITORY_REPOMD "repository:repomd"\fR
-.RS 4
-An array of file resources of the repository\&.
-.RE
-.PP
-\fBREPOSITORY_REPOMD_TYPE "repository:repomd:type"\fR
-.RS 4
-The type of the resource, e\&.g\&. \(lqprimary\(rq\&.
-.RE
-.PP
-\fBREPOSITORY_REPOMD_LOCATION "repository:repomd:location"\fR
-.RS 4
-The location (aka filename) of the resource
-.RE
-.PP
-\fBREPOSITORY_REPOMD_TIMESTAMP "repository:repomd:timestamp"\fR
-.RS 4
-The seconds since the unix epoch when the resource was created\&.
-.RE
-.PP
-\fBREPOSITORY_REPOMD_CHECKSUM "repository:repomd:checksum"\fR
-.RS 4
-The file checksum of the resource\&.
-.RE
-.PP
-\fBREPOSITORY_REPOMD_OPENCHECKSUM "repository:repomd:openchecksum"\fR
-.RS 4
-The checksum over the uncompressed contents of the resource\&.
-.RE
-.PP
-\fBREPOSITORY_REPOMD_SIZE "repository:repomd:size"\fR
-.RS 4
-The size of the resource file\&.
-.RE
-.SH "DELTA PACKAGE ATTRIBUTES"
-.PP
-\fBDELTA_PACKAGE_NAME "delta:pkgname"\fR
-.RS 4
-The target package name for the delta package\&. Applying the delta will recreate the target package\&.
-.RE
-.PP
-\fBDELTA_PACKAGE_EVR "delta:pkgevr"\fR
-.RS 4
-The version of the target package\&.
-.RE
-.PP
-\fBDELTA_PACKAGE_ARCH "delta:pkgarch"\fR
-.RS 4
-The architecture of the target package\&.
-.RE
-.PP
-\fBDELTA_LOCATION_DIR "delta:locdir"\fR
-.RS 4
-The directory in the repository that contains the delta package\&.
-.RE
-.PP
-\fBDELTA_LOCATION_NAME "delta:locname"\fR
-.RS 4
-The first part of the file name of the delta package\&.
-.RE
-.PP
-\fBDELTA_LOCATION_EVR "delta:locevr"\fR
-.RS 4
-The version part of the file name of the delta package\&.
-.RE
-.PP
-\fBDELTA_LOCATION_SUFFIX "delta:locsuffix"\fR
-.RS 4
-The suffix part of the file name of the delta package\&.
-.RE
-.PP
-\fBDELTA_LOCATION_BASE "delta:locbase"\fR
-.RS 4
-This attribute can be used to overwrite the repositories base url for the delta\&.
-.RE
-.PP
-\fBDELTA_DOWNLOADSIZE "delta:downloadsize"\fR
-.RS 4
-The size of the delta rpm file\&.
-.RE
-.PP
-\fBDELTA_CHECKSUM "delta:checksum"\fR
-.RS 4
-The checksum of the delta rpm file\&.
-.RE
-.PP
-\fBDELTA_BASE_EVR "delta:baseevr"\fR
-.RS 4
-The version of the package the delta was built against\&.
-.RE
-.PP
-\fBDELTA_SEQ_NAME "delta:seqname"\fR
-.RS 4
-The first part of the delta sequence, the base package name\&.
-.RE
-.PP
-\fBDELTA_SEQ_EVR "delta:seqevr"\fR
-.RS 4
-The evr part of the delta sequence, the base package evr\&. Identical to the DELTA_BASE_EVR attribute\&.
-.RE
-.PP
-\fBDELTA_SEQ_NUM "delta:seqnum"\fR
-.RS 4
-The last part of the delta sequence, the content selection string\&.
-.RE
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/libsolv-constantids.txt b/libsolv-0.6.15/doc/libsolv-constantids.txt
deleted file mode 100644 (file)
index e067642..0000000
+++ /dev/null
@@ -1,680 +0,0 @@
-Libsolv-Constantids(3)
-======================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-libsolv-constantids - fixed Ids for often used strings
-
-
-Description
------------
-Constant Ids are Ids of strings that are often needed. They are defined
-to ease programming and reduce the number of pool_str2id calls. The
-constant Ids are part of the binary ABI of libsolv, a minor version 
-update will only add new constants and not change existing Ids to
-maintain compatible. The on-disk solv format works does not use the
-fixed Ids, but instead references the strings, so solv files can still
-be read when the ABI is broken.
-
-
-Special Strings
----------------
-*ID_EMPTY ""*::
-  The empty string. It will always have Id 1.
-
-*SYSTEM_SYSTEM "system:system"*::
-  The name of the always installed "system" solvable.
-
-
-Solvable Attributes
--------------------
-These are Ids for keyname of attributes. They can be used in the
-lookup and storage functions to select the correct attribute in the
-solvable. The descriptions below describe the intended semantics
-of the values stored in the attribute with the keyname.
-
-*SOLVABLE_NAME "solvable:name"*::
-  The name of the package.
-
-*SOLVABLE_ARCH "solvable:arch"*::
-  The architecture of the package. See the Solvable Architecture section
-  for predefined architecture Id values.
-
-*SOLVABLE_EVR "solvable:evr"*::
-  The version of the package. It usually consists of some combination of
-  the Epoch, the Version, and the Release of the solvable.
-
-*SOLVABLE_VENDOR "solvable:vendor"*::
-  A vendor string. Usually the company or group that created the binary
-  package.
-
-*SOLVABLE_PROVIDES "solvable:provides"*::
-  Stores an array of dependency Ids that describe the capabilities
-  that the package provides.
-
-*SOLVABLE_OBSOLETES "solvable:obsoletes"*::
-  Stores an array of dependency Ids that describe the packages that this
-  package replaces.
-
-*SOLVABLE_CONFLICTS "solvable:conflicts"*::
-  Stores an array of dependency Ids that describe the capabilities that
-  this package conflicts with, i.e. that can't be installed together with
-  this package.
-
-*SOLVABLE_REQUIRES "solvable:requires"*::
-  Stores an array of dependency Ids that describe the capabilities that
-  also must be installed when this package is installed.
-
-*SOLVABLE_RECOMMENDS "solvable:recommends"*::
-  Stores an array of dependency Ids that describe the capabilities that
-  also should be installed when this package is installed. It's not an
-  error if not all capabilities can be met.
-
-*SOLVABLE_SUGGESTS "solvable:suggests"*::
-  Stores an array of dependency Ids that describe the capabilities that
-  also useful to have installed when this package is installed. This is
-  intended to provide a hint to the user about other packages.
-
-*SOLVABLE_SUPPLEMENTS "solvable:supplements"*::
-  Stores an array of dependency Ids that define that this package should
-  be installed if one of the capabilities is met. This is like the
-  recommends attribute, but works in the reverse way.
-
-*SOLVABLE_ENHANCES "solvable:enhances"*::
-  Stores an array of dependency Ids that define that this package is
-  useful to have installed if one of the capabilities is met. This is like
-  the suggests attribute, but works in the reverse way.
-
-*SOLVABLE_SUMMARY "solvable:summary"*::
-  The summary should be a short string without any newlines that describes
-  what a package does.
-
-*SOLVABLE_DESCRIPTION "solvable:description"*::
-  The description should be a more verbose description about what a
-  package does. It may consist of multiple lines.
-
-*SOLVABLE_DISTRIBUTION "solvable:distribution"*::
-  The distribution is a short string that describes the OS and OS version
-  this package is built for.
-
-*SOLVABLE_AUTHORS "solvable:authors"*::
-  A list of authors of this package. This attribute was used in SUSE
-  packages.
-
-*SOLVABLE_PACKAGER "solvable:packager"*::
-  The person who created the binary package, see also the vendor attribute.
-
-*SOLVABLE_GROUP "solvable:group"*::
-  The package group that this package belongs to. See also the keywords
-  attribute.
-
-*SOLVABLE_URL "solvable:url"*::
-  An URL that points to more information about the package.
-
-*SOLVABLE_KEYWORDS "solvable:keywords"*::
-  list of keyword string IDs used for tagging this package.
-
-*SOLVABLE_LICENSE "solvable:license"*::
-  The license(s) of this package.
-
-*SOLVABLE_BUILDTIME "solvable:buildtime"*::
-  The seconds since the unix epoch when the binary package was created.
-
-*SOLVABLE_BUILDHOST "solvable:buildhost"*::
-  The name of the host on which the binary package was created.
-
-*SOLVABLE_EULA "solvable:eula"*::
-  If this attribute is present the user should be asked to accept the end
-  user license agreement before the package gets installed.
-
-*SOLVABLE_CPEID "solvable:cpeid"*::
-  A Common Platform Enumeration string describes the platform this package
-  is intended for. See also the distribution attribute.
-
-*SOLVABLE_MESSAGEINS "solvable:messageins"*::
-  A message that should be displayed to the user when the package gets
-  installed.
-
-*SOLVABLE_MESSAGEDEL "solvable:messagedel"*::
-  A message that should be displayed to the user when the package gets
-  erased.
-
-*SOLVABLE_INSTALLSIZE "solvable:installsize"*::
-  The disk space in bytes needed when installing the package.
-
-*SOLVABLE_DISKUSAGE "solvable:diskusage"*::
-  A SUSE extension that stores for each directory the needed amount of
-  disk space in kilobytes and inodes.
-
-*SOLVABLE_FILELIST "solvable:filelist"*::
-  A list of files that the package contains.
-
-*SOLVABLE_INSTALLTIME "solvable:installtime"*::
-  The seconds since the unix epoch when the binary package was installed
-  on the system.
-
-*SOLVABLE_MEDIADIR "solvable:mediadir"*::
-  The directory on the repository that contains the package. If this
-  attribute is set to void, the package architecture is used as
-  directory.
-
-*SOLVABLE_MEDIAFILE "solvable:mediafile"*::
-  The filename on the repository that contains the package. If this
-  attribute is set to void, the canonical file name of the package is
-  used (i.e.  a combination of the name, version, architecture).
-
-*SOLVABLE_MEDIANR "solvable:medianr"*::
-  The media number. This is an integer describing on which of a multi-part
-  media set this package is on.
-
-*SOLVABLE_MEDIABASE "solvable:mediabase"*::
-  This attribute can be used to overwrite the repositories base url.
-
-*SOLVABLE_DOWNLOADSIZE "solvable:downloadsize"*::
-  The size of the binary package in bytes.
-
-*SOLVABLE_SOURCEARCH "solvable:sourcearch"*::
-  The architecture of the source package that this package belongs to.
-
-*SOLVABLE_SOURCENAME "solvable:sourcename"*::
-  The name of the source package that this package belongs to. If set
-  to void, the package name attribute is used instead.
-
-*SOLVABLE_SOURCEEVR "solvable:sourceevr"*::
-  The version of the source package that this package belongs to. If set
-  to void, the package version attribute is used instead.
-
-*SOLVABLE_TRIGGERS "solvable:triggers"*::
-  A list of package triggers for this package. Used in the transaction
-  ordering code.
-
-*SOLVABLE_CHECKSUM "solvable:checksum"*::
-  The checksum of the binary package. See the Data Types section for
-  a list of supported algorithms.
-
-*SOLVABLE_PKGID "solvable:pkgid"*::
-  A string identifying a package. For rpm packages, this is the md5sum
-  over the package header and the payload.
-
-*SOLVABLE_HDRID "solvable:hdrid"*::
-  A string identifying a package. For rpm packages, this is the sha1sum
-  over just the package header.
-
-*SOLVABLE_LEADSIGID "solvable:leadsigid"*::
-  A string identifying the signature part of a package. For rpm packages,
-  this is the md5sum from the start of the file up to the package header
-  (i.e. it includes the lead, the signature header, and the padding).
-
-*SOLVABLE_HEADEREND "solvable:headerend"*::
-  The offset of the payload in rpm binary packages. You can use this
-  information to download just the header if you want to display
-  information not included in the repository metadata.
-
-*SOLVABLE_CHANGELOG "solvable:changelog"*::
-  The array containing all the changelog structures.
-
-*SOLVABLE_CHANGELOG_AUTHOR "solvable:changelog:author"*::
-  The author of a changelog entry.
-
-*SOLVABLE_CHANGELOG_TIME "solvable:changelog:time"*::
-  The seconds since the unix epoch when the changelog entry was written.
-
-*SOLVABLE_CHANGELOG_TEXT "solvable:changelog:text"*::
-  The text of a changelog entry.
-
-
-Special Solvable Attributes
----------------------------
-*RPM_RPMDBID "rpm:dbid"*::
-  The rpm database id of this (installed) package. Usually a small
-  integer number.
-
-*SOLVABLE_PATCHCATEGORY "solvable:patchcategory"*::
-  The category field for patch solvables. Should be named
-  ``update:category'' instead.
-
-*UPDATE_REBOOT "update:reboot"*::
-  If this attribute is present the system should be rebooted after
-  the update is installed.
-
-*UPDATE_RESTART "update:restart"*::
-  If this attribute is present the software manager should be run
-  again after the update is installed.  
-
-*UPDATE_RELOGIN "update:relogin"*::
-  If this attribute is present the user should log off and on again
-  after the update is installed.
-
-*UPDATE_MESSAGE "update:message"*::
-  A message that should be shown to the user to warn him about anything
-  non-standard.
-
-*UPDATE_SEVERITY "update:severity"*::
-  The severity of the update.
-
-*UPDATE_RIGHTS "update:rights"*::
-  Any legal or other rights of the update.
-
-*UPDATE_COLLECTION "update:collection"*::
-  The array containing the package list of the update.
-  
-*UPDATE_COLLECTION_NAME "update:collection:name"*::
-  The name of the updated package.
-
-*UPDATE_COLLECTION_EVR "update:collection:evr"*::
-  The version of the updated package.
-
-*UPDATE_COLLECTION_ARCH "update:collection:arch"*::
-  The architecture of the updated package.
-
-*UPDATE_COLLECTION_FILENAME "update:collection:filename"*::
-  The file name of the updated package.
-
-*UPDATE_REFERENCE "update:reference"*::
-  The array containing the reference list of the update.
-
-*UPDATE_REFERENCE_TYPE "update:reference:type"*::
-  The type of the reference, e.g. bugzilla.
-
-*UPDATE_REFERENCE_HREF "update:reference:href"*::
-  The URL of the reference.
-
-*UPDATE_REFERENCE_ID "update:reference:id"*::
-  The identification string of the reference, e.g. the bug number.
-
-*UPDATE_REFERENCE_TITLE "update:reference:title"*::
-  The title of the reference, e.g. the bug summary.
-
-*PRODUCT_REFERENCEFILE "product:referencefile"*::
-  The basename of the product file in the package.
-
-*PRODUCT_SHORTLABEL "product:shortlabel"*::
-  An identification string of the product.
-
-*PRODUCT_DISTPRODUCT "product:distproduct"*::
-  Obsolete, do not use. Was a SUSE Code-10 product name.
-
-*PRODUCT_DISTVERSION "product:distversion"*::
-  Obsolete, do not use. Was a SUSE Code-10 product version.
-
-*PRODUCT_TYPE "product:type"*::
-  The type of the product, e.g. ``base''.
-
-*PRODUCT_URL "product:url"*::
-  An array of product URLs.
-
-*PRODUCT_URL_TYPE "product:url:type"*::
-  An array of product URL types.
-
-*PRODUCT_FLAGS "product:flags"*::
-  An array of product flags.
-
-*PRODUCT_PRODUCTLINE "product:productline"*::
-  A product line string used for product registering.
-
-*PRODUCT_REGISTER_TARGET "product:regtarget"*::
-  A target for product registering.
-
-*PRODUCT_REGISTER_RELEASE "product:regrelease"*::
-  A release string for product registering.
-
-*PUBKEY_KEYID "pubkey:keyid"*::
-  The keyid of a pubkey, consisting of 8 bytes in hex.
-
-*PUBKEY_FINGERPRINT "pubkey:fingerprint"*::
-  The fingerprint of a pubkey, usually a sha1sum in hex. Old V3 RSA keys
-  use a md5sum instead.
-
-*PUBKEY_EXPIRES "pubkey:expires"*::
-  The seconds since the unix epoch when the pubkey expires.
-
-*PUBKEY_SUBKEYOF "pubkey:subkeyof"*::
-  The keyid of the master pubkey for subkeys.
-
-*PUBKEY_DATA "pubkey:data"*::
-  The MPI data of the pubkey.
-
-*SOLVABLE_ISVISIBLE "solvable:isvisible"*::
-  An attribute describing if the package should be listed to the user
-  or not. Used for SUSE patterns.
-
-*SOLVABLE_CATEGORY "solvable:category"*::
-  The category of a pattern.
-
-*SOLVABLE_INCLUDES "solvable:includes"*::
-  A list of other patterns that this pattern includes.
-
-*SOLVABLE_EXTENDS "solvable:extends"*::
-  A list of other patterns that this pattern extends.
-
-*SOLVABLE_ICON "solvable:icon"*::
-  The icon name of a pattern.
-
-*SOLVABLE_ORDER "solvable:order"*::
-  An ordering clue of a pattern.
-
-*SUSETAGS_SHARE_NAME "susetags:share:name"*::
-  Internal attribute to implement susetags shared records. Holds the
-  name of the solvable used for sharing attributes.
-
-*SUSETAGS_SHARE_EVR "susetags:share:evr"*::
-  Internal attribute to implement susetags shared records. Holds the
-  version of the solvable used for sharing attributes.
-
-*SUSETAGS_SHARE_ARCH "susetags:share:arch"*::
-  Internal attribute to implement susetags shared records. Holds the
-  architecture of the solvable used for sharing attributes.
-
-
-Solvable Architectures
-----------------------
-Predefined architecture values for commonly used architectures.
-
-*ARCH_SRC "src"*::
-  Used for binary packages that contain the package sources.
-
-*ARCH_NOSRC "nosrc"*::
-  Used for binary packages that contain some of the package sources,
-  but not all files (because of restrictions).
-
-*ARCH_NOARCH "noarch"*::
-  This package can be installed on any architecture. Used for rpm.
-
-*ARCH_ALL "all"*::
-  This package can be installed on any architecture. Used for Debian.
-
-*ARCH_ANY "any"*::
-  This package can be installed on any architecture. Used for Archlinux
-  and Haiku.
-
-
-Dependency Ids
---------------
-Namespaces are special modifiers that change the meaning of a dependency.
-Namespace dependencies are created with the REL_NAMESPACE flag. To make
-custom namespaces work you have to implement a namespace callback function.
-
-The dependency markers partition the dependency array in two parts with
-different semantics.
-
-*NAMESPACE_MODALIAS "namespace:modalias"*::
-  The dependency is a special modalias dependency that matches installed
-  hardware.
-
-*NAMESPACE_SPLITPROVIDES "namespace:splitprovides"*::
-  The dependency is a special splitprovides dependency used to implement
-  updates that include a package split. A splitprovides dependency contains
-  a filename and a package name, it is matched if a package with the
-  provided package name is installed that contains the filename.
-  This namespace is implemented in libsolv, so you do not need a callback.
-
-*NAMESPACE_LANGUAGE "namespace:language"*::
-  The dependency describes a language. The callback should return true
-  if the language was selected by the user.
-
-*NAMESPACE_FILESYSTEM "namespace:filesystem"*::
-  The dependency describes a filesystem. The callback should return true
-  if the filesystem is needed.
-
-*NAMESPACE_OTHERPROVIDERS "namespace:otherproviders"*::
-  This is a hack to allow self-conflicting packages. It is not needed
-  with current rpm version, so do not use this namespace.
-
-*SOLVABLE_PREREQMARKER "solvable:prereqmarker"*::
-  This marker partitions the normal require dependencies from the
-  prerequires. It is not needed for dependency solving, but it is
-  used by the transaction ordering algorithm when a dependency cycle
-  needs to be broken (non-prereq deps get broken first).
-
-*SOLVABLE_FILEMARKER "solvable:filemarker"*::
-  This marker partitions the package provides dependencies from the
-  synthetic file provides dependencies added by pool_addfileprovides().
-
-
-Data Types
-----------
-Each attribute data is stored with a type, so that the lookup functions
-know how to interpret the data. The following types are available:
-*REPOKEY_TYPE_VOID "repokey:type:void"*::
-  No data is stored with this attribute. Thus you can only test if
-  the attribute exists or not. Useful to store boolean values.
-
-*REPOKEY_TYPE_CONSTANT "repokey:type:constant"*::
-  The data is a constant 32bit number. The number is stored in the key
-  area, so using it does not cost extra storage space (but you need the
-  extra key space).
-
-*REPOKEY_TYPE_CONSTANTID "repokey:type:constantid"*::
-  The data is a constant Id. The Id is stored in the key area,
-  so using it does not cost extra storage space (but you need the
-  extra key space).
-
-*REPOKEY_TYPE_ID "repokey:type:id"*::
-  The data is an Id.
-
-*REPOKEY_TYPE_NUM "repokey:type:num"*::
-  The data is an unsigned 64bit number.
-
-*REPOKEY_TYPE_U32 "repokey:type:num32"*::
-  The data is an unsigned 32bit number. Obsolete, do not use.
-
-*REPOKEY_TYPE_DIR "repokey:type:dir"*::
-  The data is an Id of a directory.
-
-*REPOKEY_TYPE_STR "repokey:type:str"*::
-  The data is a regular string.
-
-*REPOKEY_TYPE_BINARY "repokey:type:binary"*::
-  The data is a binary blob.
-
-*REPOKEY_TYPE_IDARRAY "repokey:type:idarray"*::
-  The data is an array of non-zero Ids.
-
-*REPOKEY_TYPE_REL_IDARRAY "repokey:type:relidarray"*::
-  The data is an array of non-zero Ids ordered so that it needs less
-  space.
-
-*REPOKEY_TYPE_DIRSTRARRAY "repokey:type:dirstrarray"*::
-  The data is a tuple consisting of a directory Id and a basename.
-  Used to store file names.
-
-*REPOKEY_TYPE_DIRNUMNUMARRAY "repokey:type:dirnumnumarray"*::
-  The data is a triple consisting of a directory Id and two 32bit
-  unsigned integers. Used to store disk usage information.
-
-*REPOKEY_TYPE_MD5 "repokey:type:md5"*::
-  The data is a binary md5sum.
-
-*REPOKEY_TYPE_SHA1 "repokey:type:sha1"*::
-  The data is a binary sha1sum.
-
-*REPOKEY_TYPE_SHA256 "repokey:type:sha256"*::
-  The data is a binary sha256sum.
-
-*REPOKEY_TYPE_FIXARRAY "repokey:type:fixarray"*::
-  The data is an array of structures that have all the same layout
-  (i.e. the same keynames and keytypes in the same order).
-
-*REPOKEY_TYPE_FLEXARRAY "repokey:type:flexarray"*::
-  The data is an array of structures that have a different layout.
-
-*REPOKEY_TYPE_DELETED "repokey:type:deleted"*::
-  The data does not exist. Used to mark an attribute that was deleted.
-
-
-Repository Metadata
--------------------
-This attributes contain meta information about the repository.
-
-*REPOSITORY_SOLVABLES "repository:solvables"*::
-  This attribute holds the array including all of the solvables. It is
-  only used in the on-disk solv files, internally the solvables are
-  stored in the pool's solvable array for fast access.
-
-*REPOSITORY_DELTAINFO "repository:deltainfo"*::
-  This attribute holds the array including all of the delta packages.
-
-*REPOSITORY_EXTERNAL "repository:external"*::
-  This attribute holds the array including all of the data to construct
-  stub repodata areas to support on-demand loading of metadata.
-
-*REPOSITORY_KEYS "repository:keys"*::
-  This should really be named "repository:external:keys", it contains an
-  array if Ids that consists of (keyname, keytype) pairs that describe the
-  keys of the stub.
-
-*REPOSITORY_LOCATION "repository:location"*::
-  This is used to provide a file name in the stub.
-
-*REPOSITORY_ADDEDFILEPROVIDES "repository:addedfileprovides"*::
-  This attribute holds an array of filename Ids, that tell the library,
-  that all of the Ids were already added to the solvable provides.
-
-*REPOSITORY_RPMDBCOOKIE "repository:rpmdbcookie"*::
-  An attribute that stores a sha256sum over the file stats of the
-  Packages database. It's used to detect rebuilds of the database,
-  as in that case the database Ids of every package are newly
-  distributed.
-
-*REPOSITORY_TIMESTAMP "repository:timestamp"*::
-  The seconds since the unix epoch when the repository was created.
-
-*REPOSITORY_EXPIRE "repository:expire"*::
-  The seconds after the timestamp when the repository will expire.
-
-*REPOSITORY_UPDATES "repository:updates"*::
-  An array of structures describing what this repository updates.
-
-*REPOSITORY_DISTROS "repository:distros"*::
-  Also an array of structures describing what this repository updates.
-  Seems to be the newer name of REPOSITORY_UPDATES.
-
-*REPOSITORY_PRODUCT_LABEL "repository:product:label"*::
-  Should really be called "repository:updates:label". What distribution
-  is updated with this repository.
-
-*REPOSITORY_PRODUCT_CPEID "repository:product:cpeid"*::
-  The cpeid of the platform updated by this repository. Is both used
-  in REPOSITORY_UPDATES and REPOSITORY_DISTROS to maximize confusion.
-
-*REPOSITORY_REPOID "repository:repoid"*::
-  An array of Id strings describing keywords/tags about the repository
-  itself.
-
-*REPOSITORY_KEYWORDS "repository:keywords"*::
-  An array of Id strings describing keywords/tags about the content of
-  the repository.
-
-*REPOSITORY_REVISION "repository:revision"*::
-  An arbitrary string describing the revision of the repository.
-
-*REPOSITORY_TOOLVERSION "repository:toolversion"*::
-  Some string describing somewhat the version of libsolv used to create
-  the solv file.
-
-
-Repository Metadata for Susetags Repos
---------------------------------------
-Attributes describing repository files in a susetags repository.
-*SUSETAGS_DATADIR "susetags:datadir"*::
-  The directory that contains the packages.
-
-*SUSETAGS_DESCRDIR "susetags:descrdir"*::
-  The directory that contains the repository file resources.
-
-*SUSETAGS_DEFAULTVENDOR "susetags:defaultvendor"*::
-  The default vendor used when a package does not specify a vendor.
-
-*SUSETAGS_FILE "susetags:file"*::
-  An array of file resources of the repository.
-
-*SUSETAGS_FILE_NAME "susetags:file:name"*::
-  The filename of the resource.
-
-*SUSETAGS_FILE_TYPE "susetags:file:type"*::
-  The type of the resource, e.g. ``META''.
-
-*SUSETAGS_FILE_CHECKSUM "susetags:file:checksum"*::
-  The file checksum of the resource.
-
-
-Repository Metadata for RpmMD Repos
------------------------------------
-*REPOSITORY_REPOMD "repository:repomd"*::
-  An array of file resources of the repository.
-
-*REPOSITORY_REPOMD_TYPE "repository:repomd:type"*::
-  The type of the resource, e.g. ``primary''.
-
-*REPOSITORY_REPOMD_LOCATION "repository:repomd:location"*::
-  The location (aka filename) of the resource
-
-*REPOSITORY_REPOMD_TIMESTAMP "repository:repomd:timestamp"*::
-  The seconds since the unix epoch when the resource was created.
-
-*REPOSITORY_REPOMD_CHECKSUM "repository:repomd:checksum"*::
-  The file checksum of the resource.
-
-*REPOSITORY_REPOMD_OPENCHECKSUM "repository:repomd:openchecksum"*::
-  The checksum over the uncompressed contents of the resource.
-
-*REPOSITORY_REPOMD_SIZE "repository:repomd:size"*::
-  The size of the resource file.
-
-
-Delta Package Attributes
-------------------------
-*DELTA_PACKAGE_NAME "delta:pkgname"*::
-  The target package name for the delta package. Applying the delta
-  will recreate the target package.
-
-*DELTA_PACKAGE_EVR "delta:pkgevr"*::
-  The version of the target package.
-
-*DELTA_PACKAGE_ARCH "delta:pkgarch"*::
-  The architecture of the target package.
-
-*DELTA_LOCATION_DIR "delta:locdir"*::
-  The directory in the repository that contains the delta package.
-
-*DELTA_LOCATION_NAME "delta:locname"*::
-  The first part of the file name of the delta package.
-
-*DELTA_LOCATION_EVR "delta:locevr"*::
-  The version part of the file name of the delta package.
-
-*DELTA_LOCATION_SUFFIX "delta:locsuffix"*::
-  The suffix part of the file name of the delta package.
-
-*DELTA_LOCATION_BASE "delta:locbase"*::
-  This attribute can be used to overwrite the repositories base url for
-  the delta.
-
-*DELTA_DOWNLOADSIZE "delta:downloadsize"*::
-  The size of the delta rpm file.
-
-*DELTA_CHECKSUM "delta:checksum"*::
-  The checksum of the delta rpm file.
-
-*DELTA_BASE_EVR "delta:baseevr"*::
-  The version of the package the delta was built against.
-
-*DELTA_SEQ_NAME "delta:seqname"*::
-  The first part of the delta sequence, the base package name.
-
-*DELTA_SEQ_EVR "delta:seqevr"*::
-  The evr part of the delta sequence, the base package evr. Identical
-  to the DELTA_BASE_EVR attribute.
-
-*DELTA_SEQ_NUM "delta:seqnum"*::
-  The last part of the delta sequence, the content selection string.
-
-
-Author
-------
-Michael Schroeder <mls@suse.de>
-
diff --git a/libsolv-0.6.15/doc/libsolv-history.3 b/libsolv-0.6.15/doc/libsolv-history.3
deleted file mode 100644 (file)
index 872cd4e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-'\" t
-.\"     Title: Libsolv-History
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "LIBSOLV\-HISTORY" "3" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-libsolv-history \- how the libsolv library came into existence
-.SH "HISTORY"
-.sp
-This project was started in May 2007 when the zypp folks decided to switch to a database to speed up installation\&. As I am not a big fan of databases, I (mls) wondered if there would be really some merit of using one for solving, as package dependencies of all packages have to be read in anyway\&.
-.sp
-Back in 2002, I researched that using a dictionary approach for storing dependencies can reduce the packages file to 1/3 of its size\&. Extending this idea a bit more, I decided to store all strings and relations as unique 32\-bit numbers\&. This has three big advantages:
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-because of the unification, testing whether two strings are equal is the same as testing the equality of two numbers, thus very fast
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-much space is saved, as numbers do not take up as much space as strings the internal memory representation does not take more space on a 64\-bit system where a pointer is twice the size of a 32\-bit number
-.RE
-.sp
-Thus, the solv format was created, which stores a repository as a string dictionary, a relation dictionary and then all packages dependencies\&. Tests showed that reading and merging multiple solv repositories takes just some milliseconds\&.
-.SS "Early solver experiments"
-.sp
-Having a new repository format was one big step, but the other area where libzypp needed improvement was the solver\&. Libzypp\(cqs solver was a port from the Red Carpet solver, which was written to update packages in an already installed system\&. Using it for the complete installation progress brought it to its limits\&. Also, the added extensions like support for weak dependencies and patches made it fragile and unpredictable\&.
-.sp
-As I was not very pleased with the way the solver worked, I looked at other solver algorithms\&. I checked smart, yum and apt, but could not find a convincing algorithm\&. My own experiments also were not very convincing, they worked fine for some problems but failed miserably for other corner cases\&.
-.SS "Using SAT for solving"
-.sp
-SUSE\(cqs hack week at the end of June 2007 turned out to be a turning point for the solver\&. Googling for solver algorithms, I stumbled over some note saying that some people are trying to use SAT algorithms to improve solving on Debian\&. Looking at the SAT entry in Wikipedia, it was easy to see that this indeed was the missing piece: SAT algorithms are well researched and there are quite some open source implementations\&. I decided to look at the minisat code, as it is one of the fastest solvers while consisting of too many lines of code\&.
-.sp
-Of course, directly using minisat would not work, as a package solver does not need to find just one correct solution, but it also has to optimize some metrics, i\&.e\&. keep as many packages installed as possible\&. Thus, I needed to write my own solver incorporation the ideas and algorithms used in minisat\&. This wasn\(cqt very hard, and at the end of the hack week the solver calculated the first right solutions\&.
-.SS "Selling it to libzypp"
-.sp
-With those encouraging results, I went to Klaus Kaempf, the system management architect at SUSE\&. We spoke about how to convince the team to make libzypp switch to the new solver\&. Fortunately, libzypp comes with a plethora of solver test cases, so we decided to make the solver pass most of the test cases first\&. Klaus wrote a "deptestomatic" implementation to check the test cases\&. Together with Stephan Kulow, who is responsible for the openSUSE distribution, we tweaked and extended the solver until most of the test cases looked good\&.
-.sp
-Duncan Mac\-Vicar Prett, the team lead of the YaST team, also joined development by creating Ruby bindings for the solver\&. Later, Klaus improved the bindings and ported them to some other languages\&.
-.SS "The attribute store"
-.sp
-The progress with the repository format and the solver attracted another hacker to the project: Michael Matz from the compiler team\&. He started with improving the repository parsers so that patches and content files also generate solvables\&. After that, he concentrated on storing all of the other metadata of the repositories that are not used for solving, like the package summaries and descriptions\&. At the end of October, a first version of this "attribute store" was checked in\&. Its design goals were:
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-space efficient storage of attributes
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-paging/on demand loading of data
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-page compression
-.RE
-.sp
-The first version of the attribute store used a different format for storing information, we later merged this format with the solv file format\&.
-.SS "libzypp integration"
-.sp
-Integration of the sat\-solver into libzypp also started in October 2007 by Stefan Schubert and Michael Andres from the YaST team\&. The first versions supported both the old solver and the new one by using the old repository read functions and converting the old package data in\-memory into a sat solver pool\&. Solvers could be switched with the environment variable ZYPP_SAT_SOLVER\&. The final decision to move to the new solver was made in January of 2008, first just by making the new solver the default one, later by completely throwing out the old solver code\&. This had the advantage that the internal solvable storage could also be done by using the solver pool, something Michael Matz already played with in a proof of concept implementation showing some drastic speed gains\&. The last traces of the old database code were removed in February\&.
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/libsolv-history.txt b/libsolv-0.6.15/doc/libsolv-history.txt
deleted file mode 100644 (file)
index da59fe5..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-Libsolv-History(3)
-==================
-:man manual: LIBSOLV
-:man source: libsolv
-
-Name
-----
-libsolv-history - how the libsolv library came into existence
-
-History
--------
-This project was started in May 2007 when the zypp folks decided to switch
-to a database to speed up installation. As I am not a big fan of databases,
-I (mls) wondered if there would be really some merit of using one for solving,
-as package dependencies of all packages have to be read in anyway.
-
-Back in 2002, I researched that using a dictionary approach for storing
-dependencies can reduce the packages file to 1/3 of its size. Extending
-this idea a bit more, I decided to store all strings and relations
-as unique 32-bit numbers. This has three big advantages:
-
-- because of the unification, testing whether two strings are equal is the
-  same as testing the equality of two numbers, thus very fast
-- much space is saved, as numbers do not take up as much space as strings
-  the internal memory representation does not take more space on a
-  64-bit system where a pointer is twice the size of a 32-bit number
-
-Thus, the solv format was created, which stores a repository as a string
-dictionary, a relation dictionary and then all packages dependencies.
-Tests showed that reading and merging multiple solv repositories takes
-just some milliseconds.
-
-=== Early solver experiments ===
-Having a new repository format was one big step, but the other area
-where libzypp needed improvement was the solver. Libzypp's solver was
-a port from the Red Carpet solver, which was written to update packages
-in an already installed system. Using it for the complete installation
-progress brought it to its limits. Also, the added extensions like
-support for weak dependencies and patches made it fragile and
-unpredictable.
-
-As I was not very pleased with the way the solver worked, I looked at
-other solver algorithms. I checked smart, yum and apt, but could not
-find a convincing algorithm. My own experiments also were not very
-convincing, they worked fine for some problems but failed miserably
-for other corner cases.
-
-=== Using SAT for solving ===
-SUSE's hack week at the end of June 2007 turned out to be a turning point
-for the solver. Googling for solver algorithms, I stumbled over some note
-saying that some people are trying to use SAT algorithms to improve
-solving on Debian. Looking at the SAT entry in Wikipedia, it was easy
-to see that this indeed was the missing piece: SAT algorithms are well
-researched and there are quite some open source implementations.
-I decided to look at the minisat code, as it is one of the fastest
-solvers while consisting of too many lines of code.
-
-Of course, directly using minisat would not work, as a package solver
-does not need to find just one correct solution, but it also has to
-optimize some metrics, i.e. keep as many packages installed as possible.
-Thus, I needed to write my own solver incorporation the ideas and
-algorithms used in minisat. This wasn't very hard, and at the end of
-the hack week the solver calculated the first right solutions.
-
-=== Selling it to libzypp ===
-With those encouraging results, I went to Klaus Kaempf, the system
-management architect at SUSE. We spoke about how to convince the
-team to make libzypp switch to the new solver. Fortunately, libzypp comes
-with a plethora of solver test cases, so we decided to make the solver pass
-most of the test cases first. Klaus wrote a "deptestomatic" implementation
-to check the test cases. Together with Stephan Kulow, who is responsible for the
-openSUSE distribution, we tweaked and extended the solver until most of
-the test cases looked good.
-
-Duncan Mac-Vicar Prett, the team lead of the YaST team, also joined
-development by creating Ruby bindings for the solver. Later, Klaus
-improved the bindings and ported them to some other languages.
-
-=== The attribute store ===
-The progress with the repository format and the solver attracted another
-hacker to the project: Michael Matz from the compiler team. He started
-with improving the repository parsers so that patches and content files
-also generate solvables. After that, he concentrated on storing all
-of the other metadata of the repositories that are not used for solving,
-like the package summaries and descriptions. At the end of October, a first
-version of this "attribute store" was checked in. Its design goals were:
-
-- space efficient storage of attributes
-- paging/on demand loading of data
-- page compression
-
-The first version of the attribute store used a different format for
-storing information, we later merged this format with the solv file
-format.
-
-=== libzypp integration ===
-Integration of the sat-solver into libzypp also started in October 2007 by
-Stefan Schubert and Michael Andres from the YaST team. The first
-versions supported both the old solver and the new one by using the
-old repository read functions and converting the old package data
-in-memory into a sat solver pool. Solvers could be switched with
-the environment variable ZYPP_SAT_SOLVER. The final decision to
-move to the new solver was made in January of 2008, first just by
-making the new solver the default one, later by completely throwing out
-the old solver code. This had the advantage that the internal solvable
-storage could also be done by using the solver pool, something Michael
-Matz already played with in a proof of concept implementation showing
-some drastic speed gains. The last traces of the old database code
-were removed in February.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/libsolv-pool.3 b/libsolv-0.6.15/doc/libsolv-pool.3
deleted file mode 100644 (file)
index 0929ba6..0000000
+++ /dev/null
@@ -1,1278 +0,0 @@
-'\" t
-.\"     Title: Libsolv-Pool
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 12/14/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "LIBSOLV\-POOL" "3" "12/14/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-libsolv-pool \- Libsolv\*(Aqs pool object
-.SH "PUBLIC ATTRIBUTES"
-.PP
-\fBvoid *appdata\fR
-.RS 4
-A no\-purpose pointer free to use for the library user\&. Freeing the pool simply discards the pointer\&.
-.RE
-.PP
-\fBStringpool ss\fR
-.RS 4
-The pool of unified strings\&.
-.RE
-.PP
-\fBReldep *rels\fR
-.RS 4
-The pool of unified relation dependencies\&.
-.RE
-.PP
-\fBint nrels\fR
-.RS 4
-Number of allocated relation dependencies\&.
-.RE
-.PP
-\fBRepo **repos\fR
-.RS 4
-The array of repository pointers, indexed by repository Id\&.
-.RE
-.PP
-\fBint nrepos\fR
-.RS 4
-Number of allocated repository array elements, i\&.e\&. the size of the repos array\&.
-.RE
-.PP
-\fBint urepos\fR
-.RS 4
-Number of used (i\&.e\&. non\-zero) repository array elements\&.
-.RE
-.PP
-\fBRepo *installed\fR
-.RS 4
-Pointer to the repo holding the installed packages\&. You are free to read this attribute, but you should use pool_set_installed() if you want to change it\&.
-.RE
-.PP
-\fBSolvable *solvables\fR
-.RS 4
-The array of Solvable objects\&.
-.RE
-.PP
-\fBint nsolvables\fR
-.RS 4
-Number of Solvable objects, i\&.e\&. the size of the solvables array\&. Note that the array may contain freed solvables, in that case the repo pointer of the solvable will be zero\&.
-.RE
-.PP
-\fBint disttype\fR
-.RS 4
-The distribution type of your system, e\&.g\&. DISTTYPE_DEB\&. You are free to read this attribute, but you should use pool_setdisttype() if you want to change it\&.
-.RE
-.PP
-\fBId *whatprovidesdata\fR
-.RS 4
-Multi\-purpose Id storage holding zero terminated arrays of Ids\&. pool_whatprovides() returns an offset into this data\&.
-.RE
-.PP
-\fBMap *considered\fR
-.RS 4
-Optional bitmap that can make the library ignore solvables\&. If a bitmap is set, only solvables that have a set bit in the bitmap at their Id are considered usable\&.
-.RE
-.PP
-\fBint debugmask\fR
-.RS 4
-A mask that defines which debug events should be reported\&. pool_setdebuglevel() sets this mask\&.
-.RE
-.PP
-\fBDatapos pos\fR
-.RS 4
-An object storing some position in the repository data\&. Functions like dataiterator_set_pos() set this object, accessing data with a pseudo solvable Id of SOLVID_POS uses it\&.
-.RE
-.PP
-\fBQueue pooljobs\fR
-.RS 4
-A queue where fixed solver jobs can be stored\&. This jobs are automatically added when solver_solve() is called, they are useful to store configuration data like which packages should be multiversion installed\&.
-.RE
-.SH "CREATION AND DESTRUCTION"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBPool *pool_create()\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a new instance of a pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_free(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Free a pool and all of the data it contains, e\&.g\&. the solvables, repositories, strings\&.
-.SH "DEBUGGING AND ERROR REPORTING"
-.SS "Constants"
-.PP
-\fBSOLV_FATAL\fR
-.RS 4
-Report the error and call \(lqexit(1)\(rq afterwards\&. You cannot mask this level\&. Reports to stderr instead of stdout\&.
-.RE
-.PP
-\fBSOLV_ERROR\fR
-.RS 4
-Used to report errors\&. Reports to stderr instead of stdout\&.
-.RE
-.PP
-\fBSOLV_WARN\fR
-.RS 4
-Used to report warnings\&.
-.RE
-.PP
-\fBSOLV_DEBUG_STATS\fR
-.RS 4
-Used to report statistical data\&.
-.RE
-.PP
-\fBSOLV_DEBUG_RULE_CREATION\fR
-.RS 4
-Used to report information about the solver\(cqs creation of rules\&.
-.RE
-.PP
-\fBSOLV_DEBUG_PROPAGATE\fR
-.RS 4
-Used to report information about the solver\(cqs unit rule propagation process\&.
-.RE
-.PP
-\fBSOLV_DEBUG_ANALYZE\fR
-.RS 4
-Used to report information about the solver\(cqs learnt rule generation mechanism\&.
-.RE
-.PP
-\fBSOLV_DEBUG_UNSOLVABLE\fR
-.RS 4
-Used to report information about the solver dealing with conflicting rules\&.
-.RE
-.PP
-\fBSOLV_DEBUG_SOLUTIONS\fR
-.RS 4
-Used to report information about the solver creating solutions to solve problems\&.
-.RE
-.PP
-\fBSOLV_DEBUG_POLICY\fR
-.RS 4
-Used to report information about the solver searching for an optimal solution\&.
-.RE
-.PP
-\fBSOLV_DEBUG_RESULT\fR
-.RS 4
-Used by the debug functions to output results\&.
-.RE
-.PP
-\fBSOLV_DEBUG_JOB\fR
-.RS 4
-Used to report information about the job rule generation process\&.
-.RE
-.PP
-\fBSOLV_DEBUG_SOLVER\fR
-.RS 4
-Used to report information about what the solver is currently doing\&.
-.RE
-.PP
-\fBSOLV_DEBUG_TRANSACTION\fR
-.RS 4
-Used to report information about the transaction generation and ordering process\&.
-.RE
-.PP
-\fBSOLV_DEBUG_TO_STDERR\fR
-.RS 4
-Write debug messages to stderr instead of stdout\&.
-.RE
-.SS "Functions"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_debug(Pool *\fR\fIpool\fR\fB, int\fR \fItype\fR\fB, const char *\fR\fIformat\fR\fB, \&.\&.\&.)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Report a message of the type \fItype\fR\&. You can filter debug messages by setting a debug mask\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setdebuglevel(Pool *\fR\fIpool\fR\fB, int\fR \fIlevel\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set a predefined debug mask\&. A higher level generally means more bits in the mask are set, thus more messages are printed\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setdebugmask(Pool *\fR\fIpool\fR\fB, int\fR \fImask\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the debug mask to filter debug messages\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_error(Pool *\fR\fIpool\fR\fB, int\fR \fIret\fR\fB, const char *\fR\fIformat\fR\fB, \&.\&.\&.)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the pool\(cqs error string\&. The \fIret\fR value is simply used as a return value of the function so that you can write code like return pool_error(\&...);\&. If the debug mask contains the \fBSOLV_ERROR\fR bit, pool_debug() is also called with the message and type \fBSOLV_ERROR\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBextern char *pool_errstr(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the current error string stored in the pool\&. Like with the libc\(cqs errno value, the string is only meaningful after a function returned an error\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setdebugcallback(Pool *\fR\fIpool\fR\fB, void (*\fR\fIdebugcallback\fR\fB)(Pool *, void *\fR\fIdata\fR\fB, int\fR \fItype\fR\fB, const char *\fR\fIstr\fR\fB), void *\fR\fIdebugcallbackdata\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set a custom debug callback function\&. Instead of writing to stdout or stderr, the callback function will be called\&.
-.SH "POOL CONFIGURATION"
-.SS "Constants"
-.PP
-\fBDISTTYPE_RPM\fR
-.RS 4
-Used for systems which use rpm as low level package manager\&.
-.RE
-.PP
-\fBDISTTYPE_DEB\fR
-.RS 4
-Used for systems which use dpkg as low level package manager\&.
-.RE
-.PP
-\fBDISTTYPE_ARCH\fR
-.RS 4
-Used for systems which use the arch linux package manager\&.
-.RE
-.PP
-\fBDISTTYPE_HAIKU\fR
-.RS 4
-Used for systems which use haiku packages\&.
-.RE
-.PP
-\fBPOOL_FLAG_PROMOTEEPOCH\fR
-.RS 4
-Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch\&. Used at some time in old rpm versions, modern systems should never need this\&.
-.RE
-.PP
-\fBPOOL_FLAG_FORBIDSELFCONFLICTS\fR
-.RS 4
-Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them recently\&.
-.RE
-.PP
-\fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR
-.RS 4
-Make obsolete type dependency match against provides instead of just the name and version of packages\&. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version\&.
-.RE
-.PP
-\fBPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES\fR
-.RS 4
-An implicit obsoletes is the internal mechanism to remove the old package on an update\&. The default is to remove all packages with the same name, rpm\-5 switched to also removing packages providing the same name\&.
-.RE
-.PP
-\fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR
-.RS 4
-Rpm\(cqs multilib implementation (used in RedHat and Fedora) distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&.
-.RE
-.PP
-\fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR
-.RS 4
-Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel\&. For current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled)\&.
-.RE
-.PP
-\fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR
-.RS 4
-New versions of rpm consider the obsoletes of installed packages when checking for dependency, thus you may not install a package that is obsoleted by some other installed package, unless you also erase the other package\&.
-.RE
-.PP
-\fBPOOL_FLAG_HAVEDISTEPOCH\fR
-.RS 4
-Mandriva added a new field called distepoch that gets checked in version comparison if the epoch/version/release of two packages are the same\&.
-.RE
-.PP
-\fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR
-.RS 4
-If a package is installed in multiversionmode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&.
-.RE
-.PP
-\fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR
-.RS 4
-Make the addfileprovides method only add files from the standard locations (i\&.e\&. the \(lqbin\(rq and \(lqetc\(rq directories)\&. This is useful if you have only few packages that use non\-standard file dependencies, but you still want the fast speed that addfileprovides() generates\&.
-.RE
-.SS "Functions"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_setdisttype(Pool *\fR\fIpool\fR\fB, int\fR \fIdisttype\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the package type of your system\&. The disttype is used for example to define package comparison semantics\&. Libsolv\(cqs default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems\&. The Function returns the old disttype on success, and \-1 if the new disttype is not supported\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_set_flag(Pool *\fR\fIpool\fR\fB, int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set a flag to a new value\&. Returns the old value of the flag\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_get_flag(Pool *\fR\fIpool\fR\fB, int\fR \fIflag\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Get the value of a pool flag\&. See the constants section about the meaning of the flags\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_set_rootdir(Pool *\fR\fIpool\fR\fB, const char *\fR\fIrootdir\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set a specific root directory\&. Some library functions support a flag that tells the function to prepend the rootdir to file and directory names\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_get_rootdir(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the current value of the root directory\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *pool_prepend_rootdir(Pool *\fR\fIpool\fR\fB, const char *\fR\fIdir\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Prepend the root directory to the \fIdir\fR argument string\&. The returned string has been newly allocated and needs to be freed after use\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *pool_prepend_rootdir_tmp(Pool *\fR\fIpool\fR\fB, const char *\fR\fIdir\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as pool_prepend_rootdir, but uses the pool\(cqs temporary space for allocation\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_set_installed(Pool *\fR\fIpool\fR\fB, Repo *\fR\fIrepo\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set which repository should be treated as the \(lqinstalled\(rq repository, i\&.e\&. the one that holds information about the installed packages\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_set_languages(Pool *\fR\fIpool\fR\fB, const char **\fR\fIlanguages\fR\fB, int\fR \fInlanguages\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the language of your system\&. The library provides lookup functions that return localized strings, for example for package descriptions\&. You can set an array of languages to provide a fallback mechanism if one language is not available\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setarch(Pool *\fR\fIpool\fR\fB, const char *\fR\fIarch\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the architecture of your system\&. The architecture is used to determine which packages are installable and which packages cannot be installed\&. The \fIarch\fR argument is normally the \(lqmachine\(rq value of the \(lquname\(rq system call\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setarchpolicy(Pool *, const char *)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set the architecture policy for your system\&. This is the general version of pool_setarch (in fact pool_setarch calls pool_setarchpolicy internally)\&. See the section about architecture policies for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_addvendorclass(Pool *\fR\fIpool\fR\fB, const char **\fR\fIvendorclass\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a new vendor equivalence class to the system\&. A vendor equivalence class defines if an installed package of one vendor can be replaced by a package coming from a different vendor\&. The \fIvendorclass\fR argument must be a NULL terminated array of strings\&. See the section about vendor policies for more information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setvendorclasses(Pool *\fR\fIpool\fR\fB, const char **\fR\fIvendorclasses\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Set all allowed vendor equivalences\&. The vendorclasses argument must be an NULL terminated array consisting of all allowed classes concatenated\&. Each class itself must be NULL terminated, thus the last class ends with two NULL elements, one to finish the class and one to finish the list of classes\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_set_custom_vendorcheck(Pool *\fR\fIpool\fR\fB, int (*\fR\fIvendorcheck\fR\fB)(Pool *, Solvable *, Solvable *))\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Define a custom vendor check mechanism\&. You can use this if libsolv\(cqs internal vendor equivalence class mechanism does not match your needs\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setloadcallback(Pool *\fR\fIpool\fR\fB, int (*\fR\fIcb\fR\fB)(Pool *, Repodata *, void *), void *\fR\fIloadcbdata\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Define a callback function that gets called when repository metadata needs to be loaded on demand\&. See the section about on demand loading in the libsolv\-repodata manual\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_setnamespacecallback(Pool *\fR\fIpool\fR\fB, Id (*\fR\fIcb\fR\fB)(Pool *, void *,\fR \fIId\fR\fB,\fR \fIId\fR\fB), void *\fR\fInscbdata\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Define a callback function to implement custom namespace support\&. See the section about namespace dependencies\&.
-.SH "ID POOL MANAGEMENT"
-.SS "Constants"
-.PP
-\fBID_EMPTY\fR
-.RS 4
-The Id of the empty string, it is always Id 1\&.
-.RE
-.PP
-\fBREL_LT\fR
-.RS 4
-Represents a \(lq<\(rq relation\&.
-.RE
-.PP
-\fBREL_EQ\fR
-.RS 4
-Represents a \(lq=\(rq relation\&.
-.RE
-.PP
-\fBREL_GT\fR
-.RS 4
-Represents a \(lq>\(rq relation\&. You can use combinations of REL_GT, REL_EQ, and REL_LT or\-ed together to create any relation you like\&.
-.RE
-.PP
-\fBREL_AND\fR
-.RS 4
-A boolean AND operation, the \(lqname\(rq and \(lqevr\(rq parts of the relation can be two sub\-dependencies\&. Packages must match both parts of the dependency\&.
-.RE
-.PP
-\fBREL_OR\fR
-.RS 4
-A boolean OR operation, the \(lqname\(rq and \(lqevr\(rq parts of the relation can be two sub\-dependencies\&. Packages can match any part of the dependency\&.
-.RE
-.PP
-\fBREL_WITH\fR
-.RS 4
-Like REL_AND, but packages must match both dependencies simultaneously\&. See the section about boolean dependencies about more information\&.
-.RE
-.PP
-\fBREL_NAMESPACE\fR
-.RS 4
-A special namespace relation\&. See the section about namespace dependencies for more information\&.
-.RE
-.PP
-\fBREL_ARCH\fR
-.RS 4
-An architecture filter dependency\&. The \(lqname\(rq part of the relation is a sub\-dependency, the \(lqevr\(rq part is the Id of an architecture that the matching packages must have (note that this is an exact match ignoring architecture policies)\&.
-.RE
-.PP
-\fBREL_FILECONFLICT\fR
-.RS 4
-An internal file conflict dependency used to represent file conflicts\&. See the pool_add_fileconflicts_deps() function\&.
-.RE
-.PP
-\fBREL_COND\fR
-.RS 4
-A conditional dependency, the \(lqname\(rq sub\-dependency is only considered if the \(lqevr\(rq sub\-dependency is fulfilled\&. See the section about boolean dependencies about more information\&.
-.RE
-.PP
-\fBREL_COMPAT\fR
-.RS 4
-A compat dependency used in Haiku to represent version ranges\&. The \(lqname\(rq part is the actual version, the \(lqevr\(rq part is the backwards compatibility version\&.
-.RE
-.SS "Functions"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_str2id(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr\fR\fB, int\fR \fIcreate\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add a string to the pool of unified strings, returning the Id of the string\&. If \fIcreate\fR is zero, new strings will not be added to the pool, instead Id 0 is returned\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_strn2id(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr\fR\fB, unsigned int\fR \fIlen\fR\fB, int\fR \fIcreate\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as pool_str2id, but only \fIlen\fR characters of the string are used\&. This can be used to add substrings to the pool\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_rel2id(Pool *\fR\fIpool\fR\fB, Id\fR \fIname\fR\fB, Id\fR \fIevr\fR\fB, int\fR \fIflags\fR\fB, int\fR \fIcreate\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create a relational dependency from to other dependencies, \fIname\fR and \fIevr\fR, and a \fIflag\fR\&. See the \fBREL_\fR constants for the supported flags\&. As with pool_str2id, \fIcreate\fR defines if new dependencies will get added or Id zero will be returned instead\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_id2langid(Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB, const char *\fR\fIlang\fR\fB, int\fR \fIcreate\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Attach a language suffix to a string Id\&. This function can be used to create language keyname Ids from keynames, it is functional equivalent to converting the \fIid\fR argument to a string, adding a \(lq:\(rq character and the \fIlang\fR argument to the string and then converting the result back into an Id\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_id2str(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert an Id back into a string\&. If the Id is a relational Id, the \(lqname\(rq part will be converted instead\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_id2rel(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the relation string of a relational Id\&. Returns an empty string if the passed Id is not a relation\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_id2evr(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the \(lqevr\(rq part of a relational Id as string\&. Returns an empty string if the passed Id is not a relation\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_dep2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert an Id back into a string\&. If the passed Id belongs to a relation, a string representing the relation is returned\&. Note that in that case the string is allocated on the pool\(cqs temporary space\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_freeidhashes(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Free the hashes used to unify strings and relations\&. You can use this function to save memory if you know that you will no longer create new strings and relations\&.
-.SH "SOLVABLE FUNCTIONS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBSolvable *pool_id2solvable(const Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a solvable Id into a pointer to the solvable data\&. Note that the pointer may become invalid if new solvables are created or old solvables deleted, because the array storing all solvables may get reallocated\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_solvid2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a string representing the solvable with the Id \fIp\fR\&. The string will be some canonical representation of the solvable, usually a combination of the name, the version, and the architecture\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_solvable2str(Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as pool_solvid2str, but instead of the Id, a pointer to the solvable is passed\&.
-.SH "DEPENDENCY MATCHING"
-.SS "Constants"
-.PP
-\fBEVRCMP_COMPARE\fR
-.RS 4
-Compare all parts of the version, treat missing parts as empty strings\&.
-.RE
-.PP
-\fBEVRCMP_MATCH_RELEASE\fR
-.RS 4
-A special mode for rpm version string matching\&. If a version misses a release part, it matches all releases\&. In that case the special values \(lq\-2\(rq and \(lq2\(rq are returned, depending on which of the two versions did not have a release part\&.
-.RE
-.PP
-\fBEVRCMP_MATCH\fR
-.RS 4
-A generic match, missing parts always match\&.
-.RE
-.PP
-\fBEVRCMP_COMPARE_EVONLY\fR
-.RS 4
-Only compare the epoch and the version parts, ignore the release part\&.
-.RE
-.SS "Functions"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_evrcmp(const Pool *\fR\fIpool\fR\fB, Id\fR \fIevr1id\fR\fB, Id\fR \fIevr2id\fR\fB, int\fR \fImode\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Compare two version Ids, return \-1 if the first version is less than the second version, 0 if they are identical, and 1 if the first version is bigger than the second one\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_evrcmp_str(const Pool *\fR\fIpool\fR\fB, const char *\fR\fIevr1\fR\fB, const char *\fR\fIevr2\fR\fB, int\fR \fImode\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as pool_evrcmp(), but uses strings instead of Ids\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_evrmatch(const Pool *\fR\fIpool\fR\fB, Id\fR \fIevrid\fR\fB, const char *\fR\fIepoch\fR\fB, const char *\fR\fIversion\fR\fB, const char *\fR\fIrelease\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Match a version Id against an epoch, a version and a release string\&. Passing NULL means that the part should match everything\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_match_dep(Pool *\fR\fIpool\fR\fB, Id\fR \fId1\fR\fB, Id\fR \fId2\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Returns \(lq1\(rq if the dependency \fId1\fR (the provider) is matched by the dependency \fId2\fR, otherwise \(lq0\(rq is returned\&. For two dependencies to match, both the \(lqname\(rq parts must match and the version range described by the \(lqevr\(rq parts must overlap\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_match_nevr(Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB, Id\fR \fId\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Like pool_match_dep, but the provider is the "self\-provides" dependency of the Solvable \fIs\fR, i\&.e\&. the dependency \(lqs→name = s→evr\(rq\&.
-.SH "WHATPROVIDES INDEX"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_createwhatprovides(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Create an index that maps dependency Ids to sets of packages that provide the dependency\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_freewhatprovides(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Free the whatprovides index to save memory\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_whatprovides(Pool *\fR\fIpool\fR\fB, Id\fR \fId\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return an offset into the Pool\(cqs whatprovidesdata array\&. The solvables with the Ids stored starting at that offset provide the dependency \fId\fR\&. The solvable list is zero terminated\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId *pool_whatprovides_ptr(Pool *\fR\fIpool\fR\fB, Id\fR \fId\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Instead of returning the offset, return the pointer to the Ids stored at that offset\&. Note that this pointer has a very limit validity time, as any call that adds new values to the whatprovidesdata area may reallocate the array\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_queuetowhatprovides(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIq\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Add the contents of the Queue \fIq\fR to the end of the whatprovidesdata array, returning the offset into the array\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_addfileprovides(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Some package managers like rpm allow dependencies on files contained in other packages\&. To allow libsolv to deal with those dependencies in an efficient way, you need to call the addfileprovides method after creating and reading all repositories\&. This method will scan all dependency for file names and then scan all packages for matching files\&. If a filename has been matched, it will be added to the provides list of the corresponding package\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_addfileprovides_queue(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIidq\fR\fB, Queue *\fR\fIidqinst\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Same as pool_addfileprovides, but the added Ids are returned in two Queues, \fIidq\fR for all repositories except the one containing the \(lqinstalled\(rq packages, \fIidqinst\fR for the latter one\&. This information can be stored in the meta section of the repositories to speed up the next time the repository is loaded and addfileprovides is called
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_flush_namespaceproviders(Pool *\fR\fIpool\fR\fB, Id\fR \fIns\fR\fB, Id\fR \fIevr\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Clear the cache of the providers for namespace dependencies matching namespace \fIns\fR\&. If the \fIevr\fR argument is non\-zero, the namespace dependency for exactly that dependency is cleared, otherwise all matching namespace dependencies are cleared\&. See the section about Namespace dependencies for further information\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_add_fileconflicts_deps(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIconflicts\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Some package managers like rpm report conflicts when a package installation overwrites a file of another installed package with different content\&. As file content information is not stored in the repository metadata, those conflicts can only be detected after the packages are downloaded\&. Libsolv provides a function to check for such conflicts, pool_findfileconflicts()\&. If conflicts are found, they can be added as special \fBREL_FILECONFLICT\fR provides dependencies, so that the solver will know about the conflict when it is re\-run\&.
-.SH "UTILITY FUNCTIONS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *pool_alloctmpspace(Pool *\fR\fIpool\fR\fB, int\fR \fIlen\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Allocate space on the pool\(cqs temporary space area\&. This space has a limited lifetime, it will be automatically freed after a fixed amount (currently 16) of other pool_alloctmpspace() calls are done\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_freetmpspace(Pool *\fR\fIpool\fR\fB, const char *\fR\fIspace\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Give the space allocated with pool_alloctmpspace back to the system\&. You do not have to use this function, as the space is automatically reclaimed, but it can be useful to extend the lifetime of other pointers to the pool\(cqs temporary space area\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_bin2hex(Pool *\fR\fIpool\fR\fB, const unsigned char *\fR\fIbuf\fR\fB, int\fR \fIlen\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert some binary data to hexadecimal, returning a string allocated in the pool\(cqs temporary space area\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *pool_tmpjoin(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr1\fR\fB, const char *\fR\fIstr2\fR\fB, const char *\fR\fIstr3\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Join three strings and return the result in the pool\(cqs temporary space area\&. You can use NULL arguments if you just want to join less strings\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBchar *pool_tmpappend(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr1\fR\fB, const char *\fR\fIstr2\fR\fB, const char *\fR\fIstr3\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Like pool_tmpjoin(), but if the first argument is the last allocated space in the pool\(cqs temporary space area, it will be replaced with the result of the join and no new temporary space slot will be used\&. Thus you can join more than three strings by a combination of one pool_tmpjoin() and multiple pool_tmpappend() calls\&. Note that the \fIstr1\fR pointer is no longer usable after the call\&.
-.SH "DATA LOOKUP"
-.SS "Constants"
-.PP
-\fBSOLVID_POS\fR
-.RS 4
-Use the data position stored in the pool for the lookup instead of looking up the data of a solvable\&.
-.RE
-.PP
-\fBSOLVID_META\fR
-.RS 4
-Use the data stored in the meta section of a repository (or repodata area) instead of looking up the data of a solvable\&. This constant does not work for the pool\(cqs lookup functions, use it for the repo\(cqs or repodata\(cqs lookup functions instead\&. It\(cqs just listed for completeness\&.
-.RE
-.SS "Functions"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_lookup_str(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the string value stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBunsigned long long pool_lookup_num(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the 64bit unsigned number stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. If no such number is found, the value of the \fInotfound\fR argument is returned instead\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBId pool_lookup_id(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the Id stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_lookup_idarray(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Queue *\fR\fIq\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Fill the queue \fIq\fR with the content of the Id array stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. Returns \(lq1\(rq if an array was found, otherwise the queue will be empty and \(lq0\(rq will be returned\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_lookup_void(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Returns \(lq1\(rq if a void value is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR, otherwise \(lq0\(rq\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_lookup_checksum(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id *\fR\fItypep\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the checksum that is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. The type of the checksum will be returned over the \fItypep\fR pointer\&. If no such checksum is found, NULL will be returned and the type will be set to zero\&. Note that the result is stored in the Pool\(cqs temporary space area\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst unsigned char *pool_lookup_bin_checksum(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id *\fR\fItypep\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return the checksum that is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. Returns the checksum as binary data, you can use the returned type to calculate the length of the checksum\&. No temporary space area is needed\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_lookup_deltalocation(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, unsigned int *\fR\fImedianrp\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-This is a utility lookup function to return the delta location for a delta rpm\&. As solvables cannot store deltas, you have to use SOLVID_POS as argument and set the Pool\(cqs datapos pointer to point to valid delta rpm data\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_search(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB, int (*\fR\fIcallback\fR\fB)(void *\fR\fIcbdata\fR\fB, Solvable *\fR\fIs\fR\fB, Repodata *\fR\fIdata\fR\fB, Repokey *\fR\fIkey\fR\fB, KeyValue *\fR\fIkv\fR\fB), void *\fR\fIcbdata\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Perform a search on all data stored in the pool\&. You can limit the search area by using the \fIsolvid\fR and \fIkeyname\fR arguments\&. The values can be optionally matched against the \fImatch\fR argument, use NULL if you do not want this matching\&. See the Dataiterator manpage about the possible matches modes and the \fIflags\fR argument\&. For all (matching) values, the callback function is called with the \fIcbdata\fR callback argument and the data describing the value\&.
-.SH "JOB AND SELECTION FUNCTIONS"
-.sp
-A Job consists of two Ids, \fIhow\fR and \fIwhat\fR\&. The \fIhow\fR part describes the action, the job flags, and the selection method while the \fIwhat\fR part is in input for the selection\&. A Selection is a queue consisting of multiple jobs (thus the number of elements in the queue must be a multiple of two)\&. See the Solver manpage for more information about jobs\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_job2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB, Id\fR \fIflagmask\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a job into a string\&. Useful for debugging purposes\&. The \fIflagmask\fR can be used to mask the flags of the job, use \(lq0\(rq if you do not want to see such flags, \(lq\-1\(rq to see all flags, or a combination of the flags you want to see\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_job2solvables(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIpkgs\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return a list of solvables that the specified job selects\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBint pool_isemptyupdatejob(Pool *\fR\fIpool\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Return \(lq1\(rq if the job is an update job that does not work with any installed package, i\&.e\&. the job is basically a no\-op\&. You can use this to turn no\-op update jobs into install jobs (as done by package managers like \(lqzypper\(rq)\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBconst char *pool_selection2str(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIselection\fR\fB, Id\fR \fIflagmask\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Convert a selection into a string\&. Useful for debugging purposes\&. See the pool_job2str() function for the \fIflagmask\fR argument\&.
-.SH "ODDS AND ENDS"
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_freeallrepos(Pool *\fR\fIpool\fR\fB, int\fR \fIreuseids\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Free all repos from the pool (including all solvables)\&. If \fIreuseids\fR is true, all Ids of the solvables are free to be reused the next time solvables are created\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\fBvoid pool_clear_pos(Pool *\fR\fIpool\fR\fB)\fR;
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-Clear the data position stored in the pool\&.
-.SH "ARCHITECTURE POLICIES"
-.sp
-An architecture policy defines a list of architectures that can be installed on the system, and also the relationship between them (i\&.e\&. the ordering)\&. Architectures can be delimited with three different characters:
-.PP
-\fB\*(Aq:\*(Aq\fR
-.RS 4
-No relationship between the architectures\&. A package of one architecture can not be replaced with one of the other architecture\&.
-.RE
-.PP
-\fB\*(Aq>\*(Aq\fR
-.RS 4
-The first architecture is better than the second one\&. An installed package of the second architecture may be replaced with one from the first architecture and vice versa\&. The solver will select the better architecture if the versions are the same\&.
-.RE
-.PP
-\fB\*(Aq=\*(Aq\fR
-.RS 4
-The two architectures are freely exchangeable\&. Used to define aliases for architectures\&.
-.RE
-.sp
-An example would be \*(Aqx86_64:i686=athlon>i586\*(Aq\&. This means that x86_64 packages can only be replaced by other x86_64 packages, i686 packages can be replaced by i686 and i586 packages (but i686 packages will be preferred) and athlon is another name for the i686 architecture\&.
-.sp
-You can turn off the architecture replacement checks with the Solver\(cqs SOLVER_FLAG_ALLOW_ARCHCHANGE flag\&.
-.SH "VENDOR POLICIES"
-.sp
-Different vendors often compile packages with different features, so Libsolv only replace installed packages of one vendor with packages coming from the same vendor\&. Also, while the version of a package is normally defined by the upstream project, the release part of the version is set by the vendor\(cqs package maintainer, so it\(cqs not meaningful to do version comparisons for packages coming from different vendors\&.
-.sp
-Vendor in this case means the SOLVABLE_VENDOR string stored in each solvable\&. Sometimes a vendor changes names, or multiple vendors form a group that coordinate their package building, so libsolv offers a way to define that a group of vendors are compatible\&. You do that be defining vendor equivalence classes, packages from a vendor from one class may be replaced with packages from all the other vendors in the class\&.
-.sp
-There can be multiple equivalence classes, the set of allowed vendor changes for an installed package is calculated by building the union of all of the equivalence classes the vendor of the installed package is part of\&.
-.sp
-You can turn off the architecture replacement checks with the Solver\(cqs SOLVER_FLAG_ALLOW_VENDORCHANGE flag\&.
-.SH "BOOLEAN DEPENDENCIES"
-.sp
-Boolean Dependencies allow to build complex expressions from simple dependencies\&. While rpm does not support boolean expressions in dependencies and debian only allows an "OR" expression, libsolv allows arbitrary complex expressions\&. The following basic types are supported:
-.PP
-\fBREL_OR\fR
-.RS 4
-The expression is true if either the first dependency or the second one is true\&. This is useful for package dependencies like \(lqRequires\(rq, where you can specify that either one of the packages need to be installed\&.
-.RE
-.PP
-\fBREL_AND\fR
-.RS 4
-The expression is true if both dependencies are true\&. The packages fulfilling the dependencies may be different, i\&.e\&. \(lqSupplements: perl AND python\(rq is true if both a package providing perl and a package providing python are installed\&. The solver currently only supports REL_AND in Supplements/Enhances dependencies, in other types of dependencies it gets treated as REL_WITH\&.
-.RE
-.PP
-\fBREL_WITH\fR
-.RS 4
-The expression is true if both dependencies are true and are fulfilled by the same package\&. Thus \(lqSupplements: perl AND python\(rq would only be true if a package is installed that provides both dependencies (some kind of multi\-language interpreter)\&.
-.RE
-.PP
-\fBREL_COND\fR
-.RS 4
-The expression is true if the first dependency is true or the second dependency is false\&. Libsolv currently does not support this type of dependency in the solver code\&.
-.RE
-.sp
-Each sub\-dependency of a boolean dependency can in turn be a boolean dependency, so you can chain them to create complex dependencies\&.
-.SH "NAMESPACE DEPENDENCIES"
-.sp
-Namespace dependencies can be used to implement dependencies on attributes external to libsolv\&. An example would be a dependency on the language set by the user\&. This types of dependencies are usually only used for \(lqConflicts\(rq or \(lqSupplements\(rq dependencies, as the underlying package manager does not know how to deal with them\&.
-.sp
-If the library needs to evaluate a namespace dependency, it calls the namespace callback function set in the pool\&. The callback function can return a set of packages that \(lqprovide\(rq the dependency\&. If the dependency is provided by the system, the returned set should consist of just the system solvable (Solvable Id 1)\&.
-.sp
-The returned set of packages must be returned as offset into the whatprovidesdata array\&. You can use the pool_queuetowhatprovides function to convert a queue into such an offset\&. To ease programming the callback function, the return values \(lq0\(rq and \(lq1\(rq are not interpreted as an offset\&. \(lq0\(rq means that no package is in the return set, \(lq1\(rq means that just the system solvable is in the set\&.
-.sp
-The returned set is cached, so that for each namespace dependency the callback is just called once\&. If you need to flush the cache (maybe because the user has selected a different language), use the pool_flush_namespaceproviders() function\&.
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/libsolv-pool.txt b/libsolv-0.6.15/doc/libsolv-pool.txt
deleted file mode 100644 (file)
index 8ee0c18..0000000
+++ /dev/null
@@ -1,881 +0,0 @@
-Libsolv-Pool(3)
-===============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-libsolv-pool - Libsolv's pool object
-
-
-Public Attributes
------------------
-
-*void *appdata*::
-A no-purpose pointer free to use for the library user. Freeing the pool
-simply discards the pointer.
-
-*Stringpool ss*::
-The pool of unified strings.
-
-*Reldep *rels*::
-The pool of unified relation dependencies.
-
-*int nrels*::
-Number of allocated relation dependencies.
-
-*Repo **repos*::
-The array of repository pointers, indexed by repository Id.
-
-*int nrepos*::
-Number of allocated repository array elements, i.e. the size
-of the repos array.
-
-*int urepos*::
-Number of used (i.e. non-zero) repository array elements.
-
-*Repo *installed*::
-Pointer to the repo holding the installed packages. You are free to read
-this attribute, but you should use pool_set_installed() if you want to
-change it.
-
-*Solvable *solvables*::
-The array of Solvable objects.
-
-*int nsolvables*::
-Number of Solvable objects, i.e. the size of the solvables array. Note
-that the array may contain freed solvables, in that case the repo pointer
-of the solvable will be zero.
-
-*int disttype*::
-The distribution type of your system, e.g. DISTTYPE_DEB. You are free to
-read this attribute, but you should use pool_setdisttype() if you want to
-change it.
-
-*Id *whatprovidesdata*::
-Multi-purpose Id storage holding zero terminated arrays of Ids.
-pool_whatprovides() returns an offset into this data.
-
-*Map *considered*::
-Optional bitmap that can make the library ignore solvables. If a bitmap is
-set, only solvables that have a set bit in the bitmap at their Id are
-considered usable.
-
-*int debugmask*::
-A mask that defines which debug events should be reported.
-pool_setdebuglevel() sets this mask.
-
-*Datapos pos*::
-An object storing some position in the repository data. Functions like
-dataiterator_set_pos() set this object, accessing data with a pseudo
-solvable Id of SOLVID_POS uses it.
-
-*Queue pooljobs*::
-A queue where fixed solver jobs can be stored. This jobs are automatically
-added when solver_solve() is called, they are useful to store configuration
-data like which packages should be multiversion installed.
-
-Creation and Destruction
-------------------------
-
-       Pool *pool_create();
-
-Create a new instance of a pool.
-
-       void pool_free(Pool *pool);
-
-Free a pool and all of the data it contains, e.g. the solvables, 
-repositories, strings.
-
-
-Debugging and error reporting
------------------------------
-
-=== Constants ===
-
-*SOLV_FATAL*::
-Report the error and call ``exit(1)'' afterwards. You cannot mask this
-level. Reports to stderr instead of stdout.
-
-*SOLV_ERROR*::
-Used to report errors. Reports to stderr instead of stdout.
-
-*SOLV_WARN*::
-Used to report warnings.
-
-*SOLV_DEBUG_STATS*::
-Used to report statistical data.
-
-*SOLV_DEBUG_RULE_CREATION*::
-Used to report information about the solver's creation of rules.
-
-*SOLV_DEBUG_PROPAGATE*::
-Used to report information about the solver's unit rule propagation
-process.
-
-*SOLV_DEBUG_ANALYZE*::
-Used to report information about the solver's learnt rule generation
-mechanism.
-
-*SOLV_DEBUG_UNSOLVABLE*::
-Used to report information about the solver dealing with conflicting
-rules.
-
-*SOLV_DEBUG_SOLUTIONS*::
-Used to report information about the solver creating solutions to solve
-problems.
-
-*SOLV_DEBUG_POLICY*::
-Used to report information about the solver searching for an optimal
-solution.
-
-*SOLV_DEBUG_RESULT*::
-Used by the debug functions to output results.
-
-*SOLV_DEBUG_JOB*::
-Used to report information about the job rule generation process.
-
-*SOLV_DEBUG_SOLVER*::
-Used to report information about what the solver is currently
-doing.
-
-*SOLV_DEBUG_TRANSACTION*::
-Used to report information about the transaction generation and
-ordering process.
-
-*SOLV_DEBUG_TO_STDERR*::
-Write debug messages to stderr instead of stdout.
-
-=== Functions ===
-
-       void pool_debug(Pool *pool, int type, const char *format, ...);
-
-Report a message of the type _type_. You can filter debug messages by
-setting a debug mask.
-
-       void pool_setdebuglevel(Pool *pool, int level);
-
-Set a predefined debug mask. A higher level generally means more bits in
-the mask are set, thus more messages are printed.
-
-       void pool_setdebugmask(Pool *pool, int mask);
-
-Set the debug mask to filter debug messages.
-
-       int pool_error(Pool *pool, int ret, const char *format, ...);
-
-Set the pool's error string. The _ret_ value is simply used as a
-return value of the function so that you can write code like
-+return pool_error(...);+. If the debug mask contains the *SOLV_ERROR*
-bit, pool_debug() is also called with the message and type *SOLV_ERROR*.
-
-       extern char *pool_errstr(Pool *pool);
-
-Return the current error string stored in the pool. Like with the libc's
-errno value, the string is only meaningful after a function returned an
-error.
-
-       void pool_setdebugcallback(Pool *pool, void (*debugcallback)(Pool *, void *data, int type, const char *str), void *debugcallbackdata);
-
-Set a custom debug callback function. Instead of writing to stdout or
-stderr, the callback function will be called.
-
-
-Pool configuration
-------------------
-
-=== Constants ===
-
-*DISTTYPE_RPM*::
-Used for systems which use rpm as low level package manager.
-
-*DISTTYPE_DEB*::
-Used for systems which use dpkg as low level package manager.
-
-*DISTTYPE_ARCH*::
-Used for systems which use the arch linux package manager.
-
-*DISTTYPE_HAIKU*::
-Used for systems which use haiku packages.
-
-*POOL_FLAG_PROMOTEEPOCH*::
-Promote the epoch of the providing dependency to the requesting
-dependency if it does not contain an epoch. Used at some time
-in old rpm versions, modern systems should never need this.
-
-*POOL_FLAG_FORBIDSELFCONFLICTS*::
-Disallow the installation of packages that conflict with themselves.
-Debian always allows self-conflicting packages, rpm used to forbid
-them but switched to also allowing them recently.
-
-*POOL_FLAG_OBSOLETEUSESPROVIDES*::
-Make obsolete type dependency match against provides instead of
-just the name and version of packages. Very old versions of rpm
-used the name/version, then it got switched to provides and later
-switched back again to just name/version.
-
-*POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES*::
-An implicit obsoletes is the internal mechanism to remove the
-old package on an update. The default is to remove all packages
-with the same name, rpm-5 switched to also removing packages
-providing the same name.
-
-*POOL_FLAG_OBSOLETEUSESCOLORS*::
-Rpm's multilib implementation (used in RedHat and Fedora)
-distinguishes between 32bit and 64bit packages (the terminology
-is that they have a different color). If obsoleteusescolors is
-set, packages with different colors will not obsolete each other.
-
-*POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*::
-Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if
-packages of the same name can be installed in parallel. For
-current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be
-false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true
-(this is the default if FEDORA is defined when libsolv is
-compiled).
-
-*POOL_FLAG_NOINSTALLEDOBSOLETES*::
-New versions of rpm consider the obsoletes of installed packages
-when checking for dependency, thus you may not install a package
-that is obsoleted by some other installed package, unless you
-also erase the other package.
-
-*POOL_FLAG_HAVEDISTEPOCH*::
-Mandriva added a new field called distepoch that gets checked in
-version comparison if the epoch/version/release of two packages
-are the same.
-
-*POOL_FLAG_NOOBSOLETESMULTIVERSION*::
-If a package is installed in multiversionmode, rpm used to ignore
-both the implicit obsoletes and the obsolete dependency of a
-package. This was changed to ignoring just the implicit obsoletes,
-thus you may install multiple versions of the same name, but
-obsoleted packages still get removed.
-
-*POOL_FLAG_ADDFILEPROVIDESFILTERED*::
-Make the addfileprovides method only add files from the standard
-locations (i.e. the ``bin'' and ``etc'' directories). This is
-useful if you have only few packages that use non-standard file
-dependencies, but you still want the fast speed that addfileprovides()
-generates.
-
-
-=== Functions ===
-       int pool_setdisttype(Pool *pool, int disttype);
-
-Set the package type of your system. The disttype is used for example
-to define package comparison semantics. Libsolv's default disttype
-should match the package manager of your system, so you only need to
-use this function if you want to use the library to solve packaging
-problems for different systems. The Function returns the old
-disttype on success, and -1 if the new disttype is not supported.
-
-       int pool_set_flag(Pool *pool, int flag, int value);
-
-Set a flag to a new value. Returns the old value of the flag.
-
-       int pool_get_flag(Pool *pool, int flag);
-
-Get the value of a pool flag. See the constants section about the meaning
-of the flags.
-
-       void pool_set_rootdir(Pool *pool, const char *rootdir);
-
-Set a specific root directory. Some library functions support a flag that
-tells the function to prepend the rootdir to file and directory names.
-
-       const char *pool_get_rootdir(Pool *pool);
-
-Return the current value of the root directory.
-
-       char *pool_prepend_rootdir(Pool *pool, const char *dir);
-
-Prepend the root directory to the _dir_ argument string. The returned
-string has been newly allocated and needs to be freed after use.
-
-       char *pool_prepend_rootdir_tmp(Pool *pool, const char *dir);
-
-Same as pool_prepend_rootdir, but uses the pool's temporary space for
-allocation.
-
-       void pool_set_installed(Pool *pool, Repo *repo);
-
-Set which repository should be treated as the ``installed'' repository,
-i.e. the one that holds information about the installed packages.
-
-       void pool_set_languages(Pool *pool, const char **languages, int nlanguages);
-
-Set the language of your system. The library provides lookup functions that
-return localized strings, for example for package descriptions. You can
-set an array of languages to provide a fallback mechanism if one language
-is not available.
-
-       void pool_setarch(Pool *pool, const char *arch);
-
-Set the architecture of your system. The architecture is used to determine
-which packages are installable and which packages cannot be installed.
-The _arch_ argument is normally the ``machine'' value of the ``uname''
-system call.
-
-       void pool_setarchpolicy(Pool *, const char *);
-
-Set the architecture policy for your system. This is the general version
-of pool_setarch (in fact pool_setarch calls pool_setarchpolicy internally).
-See the section about architecture policies for more information.
-
-       void pool_addvendorclass(Pool *pool, const char **vendorclass);
-
-Add a new vendor equivalence class to the system. A vendor equivalence class
-defines if an installed package of one vendor can be replaced by a package
-coming from a different vendor. The _vendorclass_ argument must be a
-NULL terminated array of strings. See the section about vendor policies for
-more information.
-
-       void pool_setvendorclasses(Pool *pool, const char **vendorclasses);
-
-Set all allowed vendor equivalences. The vendorclasses argument must be an
-NULL terminated array consisting of all allowed classes concatenated.
-Each class itself must be NULL terminated, thus the last class ends with
-two NULL elements, one to finish the class and one to finish the list
-of classes.
-
-       void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *));
-
-Define a custom vendor check mechanism. You can use this if libsolv's
-internal vendor equivalence class mechanism does not match your needs.
-
-       void pool_setloadcallback(Pool *pool, int (*cb)(Pool *, Repodata *, void *), void *loadcbdata);
-
-Define a callback function that gets called when repository metadata needs
-to be loaded on demand. See the section about on demand loading in the
-libsolv-repodata manual.
-
-       void pool_setnamespacecallback(Pool *pool, Id (*cb)(Pool *, void *, Id, Id), void *nscbdata);
-
-Define a callback function to implement custom namespace support. See the
-section about namespace dependencies.
-
-
-Id pool management
-------------------
-=== Constants ===
-
-*ID_EMPTY*::
-The Id of the empty string, it is always Id 1.
-
-*REL_LT*::
-Represents a ``<'' relation.
-
-*REL_EQ*::
-Represents a ``='' relation.
-
-*REL_GT*::
-Represents a ``>'' relation. You can use combinations of REL_GT, REL_EQ,
-and REL_LT or-ed together to create any relation you like.
-
-*REL_AND*::
-A boolean AND operation, the ``name'' and ``evr'' parts of the relation can
-be two sub-dependencies. Packages must match both parts of the dependency.
-
-*REL_OR*::
-A boolean OR operation, the ``name'' and ``evr'' parts of the relation can
-be two sub-dependencies. Packages can match any part of the dependency.
-
-*REL_WITH*::
-Like REL_AND, but packages must match both dependencies simultaneously. See
-the section about boolean dependencies about more information.
-
-*REL_NAMESPACE*::
-A special namespace relation. See the section about namespace dependencies
-for more information.
-
-*REL_ARCH*::
-An architecture filter dependency. The ``name'' part of the relation is a
-sub-dependency, the ``evr'' part is the Id of an architecture that the
-matching packages must have (note that this is an exact match ignoring
-architecture policies).
-
-*REL_FILECONFLICT*::
-An internal file conflict dependency used to represent file conflicts. See
-the pool_add_fileconflicts_deps() function.
-
-*REL_COND*::
-A conditional dependency, the ``name'' sub-dependency is only considered if
-the ``evr'' sub-dependency is fulfilled. See the section about boolean
-dependencies about more information.
-
-*REL_COMPAT*::
-A compat dependency used in Haiku to represent version ranges.  The
-``name'' part is the actual version, the ``evr'' part is the backwards
-compatibility version.
-
-=== Functions ===
-       Id pool_str2id(Pool *pool, const char *str, int create);
-
-Add a string to the pool of unified strings, returning the Id of the string.
-If _create_ is zero, new strings will not be added to the pool, instead
-Id 0 is returned.
-
-       Id pool_strn2id(Pool *pool, const char *str, unsigned int len, int create);
-
-Same as pool_str2id, but only _len_ characters of the string are used. This
-can be used to add substrings to the pool.
-
-       Id pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create);
-
-Create a relational dependency from to other dependencies, _name_ and _evr_,
-and a _flag_. See the *REL_* constants for the supported flags. As with
-pool_str2id, _create_ defines if new dependencies will get added or Id zero
-will be returned instead.
-
-       Id pool_id2langid(Pool *pool, Id id, const char *lang, int create);
-
-Attach a language suffix to a string Id. This function can be used to
-create language keyname Ids from keynames, it is functional equivalent
-to converting the _id_ argument to a string, adding a ``:'' character
-and the _lang_ argument to the string and then converting the result back
-into an Id.
-
-       const char *pool_id2str(const Pool *pool, Id id);
-
-Convert an Id back into a string. If the Id is a relational Id, the
-``name'' part will be converted instead.
-
-       const char *pool_id2rel(const Pool *pool, Id id);
-
-Return the relation string of a relational Id. Returns an empty string if
-the passed Id is not a relation.
-
-       const char *pool_id2evr(const Pool *pool, Id id);
-
-Return the ``evr'' part of a relational Id as string. Returns an empty
-string if the passed Id is not a relation.
-
-       const char *pool_dep2str(Pool *pool, Id id);
-
-Convert an Id back into a string. If the passed Id belongs to a relation,
-a string representing the relation is returned. Note that in that case
-the string is allocated on the pool's temporary space.
-
-       void pool_freeidhashes(Pool *pool);
-
-Free the hashes used to unify strings and relations. You can use this
-function to save memory if you know that you will no longer create new
-strings and relations.
-
-
-Solvable functions
-------------------
-
-       Solvable *pool_id2solvable(const Pool *pool, Id p);
-
-Convert a solvable Id into a pointer to the solvable data. Note that the
-pointer may become invalid if new solvables are created or old solvables
-deleted, because the array storing all solvables may get reallocated.
-
-       const char *pool_solvid2str(Pool *pool, Id p);
-
-Return a string representing the solvable with the Id _p_. The string will
-be some canonical representation of the solvable, usually a combination of
-the name, the version, and the architecture.
-
-       const char *pool_solvable2str(Pool *pool, Solvable *s);
-
-Same as pool_solvid2str, but instead of the Id, a pointer to the solvable
-is passed.
-
-
-Dependency matching
--------------------
-
-=== Constants ===
-*EVRCMP_COMPARE*::
-Compare all parts of the version, treat missing parts as empty strings.
-
-*EVRCMP_MATCH_RELEASE*::
-A special mode for rpm version string matching. If a version misses a
-release part, it matches all releases. In that case the special values
-``-2'' and ``2'' are returned, depending on which of the two versions
-did not have a release part.
-
-*EVRCMP_MATCH*::
-A generic match, missing parts always match.
-
-*EVRCMP_COMPARE_EVONLY*::
-Only compare the epoch and the version parts, ignore the release part.
-
-=== Functions ===
-       int pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode);
-
-Compare two version Ids, return -1 if the first version is less than the
-second version, 0 if they are identical, and 1 if the first version is
-bigger than the second one.
-
-       int pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
-
-Same as pool_evrcmp(), but uses strings instead of Ids.
-
-       int pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release);
-
-Match a version Id against an epoch, a version and a release string. Passing
-NULL means that the part should match everything.
-
-       int pool_match_dep(Pool *pool, Id d1, Id d2);
-
-Returns ``1'' if the dependency _d1_ (the provider) is matched by the
-dependency _d2_, otherwise ``0'' is returned. For two dependencies to
-match, both the ``name'' parts must match and the version range described
-by the ``evr'' parts must overlap.
-
-       int pool_match_nevr(Pool *pool, Solvable *s, Id d);
-
-Like pool_match_dep, but the provider is the "self-provides" dependency
-of the Solvable _s_, i.e. the dependency ``s->name = s->evr''.
-
-
-Whatprovides Index
-------------------
-       void pool_createwhatprovides(Pool *pool);
-
-Create an index that maps dependency Ids to sets of packages that provide the
-dependency.
-
-       void pool_freewhatprovides(Pool *pool);
-
-Free the whatprovides index to save memory.
-
-       Id pool_whatprovides(Pool *pool, Id d);
-
-Return an offset into the Pool's whatprovidesdata array. The solvables with
-the Ids stored starting at that offset provide the dependency _d_. The
-solvable list is zero terminated.
-
-       Id *pool_whatprovides_ptr(Pool *pool, Id d);
-
-Instead of returning the offset, return the pointer to the Ids stored at
-that offset. Note that this pointer has a very limit validity time, as any
-call that adds new values to the whatprovidesdata area may reallocate the
-array.
-
-       Id pool_queuetowhatprovides(Pool *pool, Queue *q);
-
-Add the contents of the Queue _q_ to the end of the whatprovidesdata array,
-returning the offset into the array.
-
-       void pool_addfileprovides(Pool *pool);
-
-Some package managers like rpm allow dependencies on files contained in
-other packages. To allow libsolv to deal with those dependencies in an
-efficient way, you need to call the addfileprovides method after creating
-and reading all repositories. This method will scan all dependency for file
-names and then scan all packages for matching files. If a filename has been
-matched, it will be added to the provides list of the corresponding
-package.
-
-       void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst);
-
-Same as pool_addfileprovides, but the added Ids are returned in two Queues,
-_idq_ for all repositories except the one containing the ``installed''
-packages, _idqinst_ for the latter one. This information can be stored in
-the meta section of the repositories to speed up the next time the
-repository is loaded and addfileprovides is called
-
-       void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
-
-Clear the cache of the providers for namespace dependencies matching
-namespace _ns_. If the _evr_ argument is non-zero, the namespace dependency
-for exactly that dependency is cleared, otherwise all matching namespace
-dependencies are cleared. See the section about Namespace dependencies
-for further information.
-
-       void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts);
-
-Some package managers like rpm report conflicts when a package installation
-overwrites a file of another installed package with different content. As
-file content information is not stored in the repository metadata, those
-conflicts can only be detected after the packages are downloaded. Libsolv
-provides a function to check for such conflicts, pool_findfileconflicts().
-If conflicts are found, they can be added as special *REL_FILECONFLICT*
-provides dependencies, so that the solver will know about the conflict when
-it is re-run.
-
-
-Utility functions
------------------
-       char *pool_alloctmpspace(Pool *pool, int len);
-
-Allocate space on the pool's temporary space area. This space has a limited
-lifetime, it will be automatically freed after a fixed amount (currently
-16) of other pool_alloctmpspace() calls are done.
-
-       void pool_freetmpspace(Pool *pool, const char *space);
-
-Give the space allocated with pool_alloctmpspace back to the system. You
-do not have to use this function, as the space is automatically reclaimed,
-but it can be useful to extend the lifetime of other pointers to the pool's
-temporary space area.
-
-       const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
-
-Convert some binary data to hexadecimal, returning a string allocated in
-the pool's temporary space area.
-
-       char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3);
-
-Join three strings and return the result in the pool's temporary space
-area. You can use NULL arguments if you just want to join less strings.
-
-       char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
-
-Like pool_tmpjoin(), but if the first argument is the last allocated space
-in the pool's temporary space area, it will be replaced with the result of
-the join and no new temporary space slot will be used.  Thus you can join
-more than three strings by a combination of one pool_tmpjoin() and multiple
-pool_tmpappend() calls. Note that the _str1_ pointer is no longer usable
-after the call.
-
-
-Data lookup
------------
-=== Constants ===
-
-*SOLVID_POS*::
-Use the data position stored in the pool for the lookup instead of looking
-up the data of a solvable.
-
-*SOLVID_META*::
-Use the data stored in the meta section of a repository (or repodata
-area) instead of looking up the data of a solvable. This constant does
-not work for the pool's lookup functions, use it for the repo's or
-repodata's lookup functions instead. It's just listed for completeness.
-
-=== Functions ===
-       const char *pool_lookup_str(Pool *pool, Id solvid, Id keyname);
-
-Return the  string value stored under the attribute _keyname_ in solvable
-_solvid_.
-
-       unsigned long long pool_lookup_num(Pool *pool, Id solvid, Id keyname, unsigned long long notfound);
-
-Return the 64bit unsigned number stored under the attribute _keyname_ in
-solvable _solvid_. If no such number is found, the value of the _notfound_
-argument is returned instead.
-
-       Id pool_lookup_id(Pool *pool, Id solvid, Id keyname);
-
-Return the Id stored under the attribute _keyname_ in solvable _solvid_.
-
-       int pool_lookup_idarray(Pool *pool, Id solvid, Id keyname, Queue *q);
-
-Fill the queue _q_ with the content of the Id array stored under the
-attribute _keyname_ in solvable _solvid_. Returns ``1'' if an array was
-found, otherwise the queue will be empty and ``0'' will be returned.
-
-       int pool_lookup_void(Pool *pool, Id solvid, Id keyname);
-
-Returns ``1'' if a void value is stored under the attribute _keyname_ in
-solvable _solvid_, otherwise ``0''.
-
-       const char *pool_lookup_checksum(Pool *pool, Id solvid, Id keyname, Id *typep);
-
-Return the checksum that is stored under the attribute _keyname_ in
-solvable _solvid_.  The type of the checksum will be returned over the
-_typep_ pointer. If no such checksum is found, NULL will be returned and
-the type will be set to zero. Note that the result is stored in the Pool's
-temporary space area.
-
-       const unsigned char *pool_lookup_bin_checksum(Pool *pool, Id solvid, Id keyname, Id *typep);
-
-Return the checksum that is stored under the attribute _keyname_ in
-solvable _solvid_.  Returns the checksum as binary data, you can use the
-returned type to calculate the length of the checksum. No temporary space
-area is needed.
-
-       const char *pool_lookup_deltalocation(Pool *pool, Id solvid, unsigned int *medianrp);
-
-This is a utility lookup function to return the delta location for a delta
-rpm.  As solvables cannot store deltas, you have to use SOLVID_POS as
-argument and set the Pool's datapos pointer to point to valid delta rpm
-data.
-
-       void pool_search(Pool *pool, Id solvid, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata);
-
-Perform a search on all data stored in the pool. You can limit the search
-area by using the _solvid_ and _keyname_ arguments. The values can be
-optionally matched against the _match_ argument, use NULL if you do not
-want this matching. See the Dataiterator manpage about the possible matches
-modes and the _flags_ argument. For all (matching) values, the callback
-function is called with the _cbdata_ callback argument and the data
-describing the value.
-
-
-Job and Selection functions
----------------------------
-A Job consists of two Ids, _how_ and _what_. The _how_ part describes the
-action, the job flags, and the selection method while the _what_ part is
-in input for the selection. A Selection is a queue consisting of multiple
-jobs (thus the number of elements in the queue must be a multiple of two).
-See the Solver manpage for more information about jobs.
-
-       const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
-
-Convert a job into a string. Useful for debugging purposes. The _flagmask_
-can be used to mask the flags of the job, use ``0'' if you do not want to
-see such flags, ``-1'' to see all flags, or a combination of the flags
-you want to see.
-
-       void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
-
-Return a list of solvables that the specified job selects.
-
-       int pool_isemptyupdatejob(Pool *pool, Id how, Id what);
-
-Return ``1'' if the job is an update job that does not work with any
-installed package, i.e. the job is basically a no-op. You can use this
-to turn no-op update jobs into install jobs (as done by package managers
-like ``zypper'').
-
-       const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
-
-Convert a selection into a string. Useful for debugging purposes. See the
-pool_job2str() function for the _flagmask_ argument.
-
-
-Odds and Ends
--------------
-       void pool_freeallrepos(Pool *pool, int reuseids);
-
-Free all repos from the pool (including all solvables). If _reuseids_ is
-true, all Ids of the solvables are free to be reused the next time
-solvables are created.
-
-       void pool_clear_pos(Pool *pool);
-       
-Clear the data position stored in the pool.
-
-
-Architecture Policies
----------------------
-An architecture policy defines a list of architectures that can be
-installed on the system, and also the relationship between them (i.e. the
-ordering). Architectures can be delimited with three different characters:
-
-*\':'*::
-No relationship between the architectures. A package of one architecture
-can not be replaced with one of the other architecture.
-
-*\'>'*::
-The first architecture is better than the second one. An installed package
-of the second architecture may be replaced with one from the first
-architecture and vice versa. The solver will select the better architecture
-if the versions are the same.
-
-*\'='*::
-The two architectures are freely exchangeable. Used to define aliases
-for architectures.
-
-An example would be \'+x86_64:i686=athlon>i586+'. This means that x86_64
-packages can only be replaced by other x86_64 packages, i686 packages
-can be replaced by i686 and i586 packages (but i686 packages will be
-preferred) and athlon is another name for the i686 architecture.
-
-You can turn off the architecture replacement checks with the Solver's
-SOLVER_FLAG_ALLOW_ARCHCHANGE flag.
-
-Vendor Policies
----------------
-Different vendors often compile packages with different features, so
-Libsolv only replace installed packages of one vendor with packages coming
-from the same vendor. Also, while the version of a package is normally
-defined by the upstream project, the release part of the version is
-set by the vendor's package maintainer, so it's not meaningful to
-do version comparisons for packages coming from different vendors.
-
-Vendor in this case means the SOLVABLE_VENDOR string stored in each
-solvable. Sometimes a vendor changes names, or multiple vendors form a
-group that coordinate their package building, so libsolv offers a way
-to define that a group of vendors are compatible. You do that be
-defining vendor equivalence classes, packages from a vendor from
-one class may be replaced with packages from all the other vendors
-in the class.
-
-There can be multiple equivalence classes, the set of allowed vendor
-changes for an installed package is calculated by building the union
-of all of the equivalence classes the vendor of the installed package
-is part of.
-
-You can turn off the architecture replacement checks with the Solver's
-SOLVER_FLAG_ALLOW_VENDORCHANGE flag.
-
-
-Boolean Dependencies
---------------------
-Boolean Dependencies allow to build complex expressions from simple
-dependencies. While rpm does not support boolean expressions in
-dependencies and debian only allows an "OR" expression, libsolv
-allows arbitrary complex expressions. The following basic types
-are supported:
-
-*REL_OR*::
-The expression is true if either the first dependency or the second
-one is true. This is useful for package dependencies like ``Requires'',
-where you can specify that either one of the packages need to be
-installed.
-
-*REL_AND*::
-The expression is true if both dependencies are true. The packages
-fulfilling the dependencies may be different, i.e. 
-``Supplements: perl AND python'' is true if both a package providing
-perl and a package providing python are installed. The solver currently
-only supports REL_AND in Supplements/Enhances dependencies, in other
-types of dependencies it gets treated as REL_WITH.
-
-*REL_WITH*::
-The expression is true if both dependencies are true and are fulfilled by
-the same package. Thus ``Supplements: perl AND python'' would only be true
-if a package is installed that provides both dependencies (some kind
-of multi-language interpreter).
-
-*REL_COND*::
-The expression is true if the first dependency is true or the second
-dependency is false. Libsolv currently does not support this type of
-dependency in the solver code.
-
-Each sub-dependency of a boolean dependency can in turn be a boolean
-dependency, so you can chain them to create complex dependencies.
-
-
-Namespace Dependencies
-----------------------
-Namespace dependencies can be used to implement dependencies on
-attributes external to libsolv. An example would be a dependency
-on the language set by the user. This types of dependencies are
-usually only used for ``Conflicts'' or ``Supplements'' dependencies,
-as the underlying package manager does not know how to deal with
-them.
-
-If the library needs to evaluate a namespace dependency, it calls
-the namespace callback function set in the pool. The callback
-function can return a set of packages that ``provide'' the
-dependency. If the dependency is provided by the system, the
-returned set should consist of just the system solvable (Solvable
-Id 1).
-
-The returned set of packages must be returned as offset into
-the whatprovidesdata array. You can use the pool_queuetowhatprovides
-function to convert a queue into such an offset. To ease programming
-the callback function, the return values ``0'' and ``1'' are not
-interpreted as an offset. ``0'' means that no package is in the
-return set, ``1'' means that just the system solvable is in the set.
-
-The returned set is cached, so that for each namespace dependency
-the callback is just called once. If you need to flush the cache (maybe
-because the user has selected a different language), use the
-pool_flush_namespaceproviders() function.
-
-
-Author
-------
-Michael Schroeder <mls@suse.de>
-
diff --git a/libsolv-0.6.15/doc/libsolv.3 b/libsolv-0.6.15/doc/libsolv.3
deleted file mode 100644 (file)
index 24ab788..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-'\" t
-.\"     Title: Libsolv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "LIBSOLV" "3" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-libsolv \- package dependency solver library using a satisfiability algorithm
-.SH "DOCUMENTATION"
-.sp
-The libsolv documentation is split into multiple parts:
-.PP
-\fBlibsolv\-history\fR
-.RS 4
-how the libsolv library came into existence
-.RE
-.PP
-\fBlibsolv\-constantids\fR
-.RS 4
-fixed Ids for often used strings
-.RE
-.PP
-\fBlibsolv\-bindings\fR
-.RS 4
-access libsolv from perl/python/ruby
-.RE
-.PP
-\fBlibsolv\-pool\fR
-.RS 4
-libsolv\(cqs pool object
-.RE
-.SH "POINTER VALIDITY"
-.sp
-Note that all pointers to objects that have an Id have only a limited validity period, with the exception of Repo pointers\&. There are only guaranteed to be valid until a new object of that type is added or an object of that type is removed\&. Thus pointers to Solvable objects are only valid until another solvable is created, because adding a Solvable may relocate the Pool\(cqs Solvable array\&. This is also true for Pool strings, you should use solv_strdup() to create a copy of the string if you want to use it at some later time\&. You should use the Ids in the code and not the pointers, except for short times where you know that the pointer is safe\&.
-.sp
-Note also that the data lookup functions or the dataiterator also return values with limited lifetime, this is especially true for data stored in the paged data segment of solv files\&. This is normally data that consists of big strings like package descriptions or is not often needed like package checksums\&. Thus looking up a description of a solvable and then looking up the description of a different solvable or even the checksum of the same solvable may invalidate the first result\&. (The dataiterator supports a dataiterator_strdup() function to create a safe copy\&.)
-.sp
-The language bindings already deal with pointer validity, so you do not have to worry about this issue when using the bindings\&.
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/libsolv.txt b/libsolv-0.6.15/doc/libsolv.txt
deleted file mode 100644 (file)
index af44168..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-Libsolv(3)
-==========
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-libsolv - package dependency solver library using a satisfiability algorithm
-
-
-Documentation
--------------
-The libsolv documentation is split into multiple parts:
-
-*libsolv-history*::
-  how the libsolv library came into existence
-
-*libsolv-constantids*::
-  fixed Ids for often used strings
-
-*libsolv-bindings*::
-  access libsolv from perl/python/ruby
-
-*libsolv-pool*::
-  libsolv's pool object
-
-Pointer Validity
-----------------
-Note that all pointers to objects that have an Id have only a limited
-validity period, with the exception of Repo pointers. There are only
-guaranteed to be valid until a new object of that type is added or an
-object of that type is removed. Thus pointers to Solvable objects are only 
-valid until another solvable is created, because adding a Solvable may
-relocate the Pool's Solvable array. This is also true for Pool strings,
-you should use solv_strdup() to create a copy of the string if you
-want to use it at some later time. You should use the Ids in the code
-and not the pointers, except for short times where you know that the
-pointer is safe.
-
-Note also that the data lookup functions or the dataiterator also
-return values with limited lifetime, this is especially true for data
-stored in the paged data segment of solv files. This is normally
-data that consists of big strings like package descriptions or is not
-often needed like package checksums. Thus looking up a description of
-a solvable and then looking up the description of a different solvable
-or even the checksum of the same solvable may invalidate the first
-result. (The dataiterator supports a dataiterator_strdup() function
-to create a safe copy.)
-
-The language bindings already deal with pointer validity, so you do
-not have to worry about this issue when using the bindings.
-
-
-Author
-------
-Michael Schroeder <mls@suse.de>
-
diff --git a/libsolv-0.6.15/doc/mdk2solv.1 b/libsolv-0.6.15/doc/mdk2solv.1
deleted file mode 100644 (file)
index 4400c9b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-'\" t
-.\"     Title: mdk2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "MDK2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-mdk2solv \- convert files in Mandriva synthesis format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBmdk2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The mdk2solv tool reads Mandriva synthesis data (\fBhdlist\fR) from stdin, and writes it as solv file to standard output\&.
-.PP
-\fB\-i\fR \fIINFO\&.xml\fR
-.RS 4
-Also read the info file containing url, license, and src information from the specified xml file\&.
-.RE
-.PP
-\fB\-f\fR \fIFILES\&.xml\fR
-.RS 4
-Also read filelist information from the specified xml file\&.
-.RE
-.SH "SEE ALSO"
-.sp
-genhdlist2(1)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/mdk2solv.txt b/libsolv-0.6.15/doc/mdk2solv.txt
deleted file mode 100644 (file)
index 2616a87..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-mdk2solv(1)
-===========
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-mdk2solv - convert files in Mandriva synthesis format into a solv file
-
-Synopsis
---------
-*mdk2solv* ['OPTIONS']
-
-Description
------------
-The mdk2solv tool reads Mandriva synthesis data (*hdlist*) from stdin, and writes
-it as solv file to standard output.
-
-*-i* 'INFO.xml'::
-Also read the info file containing url, license, and src information from
-the specified xml file.
-
-*-f* 'FILES.xml'::
-Also read filelist information from the specified xml file.
-
-See Also
---------
-genhdlist2(1)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/mergesolv.1 b/libsolv-0.6.15/doc/mergesolv.1
deleted file mode 100644 (file)
index 3ff00e8..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-'\" t
-.\"     Title: mergesolv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "MERGESOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-mergesolv \- merge multiple files in solv format into a single one
-.SH "SYNOPSIS"
-.sp
-\fBmergesolv\fR [\fIOPTIONS\fR] \fIFILE1\&.solv\fR \fIFILE2\&.solv\fR \&...
-.SH "DESCRIPTION"
-.sp
-The mergesolv tool reads all solv files specified on the command line, and writes a merged version to standard output\&.
-.PP
-\fB\-X\fR
-.RS 4
-Autoexpand SUSE pattern and product provides into packages\&.
-.RE
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/mergesolv.txt b/libsolv-0.6.15/doc/mergesolv.txt
deleted file mode 100644 (file)
index bbe8c72..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-mergesolv(1)
-============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-mergesolv - merge multiple files in solv format into a single one
-
-Synopsis
---------
-*mergesolv* ['OPTIONS'] 'FILE1.solv' 'FILE2.solv' ...
-
-Description
------------
-The mergesolv tool reads all solv files specified on the command line,
-and writes a merged version to standard output.
-
-*-X*::
-Autoexpand SUSE pattern and product provides into packages.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/repomdxml2solv.1 b/libsolv-0.6.15/doc/repomdxml2solv.1
deleted file mode 100644 (file)
index e14b974..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-'\" t
-.\"     Title: repomdxml2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "REPOMDXML2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-repomdxml2solv \- convert a repomd\&.xml file into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBrepomdxml2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The repomd\&.xml file is the index file of a rpm\-md repository, containing references to all data file with checksums\&. The repomdxml2solv tool reads the repomd\&.xml file from stdin and writes the parsed data as solv file to standard output\&. The data is stored as meta attributes in the result\&.
-.PP
-\fB\-q\fR \fIWHAT\fR
-.RS 4
-Data query mode: instead of writing a solv file, select the
-\fIWHAT\fR
-element in the input data and write it to standard output\&. Examples for
-\fIWHAT\fR
-are
-\fBtype\fR
-to get a list of all types, and
-\fBprimary:location\fR
-to get the location of the element with type
-\fBprimary\fR\&.
-.RE
-.SH "SEE ALSO"
-.sp
-rpmmd2solv(1), mergesolv(1), createrepo(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/repomdxml2solv.txt b/libsolv-0.6.15/doc/repomdxml2solv.txt
deleted file mode 100644 (file)
index feb859c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-repomdxml2solv(1)
-=================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-repomdxml2solv - convert a repomd.xml file into a solv file
-
-Synopsis
---------
-*repomdxml2solv* ['OPTIONS']
-
-Description
------------
-The repomd.xml file is the index file of a rpm-md repository,
-containing references to all data file with checksums. The
-repomdxml2solv tool reads the repomd.xml file from stdin and
-writes the parsed data as solv file to standard output. The
-data is stored as meta attributes in the result.
-
-*-q* 'WHAT'::
-Data query mode: instead of writing a solv file, select the
-'WHAT' element in the input data and write it to standard output.
-Examples for 'WHAT' are *type* to get a list of all types, and
-*primary:location* to get the location of the element with
-type *primary*.
-
-See Also
---------
-rpmmd2solv(1), mergesolv(1), createrepo(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/rpmdb2solv.1 b/libsolv-0.6.15/doc/rpmdb2solv.1
deleted file mode 100644 (file)
index 2b4b931..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-'\" t
-.\"     Title: rpmdb2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "RPMDB2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-rpmdb2solv \- convert the rpm database into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBrpmdb2solv\fR [\fIOPTIONS\fR] [\fIREFFILE\&.solv\fR]
-.SH "DESCRIPTION"
-.sp
-The rpmdb2solv tool reads rpm\(cqs installed packages database and writes it in solv file format to standard output\&. You can make use of an old version of the database by specifying a \fIREFFILE\&.solv\fR file\&.
-.PP
-\fB\-o\fR \fIOUTFILE\fR
-.RS 4
-Write the generated solv to
-\fIOUTFILE\fR
-instead of standard output\&.
-.RE
-.PP
-\fB\-P\fR
-.RS 4
-Print percentages as packages are being read in\&. The output format is like rpm\(cqs \-\-percent option\&.
-.RE
-.PP
-\fB\-r\fR \fIROOTDIR\fR
-.RS 4
-Use
-\fIROOTDIR\fR
-as root directory\&.
-.RE
-.PP
-\fB\-k\fR
-.RS 4
-Read pubkeys from the rpm database instead of installed packages\&. Note that many distributions stopped storing pubkeys in the database but use a directory like
-\fB/var/lib/rpm/pubkeys\fR
-instead\&.
-.RE
-.PP
-\fB\-A\fR
-.RS 4
-Also scan the
-\fB/usr/share/appdata\fR
-for installed appdata files and create pseudo packages for each file\&.
-.RE
-.PP
-\fB\-p\fR \fIPRODDIR\fR
-.RS 4
-Also read SUSE product files from directory
-\fIPRODDIR\fR\&. The standard directory is
-\fB/etc/products\&.d\fR\&.
-.RE
-.PP
-\fB\-n\fR
-.RS 4
-Do not read any packages from the rpm database\&. This is useful together with
-\fB\-p\fR
-to only convert SUSE products\&.
-.RE
-.PP
-\fB\-X\fR
-.RS 4
-Autoexpand SUSE pattern and product provides into packages\&.
-.RE
-.SH "SEE ALSO"
-.sp
-rpms2solv(1)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/rpmdb2solv.txt b/libsolv-0.6.15/doc/rpmdb2solv.txt
deleted file mode 100644 (file)
index 0c4585f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-rpmdb2solv(1)
-=============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-rpmdb2solv - convert the rpm database into a solv file
-
-Synopsis
---------
-*rpmdb2solv* ['OPTIONS'] ['REFFILE.solv']
-
-Description
------------
-The rpmdb2solv tool reads rpm's installed packages database
-and writes it in solv file format to standard output. You can
-make use of an old version of the database by specifying a
-'REFFILE.solv' file.
-
-*-o* 'OUTFILE'::
-Write the generated solv to 'OUTFILE' instead of standard output.
-
-*-P*::
-Print percentages as packages are being read in. The output
-format is like rpm's --percent option.
-
-*-r* 'ROOTDIR'::
-Use 'ROOTDIR' as root directory.
-
-*-k*::
-Read pubkeys from the rpm database instead of installed packages.
-Note that many distributions stopped storing pubkeys in the
-database but use a directory like */var/lib/rpm/pubkeys*
-instead.
-
-*-A*::
-Also scan the */usr/share/appdata* for installed appdata files
-and create pseudo packages for each file.
-
-*-p* 'PRODDIR'::
-Also read SUSE product files from directory 'PRODDIR'. The
-standard directory is */etc/products.d*.
-
-*-n*::
-Do not read any packages from the rpm database. This is useful
-together with *-p* to only convert SUSE products.
-
-*-X*::
-Autoexpand SUSE pattern and product provides into packages.
-
-See Also
---------
-rpms2solv(1)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/rpmmd2solv.1 b/libsolv-0.6.15/doc/rpmmd2solv.1
deleted file mode 100644 (file)
index 2d8e245..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-'\" t
-.\"     Title: rpmmd2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "RPMMD2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-rpmmd2solv \- convert files in rpm\-md format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBrpmmd2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The rpmmd2solv tool reads rpm\-md xml data from stdin, and writes it as solv file to standard output\&. It understands the \fBprimary\fR, \fBfilelist\fR, \fBother\fR, and \fBsusedata\fR format\&.
-.PP
-\fB\-X\fR
-.RS 4
-Autoexpand SUSE pattern and product provides into packages\&.
-.RE
-.SH "SEE ALSO"
-.sp
-repomdxml2solv(1), mergesolv(1), createrepo(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/rpmmd2solv.txt b/libsolv-0.6.15/doc/rpmmd2solv.txt
deleted file mode 100644 (file)
index c72ccc9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-rpmmd2solv(1)
-=============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-rpmmd2solv - convert files in rpm-md format into a solv file
-
-Synopsis
---------
-*rpmmd2solv* ['OPTIONS']
-
-Description
------------
-The rpmmd2solv tool reads rpm-md xml data from stdin, and writes
-it as solv file to standard output. It understands the *primary*,
-*filelist*, *other*, and *susedata* format.
-
-*-X*::
-Autoexpand SUSE pattern and product provides into packages.
-
-See Also
---------
-repomdxml2solv(1), mergesolv(1), createrepo(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/rpms2solv.1 b/libsolv-0.6.15/doc/rpms2solv.1
deleted file mode 100644 (file)
index e67c6ef..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-'\" t
-.\"     Title: rpms2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "RPMS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-rpms2solv \- convert one or more rpms into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBrpms2solv\fR [\fIOPTIONS\fR] \fIRPM1\&.rpm\fR \&...
-.SH "DESCRIPTION"
-.sp
-The rpms2solv tool converts the header data from one or more rpms into the solv file written to standard output\&.
-.PP
-\fB\-m\fR \fIMANIFESTFILE\fR
-.RS 4
-Read the rpm file names from the specified
-\fIMANIFESTFILE\fR\&. You can use
-\fB\-\fR
-to read the manifest from standard input\&.
-.RE
-.PP
-\fB\-0\fR
-.RS 4
-Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the
-\fB\-print0\fR
-option in
-\fBfind\fR\&.
-.RE
-.PP
-\fB\-F\fR
-.RS 4
-Do not put all files from the headers into the file list, but instead use the filtering also found in
-\fBcreaterepo\fR\&.
-.RE
-.PP
-\fB\-k\fR
-.RS 4
-Read pubkeys instead of rpms\&.
-.RE
-.PP
-\fB\-K\fR
-.RS 4
-Read pubkey keyrings instead of rpms\&.
-.RE
-.PP
-\fB\-X\fR
-.RS 4
-Autoexpand SUSE pattern and product provides into packages\&.
-.RE
-.SH "SEE ALSO"
-.sp
-rpmdb2solv(1)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/rpms2solv.txt b/libsolv-0.6.15/doc/rpms2solv.txt
deleted file mode 100644 (file)
index 244dffb..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-rpms2solv(1)
-============
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-rpms2solv - convert one or more rpms into a solv file
-
-Synopsis
---------
-*rpms2solv* ['OPTIONS'] 'RPM1.rpm' ...
-
-Description
------------
-The rpms2solv tool converts the header data from one or more
-rpms into the solv file written to standard output.
-
-*-m* 'MANIFESTFILE'::
-Read the rpm file names from the specified 'MANIFESTFILE'. You can
-use *-* to read the manifest from standard input.
-
-*-0*::
-Use a null byte as line terminator for manifest files instead of
-a newline. This is useful if the file names can contain newlines.
-See also the *-print0* option in *find*.
-
-*-F*::
-Do not put all files from the headers into the file list, but
-instead use the filtering also found in *createrepo*.
-
-*-k*::
-Read pubkeys instead of rpms.
-
-*-K*::
-Read pubkey keyrings instead of rpms.
-
-*-X*::
-Autoexpand SUSE pattern and product provides into packages.
-
-See Also
---------
-rpmdb2solv(1)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/susetags2solv.1 b/libsolv-0.6.15/doc/susetags2solv.1
deleted file mode 100644 (file)
index 9b07094..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-'\" t
-.\"     Title: susetags2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "SUSETAGS2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-susetags2solv \- convert the susetags repository format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBsusetags2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The susetags format is most as repository format on most products created by SUSE\&. The susetags2solv reads data from standard input, converts the format into a solv file, and writes it to standard output\&.
-.PP
-\fB\-c\fR \fICONTENTFILE\fR
-.RS 4
-Also parse the specified content file containing meta information about the repository\&.
-.RE
-.PP
-\fB\-q\fR \fIWHAT\fR
-.RS 4
-Data query mode: instead of writing a solv file, select the
-\fIWHAT\fR
-element in the input data and write it to standard output\&. An example for
-\fIWHAT\fR
-is
-\fBdefaultvendor\fR
-to get a default vendor for the repository\&.
-.RE
-.PP
-\fB\-M\fR \fIMERGEFILE\&.solv\fR
-.RS 4
-Merge the content of the specified solv file into the output\&.
-.RE
-.PP
-\fB\-X\fR
-.RS 4
-Autoexpand SUSE pattern and product provides into packages\&.
-.RE
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/susetags2solv.txt b/libsolv-0.6.15/doc/susetags2solv.txt
deleted file mode 100644 (file)
index 9a2e2f1..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-susetags2solv(1)
-================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-susetags2solv - convert the susetags repository format into a solv file
-
-Synopsis
---------
-*susetags2solv* ['OPTIONS']
-
-Description
------------
-The susetags format is most as repository format on most products
-created by SUSE. The susetags2solv reads data from standard input,
-converts the format into a solv file, and writes it to standard output.
-
-*-c* 'CONTENTFILE'::
-Also parse the specified content file containing meta information
-about the repository.
-
-*-q* 'WHAT'::
-Data query mode: instead of writing a solv file, select the
-'WHAT' element in the input data and write it to standard output.
-An example for 'WHAT' is *defaultvendor* to get a default vendor for
-the repository.
-
-*-M* 'MERGEFILE.solv'::
-Merge the content of the specified solv file into the output.
-
-*-X*::
-Autoexpand SUSE pattern and product provides into packages.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/testsolv.1 b/libsolv-0.6.15/doc/testsolv.1
deleted file mode 100644 (file)
index 0e71874..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-'\" t
-.\"     Title: testsolv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "TESTSOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-testsolv \- run a libsolv testcase through the solver
-.SH "SYNOPSIS"
-.sp
-\fBtestsolv\fR [\fIOPTIONS\fR] \fITESTCASE\fR
-.SH "DESCRIPTION"
-.sp
-The testsolv tools can be used to run a testcase\&. Testcases can either be manually created to test specific features, or they can be written by libsolv\(cqs testcase_write function\&. This is useful to evaluate bug reports about the solver\&.
-.PP
-\fB\-v\fR
-.RS 4
-Increase the debug level of the solver\&. This option can be specified multiple times to further increase the amount of debug data\&.
-.RE
-.PP
-\fB\-r\fR
-.RS 4
-Write the output in testcase format instead of human readable text\&. The output can then be used in the result section of the test case\&. If the
-\fB\-r\fR
-option is given twice, the output is formated for verbatim inclusion\&.
-.RE
-.PP
-\fB\-l\fR \fIPKGSPEC\fR
-.RS 4
-Instead of running the solver, list packages in the repositories\&.
-.RE
-.PP
-\fB\-s\fR \fISOLUTIONSPEC\fR
-.RS 4
-This is used in the solver test suite to test the calculated solutions to encountered problems\&.
-.RE
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/testsolv.txt b/libsolv-0.6.15/doc/testsolv.txt
deleted file mode 100644 (file)
index dc3a34e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-testsolv(1)
-===========
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-testsolv - run a libsolv testcase through the solver
-
-Synopsis
---------
-*testsolv* ['OPTIONS'] 'TESTCASE'
-
-Description
------------
-The testsolv tools can be used to run a testcase. Testcases can
-either be manually created to test specific features, or they
-can be written by libsolv's testcase_write function. This is useful
-to evaluate bug reports about the solver.
-
-*-v*::
-Increase the debug level of the solver. This option can be specified
-multiple times to further increase the amount of debug data.
-
-*-r*::
-Write the output in testcase format instead of human readable text.
-The output can then be used in the result section of the test case.
-If the *-r* option is given twice, the output is formated for
-verbatim inclusion.
-
-*-l* 'PKGSPEC'::
-Instead of running the solver, list packages in the repositories.
-
-*-s* 'SOLUTIONSPEC'::
-This is used in the solver test suite to test the calculated solutions
-to encountered problems.
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/doc/updateinfoxml2solv.1 b/libsolv-0.6.15/doc/updateinfoxml2solv.1
deleted file mode 100644 (file)
index 20ab3ad..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-'\" t
-.\"     Title: updateinfoxml2solv
-.\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 08/26/2015
-.\"    Manual: LIBSOLV
-.\"    Source: libsolv
-.\"  Language: English
-.\"
-.TH "UPDATEINFOXML2SOLV" "1" "08/26/2015" "libsolv" "LIBSOLV"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-updateinfoxml2solv \- convert rpm\-md\*(Aqs updateinfo\&.xml format into a solv file
-.SH "SYNOPSIS"
-.sp
-\fBupdateinfoxml2solv\fR [\fIOPTIONS\fR]
-.SH "DESCRIPTION"
-.sp
-The updateinfoxml2solv tool reads rpm\-md\(cqs updateinfo xml data from stdin, and writes it as solv file to standard output\&. Update elements are converted into special \fBpatch:\fR pseudo packages\&.
-.SH "SEE ALSO"
-.sp
-mergesolv(1), createrepo(8)
-.SH "AUTHOR"
-.sp
-Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.6.15/doc/updateinfoxml2solv.txt b/libsolv-0.6.15/doc/updateinfoxml2solv.txt
deleted file mode 100644 (file)
index 7e7c5fc..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-updateinfoxml2solv(1)
-=====================
-:man manual: LIBSOLV
-:man source: libsolv
-
-
-Name
-----
-updateinfoxml2solv - convert rpm-md's updateinfo.xml format into a solv file
-
-Synopsis
---------
-*updateinfoxml2solv* ['OPTIONS']
-
-Description
------------
-The updateinfoxml2solv tool reads rpm-md's updateinfo xml data from stdin,
-and writes it as solv file to standard output. Update elements are converted
-into special *patch:* pseudo packages.
-
-See Also
---------
-mergesolv(1), createrepo(8)
-
-Author
-------
-Michael Schroeder <mls@suse.de>
diff --git a/libsolv-0.6.15/examples/CMakeLists.txt b/libsolv-0.6.15/examples/CMakeLists.txt
deleted file mode 100644 (file)
index 703796c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-IF (SUSE OR FEDORA OR DEBIAN OR MANDRIVA OR MAGEIA)
-
-ADD_SUBDIRECTORY (solv)
-
-ENDIF (SUSE OR FEDORA OR DEBIAN OR MANDRIVA OR MAGEIA)
diff --git a/libsolv-0.6.15/examples/p5solv b/libsolv-0.6.15/examples/p5solv
deleted file mode 100755 (executable)
index 0a1dbb0..0000000
+++ /dev/null
@@ -1,749 +0,0 @@
-#!/usr/bin/perl -w
-
-use POSIX;
-use Fcntl;
-use Config::IniFiles;
-use Data::Dumper;
-use solv;
-use Devel::Peek;
-use FileHandle;
-use File::Temp ();
-use strict;
-
-package Repo::generic;
-
-sub new {
-  my ($class, $alias, $type, $attr) = @_;
-  my $r = { %{$attr || {}} };
-  $r->{alias} = $alias;
-  $r->{type} = $type;
-  return bless $r, $class;
-}
-
-sub calc_cookie_fp {
-  my ($self, $fp) = @_;
-  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
-  $chksum->add("1.1");
-  $chksum->add_fp($fp);
-  return $chksum->raw();
-}
-
-sub calc_cookie_file {
-  my ($self, $filename) = @_;
-  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
-  $chksum->add("1.1");
-  $chksum->add_stat($filename);
-  return $chksum->raw();
-}
-
-sub calc_cookie_ext {
-  my ($self, $f, $cookie) = @_;
-  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
-  $chksum->add("1.1");
-  $chksum->add($cookie);
-  $chksum->add_fstat(fileno($f));
-  return $chksum->raw();
-}
-
-sub cachepath {
-  my ($self, $ext) = @_;
-  my $path = $self->{alias};
-  $path =~ s/^\./_/s;
-  $path .= $ext ? "_$ext.solvx" : '.solv';
-  $path =~ s!/!_!gs;
-  return "/var/cache/solv/$path";
-}
-
-sub load {
-  my ($self, $pool) = @_;
-  $self->{handle} = $pool->add_repo($self->{alias});
-  $self->{handle}->{appdata} = $self;
-  $self->{handle}->{priority} = 99 - $self->{priority};
-  my $dorefresh = $self->{autorefresh};
-  if ($dorefresh) {
-    my @s = stat($self->cachepath());
-    $dorefresh = 0 if @s && ($self->{metadata_expire} == -1 || time() - $s[9] < $self->{metadata_expire});
-  }
-  $self->{cookie} = '';
-  $self->{extcookie} = '';
-  if (!$dorefresh && $self->usecachedrepo()) {
-    print "repo: '$self->{alias}' cached\n";
-    return 1;
-  }
-  return 0;
-}
-
-sub load_ext {
-  return 0;
-}
-
-sub download {
-  my ($self, $file, $uncompress, $chksum, $markincomplete) = @_;
-  if (!$self->{baseurl}) {
-    print "$self->{alias}: no baseurl\n";
-    return undef;
-  }
-  my $url = $self->{baseurl};
-  $url =~ s!/$!!;
-  $url .= "/$file";
-  open(my $f, '+>', undef) || die;
-  fcntl($f, Fcntl::F_SETFD, 0);                # turn off CLOEXEC
-  my $st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" . fileno($f), '--', $url);
-  if (POSIX::lseek(fileno($f), 0, POSIX::SEEK_END) == 0 && ($st == 0 || !$chksum)) {
-    return undef;
-  }
-  POSIX::lseek(fileno($f), 0, POSIX::SEEK_SET);
-  if ($st) {
-    print "$file: download error #$st\n";
-    $self->{incomplete} = 1 if $markincomplete;
-    return undef;
-  }
-  if ($chksum) {
-    my $fchksum = solv::Chksum->new($chksum->{type});
-    $fchksum->add_fd(fileno($f));
-    if ($fchksum != $chksum) {
-      print "$file: checksum error\n";
-      $self->{incomplete} = 1 if $markincomplete;
-      return undef;
-    }
-  }
-  if ($uncompress) {
-    return solv::xfopen_fd($file, fileno($f));
-  } else {
-    return solv::xfopen_fd(undef, fileno($f));
-  }
-}
-
-sub usecachedrepo {
-  my ($self, $ext, $mark) = @_;
-  my $cookie = $ext ? $self->{extcookie} : $self->{cookie};
-  my $cachepath = $self->cachepath($ext);
-  my $fextcookie;
-  if (sysopen(my $f, $cachepath, POSIX::O_RDONLY)) {
-    sysseek($f, -32, Fcntl::SEEK_END);
-    my $fcookie = '';
-    return undef if sysread($f, $fcookie, 32) != 32;
-    return undef if $cookie && $fcookie ne $cookie;
-    if ($self->{type} ne 'system' && !$ext) {
-      sysseek($f, -32 * 2, Fcntl::SEEK_END);
-      return undef if sysread($f, $fextcookie, 32) != 32;
-    }
-    sysseek($f, 0, Fcntl::SEEK_SET);
-    my $fd = solv::xfopen_fd(undef, fileno($f));
-    my $flags = $ext ? $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES : 0;
-    $flags |= $solv::Repo::REPO_LOCALPOOL if $ext && $ext ne 'DL';
-    if (!$self->{handle}->add_solv($fd, $flags)) {
-      return undef;
-    }
-    $self->{cookie} = $fcookie unless $ext;
-    $self->{extcookie} = $fextcookie if $fextcookie;
-    utime undef, undef, $f if $mark;
-    return 1;
-  }
-  return undef;
-}
-
-sub writecachedrepo {
-  my ($self, $ext, $repodata) = @_;
-  return if $self->{incomplete};
-  mkdir("/var/cache/solv", 0755) unless -d "/var/cache/solv";
-  my ($f, $tmpname);
-  eval {
-    ($f, $tmpname) = File::Temp::tempfile(".newsolv-XXXXXX", 'DIR' => '/var/cache/solv');
-  };
-  return unless $f;
-  chmod 0444, $f;
-  my $ff = solv::xfopen_fd(undef, fileno($f));
-  if (!$repodata) {
-    $self->{handle}->write($ff);
-  } elsif ($ext) {
-    $repodata->write($ff);
-  } else {
-     $self->{handle}->write_first_repodata($ff);
-  }
-  undef $ff;   # also flushes
-  if ($self->{type} ne 'system' && !$ext) {
-    $self->{extcookie} ||= $self->calc_cookie_ext($f, $self->{cookie});
-    syswrite($f, $self->{extcookie});
-  }
-  syswrite($f, $ext ? $self->{extcookie} : $self->{cookie});
-  close($f);
-  if ($self->{handle}->iscontiguous()) {
-    $f = solv::xfopen($tmpname);
-    if ($f) {
-      if (!$ext) {
-       $self->{handle}->empty();
-       die("internal error, cannot reload solv file\n") unless $self->{handle}->add_solv($f, $repodata ? 0 : $solv::Repo::SOLV_ADD_NO_STUBS);
-      } else {
-       $repodata->extend_to_repo();
-       my $flags = $solv::Repo::REPO_EXTEND_SOLVABLES;
-       $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL';
-       $repodata->add_solv($f, $flags);
-      }
-    }
-  }
-  rename($tmpname, $self->cachepath($ext));
-}
-
-sub packagespath {
-  my ($self) = @_;
-  return '';
-}
-
-my %langtags = (
-  $solv::SOLVABLE_SUMMARY     => $solv::REPOKEY_TYPE_STR,
-  $solv::SOLVABLE_DESCRIPTION => $solv::REPOKEY_TYPE_STR,
-  $solv::SOLVABLE_EULA        => $solv::REPOKEY_TYPE_STR,
-  $solv::SOLVABLE_MESSAGEINS  => $solv::REPOKEY_TYPE_STR,
-  $solv::SOLVABLE_MESSAGEDEL  => $solv::REPOKEY_TYPE_STR,
-  $solv::SOLVABLE_CATEGORY    => $solv::REPOKEY_TYPE_ID,
-);
-
-sub add_ext_keys {
-  my ($self, $ext, $repodata, $handle) = @_;
-  if ($ext eq 'DL') {
-    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO);
-    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY);
-  } elsif ($ext eq 'DU') {
-    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_DISKUSAGE);
-    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRNUMNUMARRAY);
-  } elsif ($ext eq 'FL') {
-    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST);
-    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY);
-  } else {
-    for my $langid (sort { $a <=> $b } keys %langtags) {
-      $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $self->{handle}->{pool}->id2langid($langid, $ext, 1));
-      $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $langtags{$langid});
-    }
-  }
-}
-
-package Repo::rpmmd;
-
-our @ISA = ('Repo::generic');
-
-sub find {
-  my ($self, $what) = @_;
-  my $di = $self->{handle}->Dataiterator_meta($solv::REPOSITORY_REPOMD_TYPE, $what, $solv::Dataiterator::SEARCH_STRING);
-  $di->prepend_keyname($solv::REPOSITORY_REPOMD);
-  for my $d (@$di) {
-    my $dp = $d->parentpos();
-    my $filename = $dp->lookup_str($solv::REPOSITORY_REPOMD_LOCATION);
-    next unless $filename;
-    my $chksum = $dp->lookup_checksum($solv::REPOSITORY_REPOMD_CHECKSUM);
-    if (!$chksum) {
-      print "no $filename file checksum!\n";
-      return (undef, undef);
-    }
-    return ($filename, $chksum);
-  }
-  return (undef, undef);
-}
-
-sub add_ext {
-  my ($self, $repodata, $what, $ext) = @_;
-  my ($filename, $chksum) = $self->find($what);
-  ($filename, $chksum) = $self->find('prestodelta') if !$filename && $what eq 'deltainfo';
-  return unless $filename;
-  my $handle = $repodata->new_handle();
-  $repodata->set_poolstr($handle, $solv::REPOSITORY_REPOMD_TYPE, $what);
-  $repodata->set_str($handle, $solv::REPOSITORY_REPOMD_LOCATION, $filename);
-  $repodata->set_checksum($handle, $solv::REPOSITORY_REPOMD_CHECKSUM, $chksum);
-  $self->add_ext_keys($ext, $repodata, $handle);
-  $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle);
-}
-
-sub add_exts {
-  my ($self) = @_;
-  my $repodata = $self->{handle}->add_repodata(0);
-  $self->add_ext($repodata, 'deltainfo', 'DL');
-  $self->add_ext($repodata, 'filelists', 'FL');
-  $repodata->internalize();
-}
-
-sub load_ext {
-  my ($self, $repodata) = @_;
-  my $repomdtype = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_TYPE);
-  my $ext;
-  if ($repomdtype eq 'filelists') {
-    $ext = 'FL';
-  } elsif ($repomdtype eq 'deltainfo') {
-    $ext = 'DL';
-  } else {
-    return 0;
-  }
-  print("[$self->{alias}:$ext: ");
-  STDOUT->flush();
-  if ($self->usecachedrepo($ext)) {
-    print "cached]\n";
-    return 1;
-  }
-  print "fetching]\n";
-  my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_LOCATION);
-  my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_CHECKSUM);
-  my $f = $self->download($filename, 1, $filechksum);
-  return 0 unless $f;
-  if ($ext eq 'FL') {
-    $self->{handle}->add_rpmmd($f, 'FL', $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES|$solv::Repo::REPO_LOCALPOOL);
-  } elsif ($ext eq 'DL') {
-    $self->{handle}->add_deltainfoxml($f, $solv::Repo::REPO_USE_LOADING);
-  }
-  $self->writecachedrepo($ext, $repodata);
-  return 1;
-}
-
-sub load {
-  my ($self, $pool) = @_;
-  return 1 if $self->Repo::generic::load($pool);
-  print "rpmmd repo '$self->{alias}': ";
-  STDOUT->flush();
-  my $f = $self->download("repodata/repomd.xml");
-  if (!$f) {
-    print "no repomd.xml file, skipped\n";
-    $self->{handle}->free(1);
-    delete $self->{handle};
-    return undef;
-  }
-  $self->{cookie} = $self->calc_cookie_fp($f);
-  if ($self->usecachedrepo(undef, 1)) {
-    print "cached\n";
-    return 1;
-  }
-  $self->{handle}->add_repomdxml($f, 0);
-  print "fetching\n";
-  my ($filename, $filechksum) = $self->find('primary');
-  if ($filename) {
-    $f = $self->download($filename, 1, $filechksum, 1);
-    if ($f) {
-      $self->{handle}->add_rpmmd($f, undef, 0);
-    }
-    return undef if $self->{incomplete};
-  }
-  ($filename, $filechksum) = $self->find('updateinfo');
-  if ($filename) {
-    $f = $self->download($filename, 1, $filechksum, 1);
-    if ($f) {
-      $self->{handle}->add_updateinfoxml($f, 0);
-    }
-  }
-  $self->add_exts();
-  $self->writecachedrepo();
-  $self->{handle}->create_stubs();
-  return 1;
-}
-
-package Repo::susetags;
-
-our @ISA = ('Repo::generic');
-
-sub find {
-  my ($self, $what) = @_;
-  
-  my $di = $self->{handle}->Dataiterator_meta($solv::SUSETAGS_FILE_NAME, $what, $solv::Dataiterator::SEARCH_STRING);
-  $di->prepend_keyname($solv::SUSETAGS_FILE);
-  for my $d (@$di) {
-    my $dp = $d->parentpos();
-    my $chksum = $dp->lookup_checksum($solv::SUSETAGS_FILE_CHECKSUM);
-    return ($what, $chksum);
-  }
-  return (undef, undef);
-}
-
-
-sub add_ext {
-  my ($self, $repodata, $what, $ext) = @_;
-  my ($filename, $chksum) = $self->find($what);
-  return unless $filename;
-  my $handle = $repodata->new_handle();
-  $repodata->set_str($handle, $solv::SUSETAGS_FILE_NAME, $filename);
-  $repodata->set_checksum($handle, $solv::SUSETAGS_FILE_CHECKSUM, $chksum);
-  $self->add_ext_keys($ext, $repodata, $handle);
-  $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle);
-}
-
-sub add_exts {
-  my ($self) = @_;
-  my $repodata = $self->{handle}->add_repodata(0);
-  my $di = $self->{handle}->Dataiterator_meta($solv::SUSETAGS_FILE_NAME, undef, 0);
-  $di->prepend_keyname($solv::SUSETAGS_FILE);
-  for my $d (@$di) {
-    my $filename = $d->str();
-    next unless $filename && $filename =~ /^packages\.(..)(?:\..*)$/;
-    next if $1 eq 'en' || $1 eq 'gz';
-    $self->add_ext($repodata, $filename, $1);
-  }
-  $repodata->internalize();
-}
-
-sub load_ext {
-  my ($self, $repodata) = @_;
-  my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_FILE_NAME);
-  my $ext = substr($filename, 9, 2);
-  print("[$self->{alias}:$ext: ");
-  STDOUT->flush();
-  if ($self->usecachedrepo($ext)) {
-    print "cached]\n";
-    return 1;
-  }
-  print "fetching]\n";
-  my $defvendorid = $self->{handle}->{meta}->lookup_id($solv::SUSETAGS_DEFAULTVENDOR);
-  my $descrdir = $self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; 
-  my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::SUSETAGS_FILE_CHECKSUM);
-  my $f = $self->download("$descrdir/$filename", 1, $filechksum);
-  return 0 unless $f;
-  my $flags = $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES;
-  $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL';
-  $self->{handle}->add_susetags($f, $defvendorid, $ext, $flags);
-  $self->writecachedrepo($ext, $repodata);
-  return 1;
-}
-
-sub load {
-  my ($self, $pool) = @_;
-  return 1 if $self->Repo::generic::load($pool);
-  print "susetags repo '$self->{alias}': ";
-  STDOUT->flush();
-  my $f = $self->download("content");
-  if (!$f) {
-    print "no content file, skipped\n";
-    $self->{handle}->free(1);
-    delete $self->{handle};
-    return undef;
-  }
-  $self->{cookie} = $self->calc_cookie_fp($f);
-  if ($self->usecachedrepo(undef, 1)) {
-    print "cached\n";
-    return 1;
-  }
-  $self->{handle}->add_content($f, 0);
-  print "fetching\n";
-  my $defvendorid = $self->{handle}->{meta}->lookup_id($solv::SUSETAGS_DEFAULTVENDOR);
-  my $descrdir = $self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; 
-  my ($filename, $filechksum) = $self->find('packages.gz');
-  ($filename, $filechksum) = $self->find('packages') unless $filename;
-  if ($filename) {
-    $f = $self->download("$descrdir/$filename", 1, $filechksum, 1);
-    if ($f) {
-      $self->{handle}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::SUSETAGS_RECORD_SHARES);
-      ($filename, $filechksum) = $self->find('packages.en.gz');
-      ($filename, $filechksum) = $self->find('packages.en') unless $filename;
-      if ($filename) {
-       $f = $self->download("$descrdir/$filename", 1, $filechksum, 1);
-       if ($f) {
-         $self->{handle}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::REPO_REUSE_REPODATA|$solv::Repo::REPO_EXTEND_SOLVABLES);
-       }
-      }
-      $self->{handle}->internalize();
-    }
-  }
-  $self->add_exts();
-  $self->writecachedrepo();
-  $self->{handle}->create_stubs();
-  return undef;
-}
-
-sub packagespath {
-  my ($self) = @_;
-  return ($self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DATADIR) || 'suse') . '/';
-}
-
-package Repo::unknown;
-
-our @ISA = ('Repo::generic');
-
-sub load {
-  my ($self) = @_;
-  print "unsupported repo '$self->{alias}': skipped\n";
-  return 0;
-}
-
-package Repo::system;
-
-our @ISA = ('Repo::generic');
-
-sub load {
-  my ($self, $pool) = @_;
-
-  $self->{handle} = $pool->add_repo($self->{alias});
-  $self->{handle}->{appdata} = $self;
-  $pool->{installed} = $self->{handle};
-  print "rpm database: ";
-  $self->{cookie} = $self->calc_cookie_file('/var/lib/rpm/Packages');
-  if ($self->usecachedrepo()) {
-    print "cached\n";
-    return 1;
-  }
-  print "reading\n";
-  if (defined(&solv::Repo::add_products)) {
-    $self->{handle}->add_products("/etc/products.d", $solv::Repo::REPO_NO_INTERNALIZE);
-  }
-  my $f = solv::xfopen($self->cachepath());
-  $self->{handle}->add_rpmdb_reffp($f, $solv::Repo::REPO_REUSE_REPODATA);
-  $self->writecachedrepo();
-  return 1;
-}
-
-package main;
-
-sub load_stub {
-  my ($repodata) = @_;
-  my $repo = $repodata->{repo}->{appdata};
-  return $repo ? $repo->load_ext($repodata) : 0;
-}
-
-die("Usage: p5solv COMMAND [ARGS]\n") unless @ARGV;
-my $cmd = shift @ARGV;
-my %cmdabbrev = ( 'ls' => 'list', 'in' => 'install', 'rm' => 'erase',
-                  've' => 'verify', 'se' => 'search' );
-$cmd = $cmdabbrev{$cmd} if $cmdabbrev{$cmd};
-
-my %cmdactionmap = (
-  'install' => $solv::Job::SOLVER_INSTALL,
-  'erase'   => $solv::Job::SOLVER_ERASE,
-  'up'      => $solv::Job::SOLVER_UPDATE,
-  'dup'     => $solv::Job::SOLVER_DISTUPGRADE,
-  'verify'  => $solv::Job::SOLVER_VERIFY,
-  'list'    => 0,  
-  'info'    => 0,
-);
-
-my @repos;
-my @reposdirs;
-if (-d '/etc/zypp/repos.d') {
-  @reposdirs = ( '/etc/zypp/repos.d' );
-} else {
-  @reposdirs = ( '/etc/yum/repos.d' );
-}
-for my $reposdir (@reposdirs) {
-  next unless -d $reposdir;
-  my $dir;
-  next unless opendir($dir, $reposdir);
-  for my $reponame (sort(grep {/\.repo$/} readdir($dir))) {
-    my $cfg = new Config::IniFiles('-file' => "$reposdir/$reponame");
-    for my $alias ($cfg->Sections()) {
-      my $repoattr = {'alias' => $alias, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900};
-      for my $p ($cfg->Parameters($alias)) {
-       $repoattr->{$p} = $cfg->val($alias, $p);
-      }
-      my $repo;
-      if ($repoattr->{type} eq 'rpm-md') {
-       $repo = Repo::rpmmd->new($alias, 'repomd', $repoattr);
-      } elsif ($repoattr->{type} eq 'yast2') {
-       $repo = Repo::susetags->new($alias, 'susetags', $repoattr);
-      } else {
-       $repo = Repo::unknown->new($alias, 'unknown', $repoattr);
-      }
-      push @repos, $repo;
-    }
-  }
-}
-
-my $pool = solv::Pool->new();
-$pool->setarch();
-$pool->set_loadcallback(\&load_stub);
-
-my $sysrepo = Repo::system->new('@System', 'system');
-$sysrepo->load($pool);
-for my $repo (@repos) {
-  $repo->load($pool) if $repo->{enabled};
-}
-
-if ($cmd eq 'search') {
-  $pool->createwhatprovides();
-  my $sel = $pool->Selection();
-  my $di = $pool->Dataiterator($solv::SOLVABLE_NAME, $ARGV[0], $solv::Dataiterator::SEARCH_SUBSTRING | $solv::Dataiterator::SEARCH_NOCASE);
-  for my $d (@$di) {
-    $sel->add_raw($solv::Job::SOLVER_SOLVABLE, $d->{solvid});
-  }
-  for my $s ($sel->solvables()) {
-    print "- ".$s->str()." [$s->{repo}->{name}]: ".$s->lookup_str($solv::SOLVABLE_SUMMARY)."\n";
-  }
-  exit(0);
-}
-
-die("unknown command '$cmd'\n") unless defined $cmdactionmap{$cmd};
-
-$pool->addfileprovides();
-$pool->createwhatprovides();
-
-my @jobs;
-for my $arg (@ARGV) {
-  my $flags = $solv::Selection::SELECTION_NAME | $solv::Selection::SELECTION_PROVIDES | $solv::Selection::SELECTION_GLOB;
-  $flags |= $solv::Selection::SELECTION_CANON | $solv::Selection::SELECTION_DOTARCH | $solv::Selection::SELECTION_REL;
-  if ($arg =~ m!^/!) {
-    $flags |= $solv::Selection::SELECTION_FILELIST;
-    $flags |= $solv::Selection::SELECTION_INSTALLED_ONLY if $cmd eq 'erase';
-  }
-  my $sel = $pool->select($arg, $flags);
-  if ($sel->isempty()) {
-    $sel = $pool->select($arg, $flags | $solv::Selection::SELECTION_NOCASE);
-    print "[ignoring case for '$arg']\n" unless $sel->isempty();
-  }
-  die("nothing matches '$arg'\n") if $sel->isempty();
-  print "[using file list match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_FILELIST;
-  print "[using capability match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_PROVIDES;
-  push @jobs, $sel->jobs($cmdactionmap{$cmd});
-}
-
-if (!@jobs && ($cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify')) {
-  my $sel = $pool->Selection_all();
-  push @jobs, $sel->jobs($cmdactionmap{$cmd});
-}
-
-die("no package matched.\n") unless @jobs;
-
-if ($cmd eq 'list' || $cmd eq 'info') {
-  for my $job (@jobs) {
-    for my $s ($job->solvables()) {
-      if ($cmd eq 'info') {
-       printf "Name:        %s\n", $s->str();
-       printf "Repo:        %s\n", $s->{repo}->{name};
-       printf "Summary:     %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY);
-       my $str = $s->lookup_str($solv::SOLVABLE_URL);
-       printf "Url:         %s\n", $str if $str;
-       $str = $s->lookup_str($solv::SOLVABLE_LICENSE);
-       printf "License:     %s\n", $str if $str;
-       printf "Description:\n%s\n", $s->lookup_str($solv::SOLVABLE_DESCRIPTION);
-      } else {
-       printf "  - %s [%s]\n", $s->str(), $s->{repo}->{name};
-       printf "    %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY);
-      }
-    }
-  }
-  exit 0;
-}
-
-# up magic, turn into install if nothing matches
-for my $job (@jobs) {
-  $job->{how} ^= $solv::Job::SOLVER_UPDATE ^ $solv::Job::SOLVER_INSTALL if $cmd eq 'up' && $job->isemptyupdate();
-}
-
-my $solver = $pool->Solver();
-$solver->set_flag($solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1);
-$solver->set_flag($solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if $cmd eq 'erase';
-
-while (1) {
-  my @problems = $solver->solve(\@jobs);
-  last unless @problems;
-  for my $problem (@problems) {
-    print "Problem $problem->{id}/".@problems.":\n";
-    print $problem->str()."\n";
-    my @solutions = $problem->solutions();
-    for my $solution (@solutions) {
-      print "  Solution $solution->{id}:\n";
-      for my $element ($solution->elements(1)) {
-       print "  - ".$element->str()."\n";
-      }
-      print "\n";
-    }
-    my $sol;
-    while (1) {
-      print "Please choose a solution: ";
-      $sol = <STDIN>;
-      chomp $sol;
-      last if $sol eq 's' || $sol eq 'q' || ($sol =~ /^\d+$/ && $sol >= 1 && $sol <= @solutions);
-    }
-    next if $sol eq 's';
-    exit(1) if $sol eq 'q';
-    my $solution = $solutions[$sol - 1];
-    for my $element ($solution->elements()) {
-      my $newjob = $element->Job();
-      if ($element->{type} == $solv::Solver::SOLVER_SOLUTION_JOB) {
-       $jobs[$element->{jobidx}] = $newjob;
-      } else {
-       push @jobs, $newjob if $newjob && !grep {$_ == $newjob} @jobs;
-      }
-    }
-  }
-}
-
-my $trans = $solver->transaction();
-undef $solver;
-if ($trans->isempty()) {
-  print "Nothing to do.\n";
-  exit 0;
-}
-
-print "\nTransaction summary:\n\n";
-for my $c ($trans->classify($solv::Transaction::SOLVER_TRANSACTION_SHOW_OBSOLETES|$solv::Transaction::SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE)) {
-  if ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
-    print "$c->{count} erased packages:\n";
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_INSTALL) {
-    print "$c->{count} installed packages:\n";
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_REINSTALLED) {
-    print "$c->{count} reinstalled packages:\n";
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
-    print "$c->{count} downgraded packages:\n";
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_CHANGED) {
-    print "$c->{count} changed packages:\n";
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED) {
-    print "$c->{count} upgraded packages:\n";
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE) {
-    printf "$c->{count} vendor changes from '%s' to '%s':\n", $c->{fromstr}, $c->{tostr};
-  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE) {
-    printf "$c->{count} arch changes from '%s' to '%s':\n", $c->{fromstr}, $c->{tostr};
-  } else {
-    next;
-  }
-  for my $p ($c->solvables()) {
-    if ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED || $c->{type} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
-      my $other = $trans->othersolvable($p);
-      printf "  - %s -> %s\n", $p->str(), $other->str();
-    } else {
-      printf "  - %s\n", $p->str();
-    }
-  }
-  print "\n";
-}
-printf "install size change: %d K\n\n", $trans->calc_installsizechange();
-
-while (1) {
-  print("OK to continue (y/n)? ");
-  my $yn = <STDIN>;
-  chomp $yn;
-  last if $yn eq 'y';
-  exit(1) if $yn eq 'n' || $yn eq 'q';
-}
-
-my @newpkgs = $trans->newsolvables();
-my %newpkgsfps;
-if (@newpkgs) {
-  my $downloadsize = 0;
-  $downloadsize += $_->lookup_num($solv::SOLVABLE_DOWNLOADSIZE) for @newpkgs;
-  printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize / 1024;
-  for my $p (@newpkgs) {
-    my $repo = $p->{repo}->{appdata};
-    my ($location) = $p->lookup_location();
-    next unless $location;
-    $location = $repo->packagespath() . $location;
-    my $chksum = $p->lookup_checksum($solv::SOLVABLE_CHECKSUM);
-    my $f = $repo->download($location, 0, $chksum);
-    die("\n$repo->{alias}: $location not found in repository\n") unless $f;
-    $newpkgsfps{$p->{id}} = $f;
-    print ".";
-    STDOUT->flush();
-  }
-  print "\n";
-}
-
-print "Committing transaction:\n\n";
-$trans->order();
-for my $p ($trans->steps()) {
-  my $steptype = $trans->steptype($p, $solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY);
-  if ($steptype == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
-    print "erase ".$p->str()."\n";
-    next unless $p->lookup_num($solv::RPM_RPMDBID);
-    my $evr = $p->{evr};
-    $evr =~ s/^[0-9]+://;      # strip epoch
-    system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "$p->{name}-$evr.$p->{arch}") && die("rpm failed: $?\n");
-  } elsif ($steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL) {
-    print "install ".$p->str()."\n";
-    my $f = $newpkgsfps{$p->{id}};
-    my $mode = $steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i';
-    $f->cloexec(0);
-    system('rpm', $mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/".$f->fileno()) && die("rpm failed: $?\n");
-    delete $newpkgsfps{$p->{id}};
-  }
-}
-
-exit 0;
diff --git a/libsolv-0.6.15/examples/pysolv b/libsolv-0.6.15/examples/pysolv
deleted file mode 100755 (executable)
index 3d6ca07..0000000
+++ /dev/null
@@ -1,960 +0,0 @@
-#!/usr/bin/python
-
-#
-# Copyright (c) 2011, Novell Inc.
-#
-# This program is licensed under the BSD license, read LICENSE.BSD
-# for further information
-#
-
-# pysolv a little software installer demoing the sat solver library/bindings
-
-# things it does:
-# - understands globs for package names / dependencies
-# - understands .arch suffix
-# - repository data caching
-# - on demand loading of secondary repository data
-# - checksum verification
-# - deltarpm support
-# - installation of commandline packages
-#
-# things not yet ported:
-# - gpg verification
-# - file conflicts
-# - fastestmirror implementation
-#
-# things available in the library but missing from pysolv:
-# - vendor policy loading
-# - soft locks file handling
-# - multi version handling
-
-import sys
-import os
-import glob
-import solv
-import re
-import tempfile
-import time
-import subprocess
-import rpm
-from stat import *
-from iniparse import INIConfig
-from optparse import OptionParser
-
-#import gc
-#gc.set_debug(gc.DEBUG_LEAK)
-
-class repo_generic(dict):
-    def __init__(self, name, type, attribs = {}):
-        for k in attribs:
-            self[k] = attribs[k]
-        self.name = name
-        self.type = type
-
-    def calc_cookie_file(self, filename):
-        chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256)
-        chksum.add("1.1")
-        chksum.add_stat(filename)
-        return chksum.raw()
-
-    def calc_cookie_fp(self, fp):
-        chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256)
-        chksum.add("1.1");
-        chksum.add_fp(fp)
-        return chksum.raw()
-
-    def calc_cookie_ext(self, f, cookie):
-        chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256)
-        chksum.add("1.1");
-        chksum.add(cookie)
-        chksum.add_fstat(f.fileno())
-        return chksum.raw()
-
-    def cachepath(self, ext = None):
-        path = re.sub(r'^\.', '_', self.name)
-        if ext:
-            path += "_" + ext + ".solvx"
-        else:
-            path += ".solv"
-        return "/var/cache/solv/" + re.sub(r'[/]', '_', path)
-        
-    def load(self, pool):
-        self.handle = pool.add_repo(self.name)
-        self.handle.appdata = self
-        self.handle.priority = 99 - self['priority']
-        dorefresh = bool(int(self['autorefresh']))
-        if dorefresh:
-            try:
-                st = os.stat(self.cachepath())
-                if self['metadata_expire'] == -1 or time.time() - st[ST_MTIME] < self['metadata_expire']:
-                    dorefresh = False
-            except OSError:
-                pass
-        self['cookie'] = ''
-        self['extcookie'] = ''
-        if not dorefresh and self.usecachedrepo(None):
-            print("repo: '%s': cached" % self.name)
-            return True
-        return False
-
-    def load_ext(self, repodata):
-        return False
-
-    def setfromurls(self, urls):
-        if not urls:
-            return
-        url = urls[0]
-        print("[using mirror %s]" % re.sub(r'^(.*?/...*?)/.*$', r'\1', url))
-        self['baseurl'] = url
-
-    def setfrommetalink(self, metalink):
-        f = self.download(metalink, False, None)
-        if not f:
-            return None
-        f = os.fdopen(f.dup(), 'r')
-        urls = []
-        chksum = None
-        for l in f.readlines():
-            l = l.strip()
-            m = re.match(r'^<hash type="sha256">([0-9a-fA-F]{64})</hash>', l)
-            if m:
-                chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256, m.group(1))
-            m = re.match(r'^<url.*>(https?://.+)repodata/repomd.xml</url>', l)
-            if m:
-                urls.append(m.group(1))
-        if not urls:
-            chksum = None       # in case the metalink is about a different file
-        f.close()
-        self.setfromurls(urls)
-        return chksum
-        
-    def setfrommirrorlist(self, mirrorlist):
-        f = self.download(mirrorlist, False, None)
-        if not f:
-            return
-        f = os.fdopen(f.dup(), 'r')
-        urls = []
-        for l in f.readline():
-            l = l.strip()
-            if l[0:6] == 'http://' or l[0:7] == 'https://':
-                urls.append(l)
-        self.setfromurls(urls)
-        f.close()
-        
-    def download(self, file, uncompress, chksum, markincomplete=False):
-        url = None
-        if 'baseurl' not in self:
-            if 'metalink' in self:
-                if file != self['metalink']:
-                    metalinkchksum = self.setfrommetalink(self['metalink'])
-                    if file == 'repodata/repomd.xml' and metalinkchksum and not chksum:
-                        chksum = metalinkchksum
-                else:
-                    url = file
-            elif 'mirrorlist' in self:
-                if file != self['mirrorlist']:
-                    self.setfrommirrorlist(self['mirrorlist'])
-                else:
-                    url = file
-        if not url:
-            if 'baseurl' not in self:
-                print("%s: no baseurl" % self.name)
-                return None
-            url = re.sub(r'/$', '', self['baseurl']) + '/' + file
-        f = tempfile.TemporaryFile()
-        st = subprocess.call(['curl', '-f', '-s', '-L', url], stdout=f.fileno())
-        if os.lseek(f.fileno(), 0, os.SEEK_CUR) == 0 and (st == 0 or not chksum):
-            return None
-        os.lseek(f.fileno(), 0, os.SEEK_SET)
-        if st:
-            print("%s: download error %d" % (file, st))
-            if markincomplete:
-                self['incomplete'] = True
-            return None
-        if chksum:
-            fchksum = solv.Chksum(chksum.type)
-            if not fchksum:
-                print("%s: unknown checksum type" % file)
-                if markincomplete:
-                    self['incomplete'] = True
-                return None
-            fchksum.add_fd(f.fileno())
-            if fchksum != chksum:
-                print("%s: checksum mismatch" % file)
-                if markincomplete:
-                    self['incomplete'] = True
-                return None
-        if uncompress:
-            return solv.xfopen_fd(file, f.fileno())
-        return solv.xfopen_fd(None, f.fileno())
-
-    def usecachedrepo(self, ext, mark=False):
-        try: 
-            repopath = self.cachepath(ext)
-            f = open(repopath, 'rb')
-            f.seek(-32, os.SEEK_END)
-            fcookie = f.read(32)
-            if len(fcookie) != 32:
-                return False
-            if not ext:
-                cookie = self['cookie']
-            else:
-                cookie = self['extcookie']
-            if cookie and fcookie != cookie:
-                return False
-            if self.type != 'system' and not ext:
-                f.seek(-32 * 2, os.SEEK_END)
-                fextcookie = f.read(32)
-                if len(fextcookie) != 32:
-                    return False
-            f.seek(0)
-            f = solv.xfopen_fd('', f.fileno())
-            flags = 0
-            if ext:
-                flags = solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES
-                if ext != 'DL':
-                    flags |= solv.Repo.REPO_LOCALPOOL
-            if not self.handle.add_solv(f, flags):
-                return False
-            if self.type != 'system' and not ext:
-                self['cookie'] = fcookie
-                self['extcookie'] = fextcookie
-            if mark:
-                # no futimes in python?
-                try:
-                    os.utime(repopath, None)
-                except Exception:
-                    pass
-        except IOError:
-            return False
-        return True
-
-    def writecachedrepo(self, ext, repodata=None):
-        if 'incomplete' in self:
-            return
-        tmpname = None
-        try:
-            if not os.path.isdir("/var/cache/solv"):
-                os.mkdir("/var/cache/solv", 0o755)
-            (fd, tmpname) = tempfile.mkstemp(prefix='.newsolv-', dir='/var/cache/solv')
-            os.fchmod(fd, 0o444)
-            f = os.fdopen(fd, 'wb+')
-            f = solv.xfopen_fd(None, f.fileno())
-            if not repodata:
-                self.handle.write(f)
-            elif ext:
-                repodata.write(f)
-            else:       # rewrite_repos case, do not write stubs
-                self.handle.write_first_repodata(f)
-            f.flush()
-            if self.type != 'system' and not ext:
-                if not self['extcookie']:
-                    self['extcookie'] = self.calc_cookie_ext(f, self['cookie'])
-                f.write(self['extcookie'])
-            if not ext:
-                f.write(self['cookie'])
-            else:
-                f.write(self['extcookie'])
-            f.close
-            if self.handle.iscontiguous():
-                # switch to saved repo to activate paging and save memory
-                nf = solv.xfopen(tmpname)
-                if not ext:
-                    # main repo
-                    self.handle.empty()
-                    flags = solv.Repo.SOLV_ADD_NO_STUBS
-                    if repodata:
-                        flags = 0       # rewrite repos case, recreate stubs
-                    if not self.handle.add_solv(nf, flags):
-                        sys.exit("internal error, cannot reload solv file")
-                else:
-                    # extension repodata
-                    # need to extend to repo boundaries, as this is how
-                    # repodata.write() has written the data
-                    repodata.extend_to_repo()
-                    flags = solv.Repo.REPO_EXTEND_SOLVABLES
-                    if ext != 'DL':
-                        flags |= solv.Repo.REPO_LOCALPOOL
-                    repodata.add_solv(nf, flags)
-            os.rename(tmpname, self.cachepath(ext))
-        except (OSError, IOError):
-            if tmpname:
-                os.unlink(tmpname)
-
-    def updateaddedprovides(self, addedprovides):
-        if 'incomplete' in self:
-            return 
-        if not hasattr(self, 'handle'):
-            return 
-        if self.handle.isempty():
-            return
-        # make sure there's just one real repodata with extensions
-        repodata = self.handle.first_repodata()
-        if not repodata:
-            return
-        oldaddedprovides = repodata.lookup_idarray(solv.SOLVID_META, solv.REPOSITORY_ADDEDFILEPROVIDES)
-        if not set(addedprovides) <= set(oldaddedprovides):
-            for id in addedprovides:
-                repodata.add_idarray(solv.SOLVID_META, solv.REPOSITORY_ADDEDFILEPROVIDES, id)
-            repodata.internalize()
-            self.writecachedrepo(None, repodata)
-
-    def packagespath(self):
-        return ''
-
-    def add_ext_keys(self, ext, repodata, handle):
-        if ext == 'DL':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
-        elif ext == 'DU':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY)
-        elif ext == 'FL':
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
-            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
-        else:
-            for langtag, langtagtype in [
-                (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR),
-                (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID)
-            ]:
-                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1))
-                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype)
-        
-
-class repo_repomd(repo_generic):
-    def load(self, pool):
-        if super(repo_repomd, self).load(pool):
-            return True
-        sys.stdout.write("rpmmd repo '%s': " % self.name)
-        sys.stdout.flush()
-        f = self.download("repodata/repomd.xml", False, None, None)
-        if not f:
-            print("no repomd.xml file, skipped")
-            self.handle.free(True)
-            del self.handle
-            return False
-        self['cookie'] = self.calc_cookie_fp(f)
-        if self.usecachedrepo(None, True):
-            print("cached")
-            return True
-        self.handle.add_repomdxml(f, 0)
-        print("fetching")
-        (filename, filechksum) = self.find('primary')
-        if filename:
-            f = self.download(filename, True, filechksum, True)
-            if f:
-                self.handle.add_rpmmd(f, None, 0)
-            if 'incomplete' in self:
-                return False # hopeless, need good primary
-        (filename, filechksum) = self.find('updateinfo')
-        if filename:
-            f = self.download(filename, True, filechksum, True)
-            if f:
-                self.handle.add_updateinfoxml(f, 0)
-        self.add_exts()
-        self.writecachedrepo(None)
-        # must be called after writing the repo
-        self.handle.create_stubs()
-        return True
-
-    def find(self, what):
-        di = self.handle.Dataiterator_meta(solv.REPOSITORY_REPOMD_TYPE, what, solv.Dataiterator.SEARCH_STRING)
-        di.prepend_keyname(solv.REPOSITORY_REPOMD)
-        for d in di:
-            dp = d.parentpos()
-            filename = dp.lookup_str(solv.REPOSITORY_REPOMD_LOCATION)
-            chksum = dp.lookup_checksum(solv.REPOSITORY_REPOMD_CHECKSUM)
-            if filename and not chksum:
-                print("no %s file checksum!" % filename)
-                filename = None
-                chksum = None
-            if filename:
-                return (filename, chksum)
-        return (None, None)
-        
-    def add_ext(self, repodata, what, ext):
-        filename, chksum = self.find(what)
-        if not filename and what == 'deltainfo':
-            filename, chksum = self.find('prestodelta')
-        if not filename:
-            return
-        handle = repodata.new_handle()
-        repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what)
-        repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename)
-        repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
-        self.add_ext_keys(ext, repodata, handle)
-        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
-
-    def add_exts(self):
-        repodata = self.handle.add_repodata(0)
-        self.add_ext(repodata, 'deltainfo', 'DL')
-        self.add_ext(repodata, 'filelists', 'FL')
-        repodata.internalize()
-    
-    def load_ext(self, repodata):
-        repomdtype = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE)
-        if repomdtype == 'filelists':
-            ext = 'FL'
-        elif repomdtype == 'deltainfo':
-            ext = 'DL'
-        else:
-            return False
-        sys.stdout.write("[%s:%s: " % (self.name, ext))
-        if self.usecachedrepo(ext):
-            sys.stdout.write("cached]\n")
-            sys.stdout.flush()
-            return True
-        sys.stdout.write("fetching]\n")
-        sys.stdout.flush()
-        filename = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_LOCATION)
-        filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.REPOSITORY_REPOMD_CHECKSUM)
-        f = self.download(filename, True, filechksum)
-        if not f:
-            return False
-        if ext == 'FL':
-            self.handle.add_rpmmd(f, 'FL', solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES|solv.Repo.REPO_LOCALPOOL)
-        elif ext == 'DL':
-            self.handle.add_deltainfoxml(f, solv.Repo.REPO_USE_LOADING)
-        self.writecachedrepo(ext, repodata)
-        return True
-
-class repo_susetags(repo_generic):
-    def load(self, pool):
-        if super(repo_susetags, self).load(pool):
-            return True
-        sys.stdout.write("susetags repo '%s': " % self.name)
-        sys.stdout.flush()
-        f = self.download("content", False, None, None)
-        if not f:
-            print("no content file, skipped")
-            self.handle.free(True)
-            del self.handle
-            return False
-        self['cookie'] = self.calc_cookie_fp(f)
-        if self.usecachedrepo(None, True):
-            print("cached")
-            return True
-        self.handle.add_content(f, 0)
-        print("fetching")
-        defvendorid = self.handle.meta.lookup_id(solv.SUSETAGS_DEFAULTVENDOR)
-        descrdir = self.handle.meta.lookup_str(solv.SUSETAGS_DESCRDIR)
-        if not descrdir:
-            descrdir = "suse/setup/descr"
-        (filename, filechksum) = self.find('packages.gz')
-        if not filename:
-            (filename, filechksum) = self.find('packages')
-        if filename:
-            f = self.download(descrdir + '/' + filename, True, filechksum, True)
-            if f:
-                self.handle.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE|solv.Repo.SUSETAGS_RECORD_SHARES)
-                (filename, filechksum) = self.find('packages.en.gz')
-                if not filename:
-                    (filename, filechksum) = self.find('packages.en')
-                if filename:
-                    f = self.download(descrdir + '/' + filename, True, filechksum, True)
-                    if f:
-                        self.handle.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE|solv.Repo.REPO_REUSE_REPODATA|solv.Repo.REPO_EXTEND_SOLVABLES)
-                self.handle.internalize()
-        self.add_exts()
-        self.writecachedrepo(None)
-        # must be called after writing the repo
-        self.handle.create_stubs()
-        return True
-
-    def find(self, what):
-        di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, what, solv.Dataiterator.SEARCH_STRING)
-        di.prepend_keyname(solv.SUSETAGS_FILE)
-        for d in di:
-            dp = d.parentpos()
-            chksum = dp.lookup_checksum(solv.SUSETAGS_FILE_CHECKSUM)
-            return (what, chksum)
-        return (None, None)
-
-    def add_ext(self, repodata, what, ext):
-        (filename, chksum) = self.find(what)
-        if not filename:
-            return
-        handle = repodata.new_handle()
-        repodata.set_str(handle, solv.SUSETAGS_FILE_NAME, filename)
-        if chksum:
-            repodata.set_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum)
-        self.add_ext_keys(ext, repodata, handle)
-        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
-        
-    def add_exts(self):
-        repodata = self.handle.add_repodata(0)
-        di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, None, 0)
-        di.prepend_keyname(solv.SUSETAGS_FILE)
-        for d in di:
-            filename = d.str
-            if not filename:
-                continue
-            if filename[0:9] != "packages.":
-                continue
-            if len(filename) == 11 and filename != "packages.gz":
-                ext = filename[9:11]
-            elif filename[11:12] == ".":
-                ext = filename[9:11]
-            else:
-                continue
-            if ext == "en":
-                continue
-            self.add_ext(repodata, filename, ext)
-        repodata.internalize()
-
-    def load_ext(self, repodata):
-        filename = repodata.lookup_str(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME)
-        ext = filename[9:11]
-        sys.stdout.write("[%s:%s: " % (self.name, ext))
-        if self.usecachedrepo(ext):
-            sys.stdout.write("cached]\n")
-            sys.stdout.flush()
-            return True
-        sys.stdout.write("fetching]\n")
-        sys.stdout.flush()
-        defvendorid = self.handle.meta.lookup_id(solv.SUSETAGS_DEFAULTVENDOR)
-        descrdir = self.handle.meta.lookup_str(solv.SUSETAGS_DESCRDIR)
-        if not descrdir:
-            descrdir = "suse/setup/descr"
-        filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.SUSETAGS_FILE_CHECKSUM)
-        f = self.download(descrdir + '/' + filename, True, filechksum)
-        if not f:
-            return False
-        flags = solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES
-        if ext != 'DL':
-            flags |= solv.Repo.REPO_LOCALPOOL
-        self.handle.add_susetags(f, defvendorid, ext, flags)
-        self.writecachedrepo(ext, repodata)
-        return True
-
-    def packagespath(self):
-        datadir = repo.handle.meta.lookup_str(solv.SUSETAGS_DATADIR)
-        if not datadir:
-            datadir = 'suse'
-        return datadir + '/'
-
-class repo_unknown(repo_generic):
-    def load(self, pool):
-        print("unsupported repo '%s': skipped" % self.name)
-        return False
-
-class repo_system(repo_generic):
-    def load(self, pool):
-        self.handle = pool.add_repo(self.name)
-        self.handle.appdata = self
-        pool.installed = self.handle
-        sys.stdout.write("rpm database: ")
-        self['cookie'] = self.calc_cookie_file("/var/lib/rpm/Packages")
-        if self.usecachedrepo(None):
-            print("cached")
-            return True
-        print("reading")
-        if hasattr(self.handle.__class__, 'add_products'):
-            self.handle.add_products("/etc/products.d", solv.Repo.REPO_NO_INTERNALIZE)
-        f = solv.xfopen(self.cachepath())
-        self.handle.add_rpmdb_reffp(f, solv.Repo.REPO_REUSE_REPODATA)
-        self.writecachedrepo(None)
-        return True
-
-class repo_cmdline(repo_generic):
-    def load(self, pool):
-        self.handle = pool.add_repo(self.name)
-        self.handle.appdata = self 
-        return True
-
-def load_stub(repodata):
-    repo = repodata.repo.appdata
-    if repo:
-        return repo.load_ext(repodata)
-    return False
-
-
-parser = OptionParser(usage="usage: solv.py [options] COMMAND")
-parser.add_option('-r', '--repo', action="append", type="string", dest="repos", help="limit to specified repositories")
-parser.add_option('--best', action="store_true", dest="best", help="force installation/update to best packages")
-parser.add_option('--clean', action="store_true", dest="clean", help="delete no longer needed packages")
-(options, args) = parser.parse_args()
-if not args:
-    parser.print_help(sys.stderr)
-    sys.exit(1)
-
-cmd = args[0]
-args = args[1:]
-
-cmdabbrev = {'ls': 'list', 'in': 'install', 'rm': 'erase', 've': 'verify', 'se': 'search'}
-if cmd in cmdabbrev:
-    cmd = cmdabbrev[cmd]
-
-cmdactionmap = {
-  'install': solv.Job.SOLVER_INSTALL,
-  'erase':   solv.Job.SOLVER_ERASE,
-  'up':      solv.Job.SOLVER_UPDATE,
-  'dup':     solv.Job.SOLVER_DISTUPGRADE,
-  'verify':  solv.Job.SOLVER_VERIFY,
-  'list':    0,
-  'info':    0
-}
-
-# read all repo configs
-repos = []
-reposdirs = []
-if os.path.isdir("/etc/zypp/repos.d"):
-  reposdirs = [ "/etc/zypp/repos.d" ]
-else:
-  reposdirs = [ "/etc/yum/repos.d" ]
-
-for reposdir in reposdirs:
-    if not os.path.isdir(reposdir):
-        continue
-    for reponame in sorted(glob.glob('%s/*.repo' % reposdir)):
-        cfg = INIConfig(open(reponame))
-        for alias in cfg:
-            repoattr = {'enabled': 0, 'priority': 99, 'autorefresh': 1, 'type': 'rpm-md', 'metadata_expire': 900}
-            for k in cfg[alias]:
-                repoattr[k] = cfg[alias][k]
-            if 'mirrorlist' in repoattr and 'metalink' not in repoattr:
-                if repoattr['mirrorlist'].find('/metalink'):
-                    repoattr['metalink'] = repoattr['mirrorlist']
-                    del repoattr['mirrorlist']
-            if repoattr['type'] == 'rpm-md':
-                repo = repo_repomd(alias, 'repomd', repoattr)
-            elif repoattr['type'] == 'yast2':
-                repo = repo_susetags(alias, 'susetags', repoattr)
-            else:
-                repo = repo_unknown(alias, 'unknown', repoattr)
-            repos.append(repo)
-
-pool = solv.Pool()
-pool.setarch()
-pool.set_loadcallback(load_stub)
-
-# now load all enabled repos into the pool
-sysrepo = repo_system('@System', 'system')
-sysrepo.load(pool)
-for repo in repos:
-    if int(repo['enabled']):
-        repo.load(pool)
-    
-repofilter = None
-if options.repos:
-    for reponame in options.repos:
-        mrepos = [ repo for repo in repos if repo.name == reponame ]
-        if not mrepos:
-            print("no repository matches '%s'" % reponame)
-            sys.exit(1)
-        repo = mrepos[0]
-        if hasattr(repo, 'handle'):
-            if not repofilter:
-                repofilter = pool.Selection()
-            repofilter.add(repo.handle.Selection(solv.Job.SOLVER_SETVENDOR))
-
-if cmd == 'search':
-    pool.createwhatprovides()
-    sel = pool.Selection()
-    di = pool.Dataiterator(solv.SOLVABLE_NAME, args[0], solv.Dataiterator.SEARCH_SUBSTRING|solv.Dataiterator.SEARCH_NOCASE)
-    for d in di:
-        sel.add_raw(solv.Job.SOLVER_SOLVABLE, d.solvid)
-    if repofilter:
-       sel.filter(repofilter)
-    for s in sel.solvables():
-        print(" - %s [%s]: %s" % (s, s.repo.name, s.lookup_str(solv.SOLVABLE_SUMMARY)))
-    sys.exit(0)
-
-if cmd not in cmdactionmap:
-    print("unknown command %s" % cmd)
-    sys.exit(1)
-
-cmdlinerepo = None
-if cmd == 'list' or cmd == 'info' or cmd == 'install':
-    for arg in args:
-        if arg.endswith(".rpm") and os.access(arg, os.R_OK):
-            if not cmdlinerepo:
-                cmdlinerepo = repo_cmdline('@commandline', 'cmdline')
-                cmdlinerepo.load(pool)
-                cmdlinerepo['packages'] = {}
-            s = cmdlinerepo.handle.add_rpm(arg, solv.Repo.REPO_REUSE_REPODATA|solv.Repo.REPO_NO_INTERNALIZE)
-            if not s:
-                print(pool.errstr)
-                sys.exit(1)
-            cmdlinerepo['packages'][arg] = s
-    if cmdlinerepo:
-        cmdlinerepo.handle.internalize()
-
-addedprovides = pool.addfileprovides_queue()
-if addedprovides:
-    sysrepo.updateaddedprovides(addedprovides)
-    for repo in repos:
-        repo.updateaddedprovides(addedprovides)
-
-pool.createwhatprovides()
-
-# convert arguments into jobs
-jobs = []
-for arg in args:
-    if cmdlinerepo and arg in cmdlinerepo['packages']:
-        jobs.append(pool.Job(solv.Job.SOLVER_SOLVABLE, cmdlinerepo['packages'][arg].id))
-    else:
-        flags = solv.Selection.SELECTION_NAME|solv.Selection.SELECTION_PROVIDES|solv.Selection.SELECTION_GLOB
-        flags |= solv.Selection.SELECTION_CANON|solv.Selection.SELECTION_DOTARCH|solv.Selection.SELECTION_REL
-        if len(arg) and arg[0] == '/':
-            flags |= solv.Selection.SELECTION_FILELIST
-            if cmd == 'erase':
-                flags |= solv.Selection.SELECTION_INSTALLED_ONLY
-        sel = pool.select(arg, flags)
-        if repofilter:
-           sel.filter(repofilter)
-        if sel.isempty():
-            sel = pool.select(arg, flags | solv.Selection.SELECTION_NOCASE)
-            if repofilter:
-               sel.filter(repofilter)
-            if not sel.isempty():
-                print("[ignoring case for '%s']" % arg)
-        if sel.isempty():
-            print("nothing matches '%s'" % arg)
-            sys.exit(1)
-        if sel.flags() & solv.Selection.SELECTION_FILELIST:
-            print("[using file list match for '%s']" % arg)
-        if sel.flags() & solv.Selection.SELECTION_PROVIDES:
-            print("[using capability match for '%s']" % arg)
-        jobs += sel.jobs(cmdactionmap[cmd])
-
-if not jobs and (cmd == 'up' or cmd == 'dup' or cmd == 'verify' or repofilter):
-    sel = pool.Selection_all()
-    if repofilter:
-       sel.filter(repofilter)
-    jobs += sel.jobs(cmdactionmap[cmd])
-
-if not jobs:
-    print("no package matched.")
-    sys.exit(1)
-
-if cmd == 'list' or cmd == 'info':
-    for job in jobs:
-        for s in job.solvables():
-            if cmd == 'info':
-                print("Name:        %s" % s)
-                print("Repo:        %s" % s.repo)
-                print("Summary:     %s" % s.lookup_str(solv.SOLVABLE_SUMMARY))
-                str = s.lookup_str(solv.SOLVABLE_URL)
-                if str:
-                    print("Url:         %s" % str)
-                str = s.lookup_str(solv.SOLVABLE_LICENSE)
-                if str:
-                    print("License:     %s" % str)
-                print("Description:\n%s" % s.lookup_str(solv.SOLVABLE_DESCRIPTION))
-                print('')
-            else:
-                print("  - %s [%s]" % (s, s.repo))
-                print("    %s" % s.lookup_str(solv.SOLVABLE_SUMMARY))
-    sys.exit(0)
-
-# up magic: use install instead of update if no installed package matches
-for job in jobs:
-    if cmd == 'up' and job.isemptyupdate():
-        job.how ^= solv.Job.SOLVER_UPDATE ^ solv.Job.SOLVER_INSTALL
-    if options.best:
-        job.how |= solv.Job.SOLVER_FORCEBEST
-    if options.clean:
-        job.how |= solv.Job.SOLVER_CLEANDEPS
-
-#pool.set_debuglevel(2)
-solver = pool.Solver()
-solver.set_flag(solv.Solver.SOLVER_FLAG_SPLITPROVIDES, 1);
-if cmd == 'erase':
-    solver.set_flag(solv.Solver.SOLVER_FLAG_ALLOW_UNINSTALL, 1);
-
-while True:
-    problems = solver.solve(jobs)
-    if not problems:
-        break
-    for problem in problems:
-        print("Problem %d/%d:" % (problem.id, len(problems)))
-        print(problem)
-        solutions = problem.solutions()
-        for solution in solutions:
-            print("  Solution %d:" % solution.id)
-            elements = solution.elements(True)
-            for element in elements:
-                print("  - %s" % element.str())
-            print('')
-        sol = ''
-        while not (sol == 's' or sol == 'q' or (sol.isdigit() and int(sol) >= 1 and int(sol) <= len(solutions))):
-            sys.stdout.write("Please choose a solution: ")
-            sys.stdout.flush()
-            sol = sys.stdin.readline().strip()
-        if sol == 's':
-            continue        # skip problem
-        if sol == 'q':
-            sys.exit(1)
-        solution = solutions[int(sol) - 1]
-        for element in solution.elements():
-            newjob = element.Job()
-            if element.type == solv.Solver.SOLVER_SOLUTION_JOB:
-                jobs[element.jobidx] = newjob
-            else:
-                if newjob and newjob not in jobs:
-                    jobs.append(newjob)
-                    
-# no problems, show transaction
-trans = solver.transaction()
-del solver
-if trans.isempty():
-    print("Nothing to do.")
-    sys.exit(0)
-print('')
-print("Transaction summary:")
-print('')
-for cl in trans.classify(solv.Transaction.SOLVER_TRANSACTION_SHOW_OBSOLETES | solv.Transaction.SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE):
-    if cl.type == solv.Transaction.SOLVER_TRANSACTION_ERASE:
-        print("%d erased packages:" % cl.count)
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_INSTALL:
-        print("%d installed packages:" % cl.count)
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_REINSTALLED:
-        print("%d reinstalled packages:" % cl.count)
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_DOWNGRADED:
-        print("%d downgraded packages:" % cl.count)
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_CHANGED:
-        print("%d changed packages:" % cl.count)
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_UPGRADED:
-        print("%d upgraded packages:" % cl.count)
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_VENDORCHANGE:
-        print("%d vendor changes from '%s' to '%s':" % (cl.count, cl.fromstr, cl.tostr))
-    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_ARCHCHANGE:
-        print("%d arch changes from '%s' to '%s':" % (cl.count, cl.fromstr, cl.tostr))
-    else:
-        continue
-    for p in cl.solvables():
-        if cl.type == solv.Transaction.SOLVER_TRANSACTION_UPGRADED or cl.type == solv.Transaction.SOLVER_TRANSACTION_DOWNGRADED:
-            op = trans.othersolvable(p)
-            print("  - %s -> %s" % (p, op))
-        else:
-            print("  - %s" % p)
-    print('')
-print("install size change: %d K" % trans.calc_installsizechange())
-print('')
-
-while True:
-    sys.stdout.write("OK to continue (y/n)? ")
-    sys.stdout.flush()
-    yn = sys.stdin.readline().strip()
-    if yn == 'y': break
-    if yn == 'n' or yn == 'q': sys.exit(1)
-newpkgs = trans.newsolvables()
-newpkgsfp = {}
-if newpkgs:
-    downloadsize = 0
-    for p in newpkgs:
-        downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE)
-    print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize / 1024))
-    for p in newpkgs:
-        repo = p.repo.appdata
-        location, medianr = p.lookup_location()
-        if not location:
-            continue
-        if repo.type == 'commandline':
-            f = solv.xfopen(location)
-            if not f:
-                sys.exit("\n%s: %s not found" % location)
-            newpkgsfp[p.id] = f
-            continue
-        if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK):
-            pname = p.name
-            di = p.repo.Dataiterator_meta(solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING)
-            di.prepend_keyname(solv.REPOSITORY_DELTAINFO)
-            for d in di:
-                dp = d.parentpos()
-                if dp.lookup_id(solv.DELTA_PACKAGE_EVR) != p.evrid or dp.lookup_id(solv.DELTA_PACKAGE_ARCH) != p.archid:
-                    continue
-                baseevrid = dp.lookup_id(solv.DELTA_BASE_EVR)
-                candidate = None
-                for installedp in pool.whatprovides(p.nameid):
-                    if installedp.isinstalled() and installedp.nameid == p.nameid and installedp.archid == p.archid and installedp.evrid == baseevrid:
-                        candidate = installedp
-                if not candidate:
-                    continue
-                seq = dp.lookup_deltaseq()
-                st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, '-c', '-s', seq])
-                if st:
-                    continue
-                chksum = dp.lookup_checksum(solv.DELTA_CHECKSUM)
-                if not chksum:
-                    continue
-                dloc, dmedianr = dp.lookup_deltalocation()
-                dloc = repo.packagespath() + dloc
-                f = repo.download(dloc, False, chksum)
-                if not f:
-                    continue
-                nf = tempfile.TemporaryFile()
-                nf = os.dup(nf.fileno())   # get rid of CLOEXEC
-                f.cloexec(0)
-                st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf])
-                if st:
-                    os.close(nf)
-                    continue
-                os.lseek(nf, 0, os.SEEK_SET)
-                newpkgsfp[p.id] = solv.xfopen_fd("", nf)
-                os.close(nf)
-                break
-            if p.id in newpkgsfp:
-                sys.stdout.write("d")
-                sys.stdout.flush()
-                continue
-                    
-        chksum = p.lookup_checksum(solv.SOLVABLE_CHECKSUM)
-        location = repo.packagespath() + location
-        f = repo.download(location, False, chksum)
-        if not f:
-            sys.exit("\n%s: %s not found in repository" % (repo.name, location))
-        newpkgsfp[p.id] = f
-        sys.stdout.write(".")
-        sys.stdout.flush()
-    print('')
-print("Committing transaction:")
-print('')
-ts = rpm.TransactionSet('/')
-ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
-erasenamehelper = {}
-for p in trans.steps():
-    type = trans.steptype(p, solv.Transaction.SOLVER_TRANSACTION_RPM_ONLY)
-    if type == solv.Transaction.SOLVER_TRANSACTION_ERASE:
-        rpmdbid = p.lookup_num(solv.RPM_RPMDBID)
-        erasenamehelper[p.name] = p
-        if not rpmdbid:
-            sys.exit("\ninternal error: installed package %s has no rpmdbid\n" % p)
-        ts.addErase(rpmdbid)
-    elif type == solv.Transaction.SOLVER_TRANSACTION_INSTALL:
-        f = newpkgsfp[p.id]
-        h = ts.hdrFromFdno(f.fileno())
-        os.lseek(f.fileno(), 0, os.SEEK_SET)
-        ts.addInstall(h, p, 'u')
-    elif type == solv.Transaction.SOLVER_TRANSACTION_MULTIINSTALL:
-        f = newpkgsfp[p.id]
-        h = ts.hdrFromFdno(f.fileno())
-        os.lseek(f.fileno(), 0, os.SEEK_SET)
-        ts.addInstall(h, p, 'i')
-checkproblems = ts.check()
-if checkproblems:
-    print(checkproblems)
-    sys.exit("Sorry.")
-ts.order()
-def runCallback(reason, amount, total, p, d):
-    if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:
-        return newpkgsfp[p.id].fileno()
-    if reason == rpm.RPMCALLBACK_INST_START:
-        print("install %s" % p)
-    if reason == rpm.RPMCALLBACK_UNINST_START:
-        # argh, p is just the name of the package
-        if p in erasenamehelper:
-            p = erasenamehelper[p]
-            print("erase %s" % p)
-runproblems = ts.run(runCallback, '')
-if runproblems:
-    print(runproblems)
-    sys.exit(1)
-sys.exit(0)
-
-# vim: sw=4 et
diff --git a/libsolv-0.6.15/examples/rbsolv b/libsolv-0.6.15/examples/rbsolv
deleted file mode 100755 (executable)
index be633f3..0000000
+++ /dev/null
@@ -1,762 +0,0 @@
-#!/usr/bin/ruby
-
-require 'solv'
-require 'rubygems'
-require 'inifile'
-require 'tempfile'
-
-class Repo_generic
-  def initialize(name, type, attribs = {})
-    @name = name
-    @type = type
-    @attribs = attribs.dup
-    @incomplete = false
-  end
-
-  def enabled?
-    return @attribs['enabled'].to_i != 0
-  end
-
-  def autorefresh?
-    return @attribs['autorefresh'].to_i != 0
-  end
-
-  def id
-    return @handle ? @handle.id : 0
-  end
-
-  def calc_cookie_fp(f)
-    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
-    chksum.add("1.1")
-    chksum.add_fp(f)
-    return chksum.raw
-  end
-
-  def calc_cookie_file(filename)
-    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
-    chksum.add("1.1")
-    chksum.add_stat(filename)
-    return chksum.raw
-  end
-
-  def calc_cookie_ext(f, cookie)
-    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
-    chksum.add("1.1")
-    chksum.add(cookie)
-    chksum.add_fstat(f.fileno)
-    return chksum.raw()
-  end
-
-  def cachepath(ext = nil)
-    path = @name.sub(/^\./, '_')
-    path += ext ? "_#{ext}.solvx" : '.solv'
-    return '/var/cache/solv/' + path.gsub(/\//, '_')
-  end
-
-  def load(pool)
-    @handle = pool.add_repo(@name)
-    @handle.appdata = self
-    @handle.priority = 99 - @attribs['priority'].to_i if @attribs['priority']
-    dorefresh = autorefresh?
-    if dorefresh
-      begin
-       s = File.stat(cachepath)
-       dorefresh = false if s && (@attribs['metadata_expire'].to_i == -1 || Time.now - s.mtime < @attribs['metadata_expire'].to_i)
-      rescue SystemCallError
-      end
-    end
-    @cookie = nil
-    @extcookie = nil
-    if !dorefresh && usecachedrepo(nil)
-      puts "repo: '#{@name}' cached"
-      return true
-    end
-    return false
-  end
-
-  def load_ext(repodata)
-    return false
-  end
-
-  def download(file, uncompress, chksum, markincomplete = false)
-    url = @attribs['baseurl']
-    if !url
-      puts "%{@name}: no baseurl"
-      return nil
-    end
-    url = url.sub(/\/$/, '') + "/#{file}"
-    f =  Tempfile.new('rbsolv')
-    f.unlink
-    st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" + f.fileno.to_s, '--', url)
-    return nil if f.stat.size == 0 && (st || !chksum)
-    if !st
-       puts "#{file}: download error #{$? >> 8}"
-       @incomplete = true if markincomplete
-       return nil
-    end
-    if chksum
-      fchksum = Solv::Chksum.new(chksum.type)
-      fchksum.add_fd(f.fileno)
-      if !fchksum == chksum
-       puts "#{file}: checksum error"
-       @incomplete = true if markincomplete
-       return nil
-      end
-    end
-    rf = nil
-    if uncompress
-      rf = Solv::xfopen_fd(file, f.fileno)
-    else
-      rf = Solv::xfopen_fd('', f.fileno)
-    end
-    f.close
-    return rf
-  end
-
-  def usecachedrepo(ext, mark = false)
-    cookie = ext ? @extcookie : @cookie
-    begin
-      repopath = cachepath(ext)
-      f = File.new(repopath, "r")
-      f.sysseek(-32, IO::SEEK_END)
-      fcookie = f.sysread(32)
-      return false if fcookie.length != 32
-      return false if cookie && fcookie != cookie
-      if !ext && @type != 'system'
-       f.sysseek(-32 * 2, IO::SEEK_END)
-       fextcookie = f.sysread(32)
-       return false if fextcookie.length != 32
-      end
-      f.sysseek(0, IO::SEEK_SET)
-      nf = Solv::xfopen_fd('', f.fileno)
-      f.close
-      flags = ext ? Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES : 0
-      flags |= Solv::Repo::REPO_LOCALPOOL if ext && ext != 'DL'
-      if ! @handle.add_solv(nf, flags)
-       nf.close
-       return false
-      end
-      nf.close()
-      @cookie = fcookie unless ext
-      @extcookie = fextcookie if !ext && @type != 'system'
-      now = Time.now
-      begin
-       File::utime(now, now, repopath) if mark
-      rescue SystemCallError
-      end
-      return true
-    rescue SystemCallError
-      return false
-    end
-    return true
-  end
-
-  def writecachedrepo(ext, repodata = nil)
-    return if @incomplete
-    begin
-      Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv")
-      f =  Tempfile.new('.newsolv-', '/var/cache/solv')
-      f.chmod(0444)
-      sf = Solv::xfopen_fd('', f.fileno)
-      if !repodata
-       @handle.write(sf)
-      elsif ext
-       repodata.write(sf)
-      else
-       @handle.write_first_repodata(sf)
-      end
-      sf.close
-      f.sysseek(0, IO::SEEK_END)
-      if @type != 'system' && !ext
-       @extcookie = calc_cookie_ext(f, @cookie) unless @extcookie
-       f.syswrite(@extcookie)
-      end
-      f.syswrite(ext ? @extcookie : @cookie)
-      f.close
-      if @handle.iscontiguous?
-       sf = Solv::xfopen(f.path)
-       if sf
-         if !ext
-           @handle.empty()
-           abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, repodata ? 0 : Solv::Repo::SOLV_ADD_NO_STUBS)
-         else
-           repodata.extend_to_repo()
-           flags = Solv::Repo::REPO_EXTEND_SOLVABLES
-           flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL'
-           repodata.add_solv(sf, flags)
-         end
-         sf.close
-       end
-      end
-      File.rename(f.path, cachepath(ext))
-      f.unlink
-      return true
-    rescue SystemCallError
-      return false
-    end
-  end
-
-  def updateaddedprovides(addedprovides)
-    return if @incomplete
-    return unless @handle && !@handle.isempty?
-    repodata = @handle.first_repodata()
-    return unless repodata
-    oldaddedprovides = repodata.lookup_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES)
-    return if (oldaddedprovides | addedprovides) == oldaddedprovides
-    for id in addedprovides
-      repodata.add_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES, id)
-    end
-    repodata.internalize()
-    writecachedrepo(nil, repodata)
-  end
-
-  def packagespath()
-    return ''
-  end
-
-  @@langtags = {
-    Solv::SOLVABLE_SUMMARY     => Solv::REPOKEY_TYPE_STR,
-    Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR,
-    Solv::SOLVABLE_EULA        => Solv::REPOKEY_TYPE_STR,
-    Solv::SOLVABLE_MESSAGEINS  => Solv::REPOKEY_TYPE_STR,
-    Solv::SOLVABLE_MESSAGEDEL  => Solv::REPOKEY_TYPE_STR,
-    Solv::SOLVABLE_CATEGORY    => Solv::REPOKEY_TYPE_ID,
-  }
-
-  def add_ext_keys(ext, repodata, h)
-    if ext == 'DL'
-      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
-      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
-    elsif ext == 'DU'
-      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE)
-      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY)
-    elsif ext == 'FL'
-      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
-      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
-    else
-      @@langtags.sort.each do |langid, langtype|
-       repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true))
-       repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype)
-      end
-    end
-  end
-end
-
-class Repo_rpmmd < Repo_generic
-
-  def find(what)
-    di = @handle.Dataiterator_meta(Solv::REPOSITORY_REPOMD_TYPE, what, Solv::Dataiterator::SEARCH_STRING)
-    di.prepend_keyname(Solv::REPOSITORY_REPOMD)
-    for d in di
-      dp = d.parentpos()
-      filename = dp.lookup_str(Solv::REPOSITORY_REPOMD_LOCATION)
-      next unless filename
-      checksum = dp.lookup_checksum(Solv::REPOSITORY_REPOMD_CHECKSUM)
-      if !checksum
-       puts "no #{filename} checksum!"
-       return nil, nil
-      end
-      return filename, checksum
-    end
-    return nil, nil
-  end
-
-  def load(pool)
-    return true if super(pool)
-    print "rpmmd repo '#{@name}: "
-    f = download("repodata/repomd.xml", false, nil, nil)
-    if !f
-      puts "no repomd.xml file, skipped"
-      @handle.free(true)
-      @handle = nil
-      return false
-    end
-    @cookie = calc_cookie_fp(f)
-    if usecachedrepo(nil, true)
-      puts "cached"
-      f.close
-      return true
-    end
-    @handle.add_repomdxml(f, 0)
-    f.close
-    puts "fetching"
-    filename, filechksum = find('primary')
-    if filename
-      f = download(filename, true, filechksum, true)
-      if f
-       @handle.add_rpmmd(f, nil, 0)
-       f.close
-      end
-      return false if @incomplete
-    end
-    filename, filechksum = find('updateinfo')
-    if filename
-      f = download(filename, true, filechksum, true)
-      if f
-       @handle.add_updateinfoxml(f, 0)
-       f.close
-      end
-    end
-    add_exts()
-    writecachedrepo(nil)
-    @handle.create_stubs()
-    return true
-  end
-
-  def add_ext(repodata, what, ext)
-    filename, filechksum = find(what)
-    filename, filechksum = find('prestodelta') if !filename && what == 'deltainfo'
-    return unless filename
-    h = repodata.new_handle()
-    repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what)
-    repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename)
-    repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum)
-    add_ext_keys(ext, repodata, h)
-    repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
-  end
-
-  def add_exts
-    repodata = @handle.add_repodata(0)
-    add_ext(repodata, 'deltainfo', 'DL')
-    add_ext(repodata, 'filelists', 'FL')
-    repodata.internalize()
-  end
-
-  def load_ext(repodata)
-    repomdtype = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE)
-    if repomdtype == 'filelists'
-      ext = 'FL'
-    elsif repomdtype == 'deltainfo'
-      ext = 'DL'
-    else
-      return false
-    end
-    print "[#{@name}:#{ext}: "
-    STDOUT.flush
-    if usecachedrepo(ext)
-      puts "cached]\n"
-      return true
-    end
-    puts "fetching]\n"
-    filename = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_LOCATION)
-    filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_CHECKSUM)
-    f = download(filename, true, filechksum)
-    return false unless f
-    if ext == 'FL'
-      @handle.add_rpmmd(f, 'FL', Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES|Solv::Repo::REPO_LOCALPOOL)
-    elsif ext == 'DL'
-      @handle.add_deltainfoxml(f, Solv::Repo::REPO_USE_LOADING)
-    end
-    f.close
-    writecachedrepo(ext, repodata)
-    return true
-  end
-
-end
-
-class Repo_susetags < Repo_generic
-
-  def find(what)
-    di = @handle.Dataiterator_meta(Solv::SUSETAGS_FILE_NAME, what, Solv::Dataiterator::SEARCH_STRING)
-    di.prepend_keyname(Solv::SUSETAGS_FILE)
-    for d in di
-      dp = d.parentpos()
-      checksum = dp.lookup_checksum(Solv::SUSETAGS_FILE_CHECKSUM)
-      return what, checksum
-    end
-    return nil, nil
-  end
-
-  def load(pool)
-    return true if super(pool)
-    print "susetags repo '#{@name}: "
-    f = download("content", false, nil, nil)
-    if !f
-      puts "no content file, skipped"
-      @handle.free(true)
-      @handle = nil
-      return false
-    end
-    @cookie = calc_cookie_fp(f)
-    if usecachedrepo(nil, true)
-      puts "cached"
-      f.close
-      return true
-    end
-    @handle.add_content(f, 0)
-    f.close
-    puts "fetching"
-    defvendorid = @handle.meta.lookup_id(Solv::SUSETAGS_DEFAULTVENDOR)
-    descrdir = @handle.meta.lookup_str(Solv::SUSETAGS_DESCRDIR)
-    descrdir = "suse/setup/descr" unless descrdir
-    (filename, filechksum) = find('packages.gz')
-    (filename, filechksum) = find('packages') unless filename
-    if filename
-      f = download("#{descrdir}/#{filename}", true, filechksum, true)
-      if f
-       @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::SUSETAGS_RECORD_SHARES)
-       f.close
-       (filename, filechksum) = find('packages.en.gz')
-       (filename, filechksum) = find('packages.en') unless filename
-       if filename
-         f = download("#{descrdir}/#{filename}", true, filechksum, true)
-         if f
-           @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::REPO_REUSE_REPODATA|Solv::Repo::REPO_EXTEND_SOLVABLES)
-           f.close
-         end
-       end
-       @handle.internalize()
-      end
-    end
-    add_exts()
-    writecachedrepo(nil)
-    @handle.create_stubs()
-    return true
-  end
-
-  def add_ext(repodata, what, ext)
-    (filename, filechksum) = find(what)
-    h = repodata.new_handle()
-    repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename)
-    repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum)
-    add_ext_keys(ext, repodata, h)
-    repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
-  end
-
-  def add_exts
-    repodata = @handle.add_repodata(0)
-    di = @handle.Dataiterator_meta(Solv::SUSETAGS_FILE_NAME, nil, 0)
-    di.prepend_keyname(Solv::SUSETAGS_FILE)
-    for d in di
-      filename = d.str
-      next unless filename && filename =~ /^packages\.(..)(?:\..*)$/
-      next if $1 == 'en' || $1 == 'gz'
-      add_ext(repodata, filename, $1)
-    end
-    repodata.internalize()
-  end
-
-  def load_ext(repodata)
-    filename = repodata.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME)
-    ext = filename[9,2]
-    print "[#{@name}:#{ext}: "
-    STDOUT.flush
-    if usecachedrepo(ext)
-      puts "cached]\n"
-      return true
-    end
-    puts "fetching]\n"
-    defvendorid = @handle.meta.lookup_id(Solv::SUSETAGS_DEFAULTVENDOR)
-    descrdir = @handle.meta.lookup_str(Solv::SUSETAGS_DESCRDIR)
-    descrdir = "suse/setup/descr" unless descrdir
-    filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::SUSETAGS_FILE_CHECKSUM)
-    f = download("#{descrdir}/#{filename}", true, filechksum)
-    return false unless f
-    flags = Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES
-    flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL'
-    @handle.add_susetags(f, defvendorid, ext, flags)
-    f.close
-    writecachedrepo(ext, repodata)
-    return true
-  end
-
-  def packagespath()
-    datadir = @handle.meta.lookup_str(Solv::SUSETAGS_DATADIR)
-    datadir = "suse" unless datadir
-    return datadir + '/'
-  end
-end
-
-class Repo_unknown < Repo_generic
-  def load(pool)
-    puts "unsupported repo '#{@name}: skipped"
-    return false
-  end
-end
-
-class Repo_system < Repo_generic
-  def load(pool)
-    @handle = pool.add_repo(@name)
-    @handle.appdata = self
-    pool.installed = @handle
-    print "rpm database: "
-    @cookie = calc_cookie_file("/var/lib/rpm/Packages")
-    if usecachedrepo(nil)
-      puts "cached"
-      return true
-    end
-    puts "reading"
-    if @handle.respond_to? :add_products
-      @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
-    end
-    f = Solv::xfopen(cachepath())
-    @handle.add_rpmdb_reffp(f, Solv::Repo::REPO_REUSE_REPODATA)
-    f.close if f
-    writecachedrepo(nil)
-    return true
-  end
-end
-
-args = ARGV
-cmd = args.shift
-
-cmdabbrev = { 'ls' => 'list', 'in' => 'install', 'rm' => 'erase',
-              've' => 'verify', 'se' => 'search' }
-cmd = cmdabbrev[cmd] if cmdabbrev.has_key?(cmd)
-
-cmdactionmap = { 
-  'install' => Solv::Job::SOLVER_INSTALL,
-  'erase'   => Solv::Job::SOLVER_ERASE,
-  'up'      => Solv::Job::SOLVER_UPDATE,
-  'dup'     => Solv::Job::SOLVER_DISTUPGRADE,
-  'verify'  => Solv::Job::SOLVER_VERIFY,
-  'list'    => 0,  
-  'info'    => 0,
-}
-
-repos = []
-reposdirs = []
-if FileTest.directory?('/etc/zypp/repos.d')
-  reposdirs = [ '/etc/zypp/repos.d' ]
-else
-  reposdirs = [ '/etc/yum/repos.d' ]
-end
-for reposdir in reposdirs do
-  next unless FileTest.directory?(reposdir)
-  for reponame in Dir["#{reposdir}/*.repo"].sort do
-    cfg = IniFile.load(reponame)
-    cfg.each_section do |ali|
-      repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
-      repoattr.update(cfg[ali])
-      if repoattr['type'] == 'rpm-md'
-       repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
-      elsif repoattr['type'] == 'yast2'
-       repo = Repo_susetags.new(ali, 'susetags', repoattr)
-      else
-       repo = Repo_unknown.new(ali, 'unknown', repoattr)
-      end
-      repos.push(repo)
-    end
-  end
-end
-
-pool = Solv::Pool.new()
-pool.setarch()
-
-pool.set_loadcallback { |repodata|
-  repo = repodata.repo.appdata
-  repo ? repo.load_ext(repodata) : false
-}
-
-sysrepo = Repo_system.new('@System', 'system')
-sysrepo.load(pool)
-for repo in repos
-  repo.load(pool) if repo.enabled?
-end
-
-if cmd == 'search'
-  pool.createwhatprovides()
-  sel = pool.Selection
-  for di in pool.Dataiterator(Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
-    sel.add_raw(Solv::Job::SOLVER_SOLVABLE, di.solvid)
-  end
-  for s in sel.solvables
-    puts "- #{s.str} [#{s.repo.name}]: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
-  end
-  exit
-end
-
-abort("unknown command '#{cmd}'\n") unless cmdactionmap.has_key?(cmd)
-
-addedprovides = pool.addfileprovides_queue()
-if !addedprovides.empty?
-  sysrepo.updateaddedprovides(addedprovides)
-  for repo in repos
-    repo.updateaddedprovides(addedprovides)
-  end
-end
-pool.createwhatprovides()
-
-jobs = []
-for arg in args
-  flags = Solv::Selection::SELECTION_NAME | Solv::Selection::SELECTION_PROVIDES | Solv::Selection::SELECTION_GLOB
-  flags |= Solv::Selection::SELECTION_CANON | Solv::Selection::SELECTION_DOTARCH | Solv::Selection::SELECTION_REL
-  if arg =~ /^\//
-    flags |= Solv::Selection::SELECTION_FILELIST
-    flags |= Solv::Selection::SELECTION_INSTALLED_ONLY if cmd == 'erase'
-  end
-  sel = pool.select(arg, flags)
-  if sel.isempty?
-    sel = pool.select(arg, flags |  Solv::Selection::SELECTION_NOCASE)
-    puts "[ignoring case for '#{arg}']" unless sel.isempty?
-  end
-  puts "[using file list match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_FILELIST != 0
-  puts "[using capability match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_PROVIDES != 0
-  jobs += sel.jobs(cmdactionmap[cmd])
-end
-
-if jobs.empty? && (cmd == 'up' || cmd == 'dup' || cmd == 'verify')
-  sel = pool.Selection_all()
-  jobs += sel.jobs(cmdactionmap[cmd])
-end
-
-abort("no package matched.") if jobs.empty?
-
-if cmd == 'list' || cmd == 'info'
-  for job in jobs
-    for s in job.solvables()
-      if cmd == 'info'
-       puts "Name:        #{s.str}"
-       puts "Repo:        #{s.repo.name}"
-       puts "Summary:     #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
-       str = s.lookup_str(Solv::SOLVABLE_URL)
-       puts "Url:         #{str}" if str
-       str = s.lookup_str(Solv::SOLVABLE_LICENSE)
-       puts "License:     #{str}" if str
-       puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
-       puts
-      else
-       puts "  - #{s.str} [#{s.repo.name}]"
-       puts "    #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
-      end
-    end
-  end
-  exit
-end
-
-for job in jobs
-  job.how ^= Solv::Job::SOLVER_UPDATE ^ Solv::Job::SOLVER_INSTALL if cmd == 'up' and job.isemptyupdate?
-end
-
-solver = pool.Solver
-solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1)
-solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase'
-#pool.set_debuglevel(1)
-
-while true
-  problems = solver.solve(jobs)
-  break if problems.empty?
-  for problem in problems
-    puts "Problem #{problem.id}/#{problems.count}:"
-    puts problem
-    solutions = problem.solutions
-    for solution in solutions
-      puts "  Solution #{solution.id}:"
-      elements = solution.elements(true)
-      for element in elements
-       puts "  - #{element.str}"
-      end
-      puts
-    end
-    sol = nil
-    while true
-      print "Please choose a solution: "
-      STDOUT.flush
-      sol = STDIN.gets.strip
-      break if sol == 's' || sol == 'q'
-      break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length
-    end
-    next if sol == 's'
-    abort if sol == 'q'
-    solution = solutions[sol.to_i - 1]
-    for element in solution.elements
-      newjob = element.Job()
-      if element.type == Solv::Solver::SOLVER_SOLUTION_JOB
-       jobs[element.jobidx] = newjob
-      else
-       jobs.push(newjob) if newjob && !jobs.include?(newjob)
-      end
-    end
-  end
-end
-
-trans = solver.transaction
-solver = nil
-if trans.isempty?
-  puts "Nothing to do."
-  exit
-end
-
-puts "\nTransaction summary:\n"
-for cl in trans.classify(Solv::Transaction::SOLVER_TRANSACTION_SHOW_OBSOLETES | Solv::Transaction::SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE)
-  if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
-    puts "#{cl.count} erased packages:"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
-    puts "#{cl.count} installed packages:"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
-    puts "#{cl.count} reinstalled packages:"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
-    puts "#{cl.count} downgraded packages:"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
-    puts "#{cl.count} changed packages:"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
-    puts "#{cl.count} upgraded packages:"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
-    puts "#{cl.count} vendor changes from '#{cl.fromstr}' to '#{cl.tostr}':"
-  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
-    puts "#{cl.count} arch changes from '#{cl.fromstr}' to '#{cl.tostr}':"
-  else
-    next
-  end
-  for p in cl.solvables
-    if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
-      puts "  - #{p.str} -> #{trans.othersolvable(p).str}"
-    else
-      puts "  - #{p.str}"
-    end
-  end
-  puts
-end
-puts "install size change: #{trans.calc_installsizechange()} K\n\n"
-
-while true
-  print("OK to continue (y/n)? ")
-  STDOUT.flush
-  yn = STDIN.gets.strip
-  break if yn == 'y'
-  abort if yn == 'n' || yn == 'q'
-end
-
-newpkgs = trans.newsolvables()
-newpkgsfp = {}
-if !newpkgs.empty?
-  downloadsize = 0
-  for p in newpkgs
-    downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE)
-  end
-  puts "Downloading #{newpkgs.length} packages, #{downloadsize / 1024} K"
-  for p in newpkgs
-    repo = p.repo.appdata
-    location, medianr = p.lookup_location()
-    next unless location
-    location = repo.packagespath + location
-    chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM)
-    f = repo.download(location, false, chksum)
-    abort("\n#{@name}: #{location} not found in repository\n") unless f
-    newpkgsfp[p.id] = f
-    print "."
-    STDOUT.flush()
-  end
-  puts
-end
-
-puts "Committing transaction:"
-puts
-trans.order()
-for p in trans.steps
-  steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY)
-  if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE
-    puts "erase #{p.str}"
-    next unless p.lookup_num(Solv::RPM_RPMDBID)
-    evr = p.evr.sub(/^[0-9]+:/, '')
-    system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}") 
-  elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL)
-    puts "install #{p.str}"
-    f = newpkgsfp.delete(p.id)
-    next unless f
-    mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'
-    f.cloexec(0)
-    system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{f.fileno().to_s}") || abort("rpm failed: #{$? >> 8}")
-    f.close
-  end
-end
diff --git a/libsolv-0.6.15/examples/solv/CMakeLists.txt b/libsolv-0.6.15/examples/solv/CMakeLists.txt
deleted file mode 100644 (file)
index 41f45f7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-
-ADD_EXECUTABLE (solv solv.c
-checksig.c
-deltarpm.c
-fastestmirror.c
-fileconflicts.c
-fileprovides.c
-mirror.c
-patchjobs.c
-repoinfo.c
-repoinfo_cache.c
-repoinfo_config_debian.c
-repoinfo_config_yum.c
-repoinfo_config_urpmi.c
-repoinfo_download.c
-repoinfo_system_debian.c
-repoinfo_system_rpm.c
-repoinfo_type_debian.c
-repoinfo_type_mdk.c
-repoinfo_type_rpmmd.c
-repoinfo_type_susetags.c
-)
-
-TARGET_LINK_LIBRARIES (solv libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-INSTALL(TARGETS
-    solv
-    DESTINATION ${BIN_INSTALL_DIR})
-
diff --git a/libsolv-0.6.15/examples/solv/checksig.c b/libsolv-0.6.15/examples/solv/checksig.c
deleted file mode 100644 (file)
index ff60c66..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "pool.h"
-#include "repo.h"
-#ifdef ENABLE_PUBKEY
-#include "repo_pubkey.h"
-#endif
-
-#include "checksig.h"
-
-#ifndef DEBIAN
-
-static void
-cleanupgpg(char *gpgdir)
-{
-  char cmd[256];
-  snprintf(cmd, sizeof(cmd), "%s/pubring.gpg", gpgdir);
-  unlink(cmd);
-  snprintf(cmd, sizeof(cmd), "%s/pubring.gpg~", gpgdir);
-  unlink(cmd);
-  snprintf(cmd, sizeof(cmd), "%s/secring.gpg", gpgdir);
-  unlink(cmd);
-  snprintf(cmd, sizeof(cmd), "%s/trustdb.gpg", gpgdir);
-  unlink(cmd);
-  snprintf(cmd, sizeof(cmd), "%s/keys", gpgdir);
-  unlink(cmd);
-  rmdir(gpgdir);
-}
-
-int
-checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
-{
-  char *gpgdir;
-  char *keysfile;
-  const char *pubkey;
-  char cmd[256];
-  FILE *kfp;
-  Solvable *s;
-  Id p;
-  off_t posfp, possigfp;
-  int r, nkeys;
-
-  gpgdir = mkdtemp(pool_tmpjoin(sigpool, "/var/tmp/solvgpg.XXXXXX", 0, 0));
-  if (!gpgdir)
-    return 0;
-  keysfile = pool_tmpjoin(sigpool, gpgdir, "/keys", 0);
-  if (!(kfp = fopen(keysfile, "w")) )
-    {
-      cleanupgpg(gpgdir);
-      return 0;
-    }
-  nkeys = 0;
-  for (p = 1, s = sigpool->solvables + p; p < sigpool->nsolvables; p++, s++)
-    {
-      if (!s->repo)
-       continue;
-      pubkey = solvable_lookup_str(s, SOLVABLE_DESCRIPTION);
-      if (!pubkey || !*pubkey)
-       continue;
-      if (fwrite(pubkey, strlen(pubkey), 1, kfp) != 1)
-       break;
-      if (fputc('\n', kfp) == EOF)     /* Just in case... */
-       break;
-      nkeys++;
-    }
-  if (fclose(kfp) || !nkeys || p < sigpool->nsolvables)
-    {
-      cleanupgpg(gpgdir);
-      return 0;
-    }
-  snprintf(cmd, sizeof(cmd), "gpg2 -q --homedir %s --import %s", gpgdir, keysfile);
-  if (system(cmd))
-    {
-      fprintf(stderr, "key import error\n");
-      cleanupgpg(gpgdir);
-      return 0;
-    }
-  unlink(keysfile);
-  posfp = lseek(fileno(fp), 0, SEEK_CUR);
-  lseek(fileno(fp), 0, SEEK_SET);
-  possigfp = lseek(fileno(sigfp), 0, SEEK_CUR);
-  lseek(fileno(sigfp), 0, SEEK_SET);
-  snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/pubring.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, fileno(sigfp), fileno(fp));
-  fcntl(fileno(fp), F_SETFD, 0);       /* clear CLOEXEC */
-  fcntl(fileno(sigfp), F_SETFD, 0);    /* clear CLOEXEC */
-  r = system(cmd);
-  lseek(fileno(sigfp), possigfp, SEEK_SET);
-  lseek(fileno(fp), posfp, SEEK_SET);
-  fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
-  fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
-  cleanupgpg(gpgdir);
-  return r == 0 ? 1 : 0;
-}
-
-#else
-
-int
-checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
-{
-  char cmd[256];
-  int r;
-
-  snprintf(cmd, sizeof(cmd), "gpgv -q --keyring /etc/apt/trusted.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", fileno(sigfp), fileno(fp));
-  fcntl(fileno(fp), F_SETFD, 0);       /* clear CLOEXEC */
-  fcntl(fileno(sigfp), F_SETFD, 0);    /* clear CLOEXEC */
-  r = system(cmd);
-  fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
-  fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
-  return r == 0 ? 1 : 0;
-}
-
-#endif
-
-Pool *
-read_sigs()
-{
-  Pool *sigpool = pool_create();
-#if defined(ENABLE_PUBKEY) && defined(ENABLE_RPMDB)
-  Repo *repo = repo_create(sigpool, "pubkeys");
-  repo_add_rpmdb_pubkeys(repo, 0);
-#endif
-  return sigpool;
-}
diff --git a/libsolv-0.6.15/examples/solv/checksig.h b/libsolv-0.6.15/examples/solv/checksig.h
deleted file mode 100644 (file)
index 67ebaf8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-extern int checksig(Pool *sigpool, FILE *fp, FILE *sigfp);
-extern Pool *read_sigs();
-
diff --git a/libsolv-0.6.15/examples/solv/deltarpm.c b/libsolv-0.6.15/examples/solv/deltarpm.c
deleted file mode 100644 (file)
index 551d570..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repoinfo.h"
-#include "repoinfo_download.h"
-
-#include "deltarpm.h"
-
-static inline int
-opentmpfile()
-{
-  char tmpl[100];
-  int fd;
-
-  strcpy(tmpl, "/var/tmp/solvXXXXXX");
-  fd = mkstemp(tmpl);
-  if (fd < 0) 
-    {    
-      perror("mkstemp");
-      exit(1);
-    }    
-  unlink(tmpl);
-  return fd;
-}
-
-FILE *
-trydeltadownload(Solvable *s, const char *loc)
-{
-  Repo *repo = s->repo;
-  Pool *pool = repo->pool;
-  struct repoinfo *cinfo = repo->appdata;
-  Dataiterator di;
-  Id pp;
-  const unsigned char *chksum;
-  Id chksumtype;
-  FILE *retfp = 0;
-  char *matchname = strdup(pool_id2str(pool, s->name));
-
-  dataiterator_init(&di, pool, repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING);
-  dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO);
-  while (dataiterator_step(&di))
-    {
-      Id baseevr, op;
-
-      dataiterator_setpos_parent(&di);
-      if (pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_EVR) != s->evr ||
-         pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_ARCH) != s->arch)
-       continue;
-      baseevr = pool_lookup_id(pool, SOLVID_POS, DELTA_BASE_EVR);
-      FOR_PROVIDES(op, pp, s->name)
-       {
-         Solvable *os = pool->solvables + op;
-         if (os->repo == pool->installed && os->name == s->name && os->arch == s->arch && os->evr == baseevr)
-           break;
-       }
-      if (op && access("/usr/bin/applydeltarpm", X_OK) == 0)
-       {
-         /* base is installed, run sequence check */
-         const char *seq;
-         const char *dloc;
-         const char *archstr;
-         FILE *fp;
-         char cmd[128];
-         int newfd;
-
-         archstr = pool_id2str(pool, s->arch);
-         if (strlen(archstr) > 10 || strchr(archstr, '\'') != 0)
-           continue;
-
-         seq = pool_tmpjoin(pool, pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME), "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR));
-         seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM));
-         if (strchr(seq, '\'') != 0)
-           continue;
-#ifdef FEDORA
-         sprintf(cmd, "/usr/bin/applydeltarpm -a '%s' -c -s '", archstr);
-#else
-         sprintf(cmd, "/usr/bin/applydeltarpm -c -s '");
-#endif
-         if (system(pool_tmpjoin(pool, cmd, seq, "'")) != 0)
-           continue;   /* didn't match */
-         /* looks good, download delta */
-         chksumtype = 0;
-         chksum = pool_lookup_bin_checksum(pool, SOLVID_POS, DELTA_CHECKSUM, &chksumtype);
-         if (!chksumtype)
-           continue;   /* no way! */
-         dloc = pool_lookup_deltalocation(pool, SOLVID_POS, 0);
-         if (!dloc)
-           continue;
-#ifdef ENABLE_SUSEREPO
-         if (cinfo->type == TYPE_SUSETAGS)
-           {
-             const char *datadir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DATADIR);
-             dloc = pool_tmpjoin(pool, datadir ? datadir : "suse", "/", dloc);
-           }
-#endif
-         if ((fp = curlfopen(cinfo, dloc, 0, chksum, chksumtype, 0)) == 0)
-           continue;
-         /* got it, now reconstruct */
-         newfd = opentmpfile();
-#ifdef FEDORA
-         sprintf(cmd, "applydeltarpm -a '%s' /dev/fd/%d /dev/fd/%d", archstr, fileno(fp), newfd);
-#else
-         sprintf(cmd, "applydeltarpm /dev/fd/%d /dev/fd/%d", fileno(fp), newfd);
-#endif
-         fcntl(fileno(fp), F_SETFD, 0);
-         if (system(cmd))
-           {
-             close(newfd);
-             fclose(fp);
-             continue;
-           }
-         lseek(newfd, 0, SEEK_SET);
-         chksumtype = 0;
-         chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
-         if (chksumtype && !verify_checksum(newfd, loc, chksum, chksumtype))
-           {
-             close(newfd);
-             fclose(fp);
-             continue;
-           }
-         retfp = fdopen(newfd, "r");
-         fclose(fp);
-         break;
-       }
-    }
-  dataiterator_free(&di);
-  solv_free(matchname);
-  return retfp;
-}
diff --git a/libsolv-0.6.15/examples/solv/deltarpm.h b/libsolv-0.6.15/examples/solv/deltarpm.h
deleted file mode 100644 (file)
index 528e5a2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-extern FILE *trydeltadownload(Solvable *s, const char *loc);
diff --git a/libsolv-0.6.15/examples/solv/fastestmirror.c b/libsolv-0.6.15/examples/solv/fastestmirror.c
deleted file mode 100644 (file)
index d2ebd97..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <poll.h>
-#include <errno.h>
-
-#include "util.h"
-
-#include "fastestmirror.h"
-
-void
-findfastest(char **urls, int nurls)
-{
-  int i, j, port;
-  int *socks, qc;
-  struct pollfd *fds;
-  char *p, *p2, *q;
-  char portstr[16];
-  struct addrinfo hints, *result;;
-
-  fds = solv_calloc(nurls, sizeof(*fds));
-  socks = solv_calloc(nurls, sizeof(*socks));
-  for (i = 0; i < nurls; i++)
-    {
-      socks[i] = -1;
-      p = strchr(urls[i], '/');
-      if (!p)
-       continue;
-      if (p[1] != '/')
-       continue;
-      p += 2;
-      q = strchr(p, '/');
-      qc = 0;
-      if (q)
-       {
-         qc = *q;
-         *q = 0;
-       }
-      if ((p2 = strchr(p, '@')) != 0)
-       p = p2 + 1;
-      port = 80;
-      if (!strncmp("https:", urls[i], 6))
-       port = 443;
-      else if (!strncmp("ftp:", urls[i], 4))
-       port = 21;
-      if ((p2 = strrchr(p, ':')) != 0)
-       {
-         port = atoi(p2 + 1);
-         if (q)
-           *q = qc;
-         q = p2;
-         qc = *q;
-         *q = 0;
-       }
-      sprintf(portstr, "%d", port);
-      memset(&hints, 0, sizeof(struct addrinfo));
-      hints.ai_family = AF_UNSPEC;
-      hints.ai_socktype = SOCK_STREAM;
-      hints.ai_flags = AI_NUMERICSERV;
-      result = 0;
-      if (!getaddrinfo(p, portstr, &hints, &result))
-       {
-         socks[i] = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
-         if (socks[i] >= 0)
-           {
-             fcntl(socks[i], F_SETFL, O_NONBLOCK);
-             if (connect(socks[i], result->ai_addr, result->ai_addrlen) == -1)
-               {
-                 if (errno != EINPROGRESS)
-                   {
-                     close(socks[i]);
-                     socks[i] = -1;
-                   }
-               }
-           }
-         freeaddrinfo(result);
-       }
-      if (q)
-       *q = qc;
-    }
-  for (;;)
-    {
-      for (i = j = 0; i < nurls; i++)
-       {
-         if (socks[i] < 0)
-           continue;
-         fds[j].fd = socks[i];
-         fds[j].events = POLLOUT;
-         j++;
-       }
-      if (j < 2)
-       {
-         i = j - 1;
-         break;
-       }
-      if (poll(fds, j, 10000) <= 0)
-       {
-         i = -1;       /* something is wrong */
-         break;
-       }
-      for (i = 0; i < j; i++)
-       if ((fds[i].revents & POLLOUT) != 0)
-         {
-           int soe = 0;
-           socklen_t soel = sizeof(int);
-           if (getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, &soe, &soel) == -1 || soe != 0)
-             {
-               /* connect failed, kill socket */
-               for (j = 0; j < nurls; j++)
-                 if (socks[j] == fds[i].fd)
-                   {
-                     close(socks[j]);
-                     socks[j] = -1;
-                   }
-               i = j + 1;
-               break;
-             }
-           break;      /* horray! */
-         }
-      if (i == j + 1)
-       continue;
-      if (i == j)
-        i = -1;                /* something is wrong, no bit was set */
-      break;
-    }
-  /* now i contains the fastest fd index */
-  if (i >= 0)
-    {
-      for (j = 0; j < nurls; j++)
-       if (socks[j] == fds[i].fd)
-         break;
-      if (j != 0)
-       {
-         char *url0 = urls[0];
-         urls[0] = urls[j];
-         urls[j] = url0;
-       }
-    }
-  for (i = j = 0; i < nurls; i++)
-    if (socks[i] >= 0)
-      close(socks[i]);
-  free(socks);
-  free(fds);
-}
diff --git a/libsolv-0.6.15/examples/solv/fastestmirror.h b/libsolv-0.6.15/examples/solv/fastestmirror.h
deleted file mode 100644 (file)
index 53251ef..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern void findfastest(char **urls, int nurls);
-
diff --git a/libsolv-0.6.15/examples/solv/fileconflicts.c b/libsolv-0.6.15/examples/solv/fileconflicts.c
deleted file mode 100644 (file)
index 982de85..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_rpmdb.h"
-#include "pool_fileconflicts.h"
-
-#include "fileconflicts.h"
-
-struct fcstate {
-  FILE **newpkgsfps;
-  Queue *checkq;
-  int newpkgscnt;
-  void *rpmstate;
-};
-
-static void *
-fileconflict_cb(Pool *pool, Id p, void *cbdata)
-{
-  struct fcstate *fcstate = cbdata;
-  Solvable *s;
-  Id rpmdbid;
-  int i;
-  FILE *fp; 
-
-  s = pool_id2solvable(pool, p);
-  if (pool->installed && s->repo == pool->installed)
-    {    
-      if (!s->repo->rpmdbid)
-        return 0;
-      rpmdbid = s->repo->rpmdbid[p - s->repo->start];
-      if (!rpmdbid)
-        return 0;
-      return rpm_byrpmdbid(fcstate->rpmstate, rpmdbid);
-    }    
-  for (i = 0; i < fcstate->newpkgscnt; i++) 
-    if (fcstate->checkq->elements[i] == p)
-      break;
-  if (i == fcstate->newpkgscnt)
-    return 0;
-  fp = fcstate->newpkgsfps[i];
-  if (!fp)
-    return 0;
-  rewind(fp);
-  return rpm_byfp(fcstate->rpmstate, fp, pool_solvable2str(pool, s)); 
-}
-
-int
-checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Queue *conflicts)
-{
-  struct fcstate fcstate;
-  int i;
-
-  printf("Searching for file conflicts\n");
-  queue_init(conflicts);
-  fcstate.rpmstate = rpm_state_create(pool, pool_get_rootdir(pool));
-  fcstate.newpkgscnt = newpkgs;
-  fcstate.checkq = checkq;
-  fcstate.newpkgsfps = newpkgsfps;
-  pool_findfileconflicts(pool, checkq, newpkgs, conflicts, FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, &fileconflict_cb, &fcstate);
-  fcstate.rpmstate = rpm_state_free(fcstate.rpmstate);
-  if (conflicts->count)
-    {
-      printf("\n");
-      for (i = 0; i < conflicts->count; i += 6)
-       printf("file %s of package %s conflicts with package %s\n", pool_id2str(pool, conflicts->elements[i]), pool_solvid2str(pool, conflicts->elements[i + 1]), pool_solvid2str(pool, conflicts->elements[i + 4]));
-      printf("\n");
-    }
-  return conflicts->count;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/fileconflicts.h b/libsolv-0.6.15/examples/solv/fileconflicts.h
deleted file mode 100644 (file)
index e3f31e7..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern int checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Queue *conflicts);
-
diff --git a/libsolv-0.6.15/examples/solv/fileprovides.c b/libsolv-0.6.15/examples/solv/fileprovides.c
deleted file mode 100644 (file)
index 2654ab6..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-
-#include "fileprovides.h"
-
-static void
-rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_inst)
-{
-  Repo *repo;
-  Repodata *data;
-  Map providedids;
-  Queue fileprovidesq;
-  int i, j, n;
-  struct repoinfo *cinfo;
-
-  map_init(&providedids, pool->ss.nstrings);
-  queue_init(&fileprovidesq);
-  for (i = 0; i < addedfileprovides->count; i++)
-    MAPSET(&providedids, addedfileprovides->elements[i]);
-  FOR_REPOS(i, repo)
-    {
-      /* make sure all repodatas but the first are extensions */
-      if (repo->nrepodata < 2)
-       continue;
-      cinfo = repo->appdata;
-      if (!cinfo)
-       continue;       /* cmdline */
-      if (cinfo->incomplete)
-       continue;
-      data = repo_id2repodata(repo, 1);
-      if (data->loadcallback)
-        continue;
-      for (j = 2; j < repo->nrepodata; j++)
-       {
-         Repodata *edata = repo_id2repodata(repo, j);
-         if (!edata->loadcallback)
-           break;
-       }
-      if (j < repo->nrepodata)
-       continue;       /* found a non-extension repodata, can't rewrite  */
-      if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
-       {
-         if (repo == pool->installed && addedfileprovides_inst)
-           {
-             for (j = 0; j < addedfileprovides->count; j++)
-               MAPCLR(&providedids, addedfileprovides->elements[j]);
-             for (j = 0; j < addedfileprovides_inst->count; j++)
-               MAPSET(&providedids, addedfileprovides_inst->elements[j]);
-           }
-         n = 0;
-         for (j = 0; j < fileprovidesq.count; j++)
-           if (MAPTST(&providedids, fileprovidesq.elements[j]))
-             n++;
-         if (repo == pool->installed && addedfileprovides_inst)
-           {
-             for (j = 0; j < addedfileprovides_inst->count; j++)
-               MAPCLR(&providedids, addedfileprovides_inst->elements[j]);
-             for (j = 0; j < addedfileprovides->count; j++)
-               MAPSET(&providedids, addedfileprovides->elements[j]);
-             if (n == addedfileprovides_inst->count)
-               continue;       /* nothing new added */
-           }
-         else if (n == addedfileprovides->count)
-           continue;   /* nothing new added */
-       }
-      repodata_set_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, repo == pool->installed && addedfileprovides_inst ? addedfileprovides_inst : addedfileprovides);
-      repodata_internalize(data);
-      writecachedrepo(cinfo, 0, data);
-    }
-  queue_free(&fileprovidesq);
-  map_free(&providedids);
-}
-
-void
-addfileprovides(Pool *pool)
-{
-  Queue addedfileprovides;
-  Queue addedfileprovides_inst;
-
-  queue_init(&addedfileprovides);
-  queue_init(&addedfileprovides_inst);
-  pool_addfileprovides_queue(pool, &addedfileprovides, &addedfileprovides_inst);
-  if (addedfileprovides.count || addedfileprovides_inst.count)
-    rewrite_repos(pool, &addedfileprovides, &addedfileprovides_inst);
-  queue_free(&addedfileprovides);
-  queue_free(&addedfileprovides_inst);
-}
diff --git a/libsolv-0.6.15/examples/solv/fileprovides.h b/libsolv-0.6.15/examples/solv/fileprovides.h
deleted file mode 100644 (file)
index 1069d5a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-void addfileprovides(Pool *pool);
diff --git a/libsolv-0.6.15/examples/solv/mirror.c b/libsolv-0.6.15/examples/solv/mirror.c
deleted file mode 100644 (file)
index 52dc5ef..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "pool.h"
-#include "util.h"
-#include "fastestmirror.h"
-
-#include "mirror.h"
-
-char *
-findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep)
-{
-  char buf[4096], *bp, *ep;
-  char **urls = 0;
-  int nurls = 0;
-  int i;
-
-  if (chksumtypep)
-    *chksumtypep = 0;
-  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
-    {
-      while (*bp == ' ' || *bp == '\t')
-       bp++;
-      if (chksumtypep && !*chksumtypep && !strncmp(bp, "<hash type=\"sha256\">", 20))
-       {
-         bp += 20;
-         if (solv_hex2bin((const char **)&bp, chksump, 32) == 32)
-           *chksumtypep = REPOKEY_TYPE_SHA256;
-         continue;
-       }
-      if (strncmp(bp, "<url", 4))
-       continue;
-      bp = strchr(bp, '>');
-      if (!bp)
-       continue;
-      bp++;
-      ep = strstr(bp, "repodata/repomd.xml</url>");
-      if (!ep)
-       continue;
-      *ep = 0;
-      if (strncmp(bp, "http", 4))
-       continue;
-      urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15);
-      urls[nurls++] = strdup(bp);
-    }
-  if (nurls)
-    {
-      if (nurls > 1)
-        findfastest(urls, nurls > 5 ? 5 : nurls);
-      bp = urls[0];
-      urls[0] = 0;
-      for (i = 0; i < nurls; i++)
-        solv_free(urls[i]);
-      solv_free(urls);
-      ep = strchr(bp, '/');
-      if ((ep = strchr(ep + 2, '/')) != 0)
-       {
-         *ep = 0;
-         printf("[using mirror %s]\n", bp);
-         *ep = '/';
-       }
-      return bp;
-    }
-  return 0;
-}
-
-char *
-findmirrorlisturl(FILE *fp)
-{
-  char buf[4096], *bp, *ep;
-  int i, l;
-  char **urls = 0;
-  int nurls = 0;
-
-  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
-    {
-      while (*bp == ' ' || *bp == '\t')
-       bp++;
-      if (!*bp || *bp == '#')
-       continue;
-      l = strlen(bp);
-      while (l > 0 && (bp[l - 1] == ' ' || bp[l - 1] == '\t' || bp[l - 1] == '\n'))
-       bp[--l] = 0;
-      if ((ep = strstr(bp, "url=")) != 0)
-       bp = ep + 4;
-      urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15);
-      urls[nurls++] = strdup(bp);
-    }
-  if (nurls)
-    {
-      if (nurls > 1)
-        findfastest(urls, nurls > 5 ? 5 : nurls);
-      bp = urls[0];
-      urls[0] = 0;
-      for (i = 0; i < nurls; i++)
-        solv_free(urls[i]);
-      solv_free(urls);
-      ep = strchr(bp, '/');
-      if ((ep = strchr(ep + 2, '/')) != 0)
-       {
-         *ep = 0;
-         printf("[using mirror %s]\n", bp);
-         *ep = '/';
-       }
-      return bp;
-    }
-  return 0;
-}
diff --git a/libsolv-0.6.15/examples/solv/mirror.h b/libsolv-0.6.15/examples/solv/mirror.h
deleted file mode 100644 (file)
index ed85a39..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-char *findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep);
-char *findmirrorlisturl(FILE *fp);
diff --git a/libsolv-0.6.15/examples/solv/patchjobs.c b/libsolv-0.6.15/examples/solv/patchjobs.c
deleted file mode 100644 (file)
index 64ad607..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "evr.h"
-#include "solver.h"
-
-void
-add_patchjobs(Pool *pool, Queue *job)
-{
-  Id p, pp;
-  int pruneyou = 0;
-  Map installedmap, multiversionmap;
-  Solvable *s;
-
-  map_init(&multiversionmap, 0);
-  map_init(&installedmap, pool->nsolvables);
-  solver_calculate_multiversionmap(pool, job, &multiversionmap);
-  if (pool->installed)
-    FOR_REPO_SOLVABLES(pool->installed, p, s)
-      MAPSET(&installedmap, p);
-
-  /* install all patches */
-  for (p = 1; p < pool->nsolvables; p++)
-    {
-      const char *type;
-      int r;
-      Id p2;
-
-      s = pool->solvables + p;
-      if (strncmp(pool_id2str(pool, s->name), "patch:", 6) != 0)
-       continue;
-      FOR_PROVIDES(p2, pp, s->name)
-       {
-         Solvable *s2 = pool->solvables + p2;
-         if (s2->name != s->name)
-           continue;
-         r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
-         if (r < 0 || (r == 0 && p > p2))
-           break;
-       }
-      if (p2)
-       continue;
-      type = solvable_lookup_str(s, SOLVABLE_PATCHCATEGORY);
-      if (type && !strcmp(type, "optional"))
-       continue;
-      r = solvable_trivial_installable_map(s, &installedmap, 0, &multiversionmap);
-      if (r == -1)
-       continue;
-      if (solvable_lookup_bool(s, UPDATE_RESTART) && r == 0)
-       {
-         if (!pruneyou++)
-           queue_empty(job);
-       }
-      else if (pruneyou)
-       continue;
-      queue_push2(job, SOLVER_SOLVABLE, p);
-    }
-  map_free(&installedmap);
-  map_free(&multiversionmap);
-}
diff --git a/libsolv-0.6.15/examples/solv/patchjobs.h b/libsolv-0.6.15/examples/solv/patchjobs.h
deleted file mode 100644 (file)
index 52edcbe..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern void add_patchjobs(Pool *pool, Queue *job);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo.c b/libsolv-0.6.15/examples/solv/repoinfo.c
deleted file mode 100644 (file)
index e08d160..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-#include "repo_rpmdb.h"
-#endif
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-#include "repo_deb.h"
-#endif
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-
-#if defined(SUSE) || defined(FEDORA)
-#include "repoinfo_config_yum.h"
-#endif
-#if defined(DEBIAN)
-#include "repoinfo_config_debian.h"
-#endif
-#if defined(MANDRIVA) || defined(MAGEIA)
-#include "repoinfo_config_urpmi.h"
-#endif
-
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-#include "repoinfo_system_rpm.h"
-#endif
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-#include "repoinfo_system_debian.h"
-#endif
-
-#ifdef ENABLE_RPMMD
-#include "repoinfo_type_rpmmd.h"
-#endif
-#ifdef ENABLE_SUSEREPO
-#include "repoinfo_type_susetags.h"
-#endif
-#ifdef ENABLE_DEBIAN
-#include "repoinfo_type_debian.h"
-#endif
-#ifdef ENABLE_MDKREPO
-#include "repoinfo_type_mdk.h"
-#endif
-
-static int
-repoinfos_sort_cmp(const void *ap, const void *bp)
-{
-  const struct repoinfo *a = ap;
-  const struct repoinfo *b = bp;
-  return strcmp(a->alias, b->alias);
-}
-
-void
-sort_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
-{
-  qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), repoinfos_sort_cmp);
-}
-
-void
-free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
-{
-  int i, j;
-  for (i = 0; i < nrepoinfos; i++)
-    {
-      struct repoinfo *cinfo = repoinfos + i;
-      solv_free(cinfo->name);
-      solv_free(cinfo->alias);
-      solv_free(cinfo->path);
-      solv_free(cinfo->metalink);
-      solv_free(cinfo->mirrorlist);
-      solv_free(cinfo->baseurl);
-      for (j = 0; j < cinfo->ncomponents; j++)
-        solv_free(cinfo->components[j]);
-      solv_free(cinfo->components);
-    }
-  solv_free(repoinfos);
-#if defined(SUSE) || defined(FEDORA)
-  yum_substitute((Pool *)0, 0);                /* free data */
-#endif
-}
-
-struct repoinfo *
-read_repoinfos(Pool *pool, int *nrepoinfosp)
-{
-  struct repoinfo *repoinfos = 0;
-#if defined(SUSE) || defined(FEDORA)
-  repoinfos = read_repoinfos_yum(pool, nrepoinfosp);
-#endif
-#if defined(MANDRIVA) || defined(MAGEIA)
-  repoinfos = read_repoinfos_urpmi(pool, nrepoinfosp);
-#endif
-#if defined(DEBIAN)
-  repoinfos = read_repoinfos_debian(pool, nrepoinfosp);
-#endif
-  return repoinfos;
-}
-
-int
-read_installed_repo(struct repoinfo *cinfo, Pool *pool)
-{
-  int r = 1;
-  cinfo->type = TYPE_INSTALLED;
-  cinfo->repo = repo_create(pool, "@System");
-  cinfo->repo->appdata = cinfo;
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-  r = read_installed_rpm(cinfo);
-#endif
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-  r = read_installed_debian(cinfo);
-#endif
-  pool_set_installed(pool, cinfo->repo);
-  return r;
-}
-
-int
-is_cmdline_package(const char *filename)
-{
-  int l = strlen(filename);
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-  if (l > 4 && !strcmp(filename + l - 4, ".rpm"))
-    return 1;
-#endif
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-  if (l > 4 && !strcmp(filename + l - 4, ".deb"))
-    return 1;
-#endif
-  return 0;
-}
-
-Id
-add_cmdline_package(Repo *repo, const char *filename)
-{
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-  return repo_add_rpm(repo, filename, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
-#endif
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-  return repo_add_deb(repo, filename, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
-#endif
-  return 0;
-}
-
-void
-commit_transactionelement(Pool *pool, Id type, Id p, FILE *fp)
-{
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-  commit_transactionelement_rpm(pool, type, p, fp);
-#endif
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-  commit_transactionelement_debian(pool, type, p, fp);
-#endif
-}
-
-void
-add_ext_keys(Repodata *data, Id handle, const char *ext)
-{
-  static Id langtags[] = {
-    SOLVABLE_SUMMARY,     REPOKEY_TYPE_STR,
-    SOLVABLE_DESCRIPTION, REPOKEY_TYPE_STR,
-    SOLVABLE_EULA,        REPOKEY_TYPE_STR,
-    SOLVABLE_MESSAGEINS,  REPOKEY_TYPE_STR,
-    SOLVABLE_MESSAGEDEL,  REPOKEY_TYPE_STR,
-    SOLVABLE_CATEGORY,    REPOKEY_TYPE_ID,
-    0, 0
-  };
-  if (!strcmp(ext, "DL"))
-    {
-      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOSITORY_DELTAINFO);
-      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_FLEXARRAY);
-    }
-  else if (!strcmp(ext, "FL"))
-    {
-      repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_FILELIST);
-      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRSTRARRAY);
-    }
-  else if (!strcmp(ext, "DU"))
-    {
-      repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_DISKUSAGE);
-      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRNUMNUMARRAY);
-    }
-  else
-    {
-      Pool *pool = data->repo->pool;
-      int i;
-      for (i = 0; langtags[i]; i += 2)
-       {
-         repodata_add_idarray(data, handle, REPOSITORY_KEYS, pool_id2langid(pool, langtags[i], ext, 1));
-         repodata_add_idarray(data, handle, REPOSITORY_KEYS, langtags[i + 1]);
-       }
-    }
-}
-
-int
-load_stub(Pool *pool, Repodata *data, void *dp)
-{
-  struct repoinfo *cinfo = data->repo->appdata;
-  switch (cinfo->type)
-    {
-#ifdef ENABLE_SUSEREPO
-    case TYPE_SUSETAGS:
-      return susetags_load_ext(data->repo, data);
-#endif
-#ifdef ENABLE_RPMMD
-    case TYPE_RPMMD:
-      return repomd_load_ext(data->repo, data);
-#endif
-#ifdef ENABLE_MDKREPO
-    case TYPE_MDK:
-      return mdk_load_ext(data->repo, data);
-#endif
-    default:
-      /* debian does not have any ext data yet */
-      return 0;
-    }
-}
-
-void
-read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
-{
-  Repo *repo;
-  int i;
-  Pool *sigpool = 0;
-
-  for (i = 0; i < nrepoinfos; i++)
-    {
-      struct repoinfo *cinfo = repoinfos + i;
-      if (!cinfo->enabled)
-       continue;
-
-      repo = repo_create(pool, cinfo->alias);
-      cinfo->repo = repo;
-      repo->appdata = cinfo;
-      repo->priority = 99 - cinfo->priority;
-
-      if ((!cinfo->autorefresh || cinfo->metadata_expire) && usecachedrepo(cinfo, 0, 0))
-       {
-         printf("repo '%s':", cinfo->alias);
-         printf(" cached\n");
-         continue;
-       }
-
-      switch (cinfo->type)
-       {
-#ifdef ENABLE_RPMMD
-        case TYPE_RPMMD:
-         repomd_load(cinfo, &sigpool);
-         break;
-#endif
-#ifdef ENABLE_SUSEREPO
-        case TYPE_SUSETAGS:
-         susetags_load(cinfo, &sigpool);
-         break;
-#endif
-#ifdef ENABLE_DEBIAN
-        case TYPE_DEBIAN:
-         debian_load(cinfo, &sigpool);
-         break;
-#endif
-#ifdef ENABLE_MDKREPO
-        case TYPE_MDK:
-         mdk_load(cinfo, &sigpool);
-         break;
-#endif
-       default:
-         printf("unsupported repo '%s': skipped\n", cinfo->alias);
-         repo_free(repo, 1);
-         cinfo->repo = 0;
-         break;
-       }
-    }
-  if (sigpool)
-    pool_free(sigpool);
-}
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo.h b/libsolv-0.6.15/examples/solv/repoinfo.h
deleted file mode 100644 (file)
index 04f94b7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-struct repoinfo {
-  Repo *repo;
-
-  int type;
-  char *alias;
-  char *name;
-  int enabled;
-  int autorefresh;
-  char *baseurl;
-  char *metalink;
-  char *mirrorlist;
-  char *path;
-  int pkgs_gpgcheck;
-  int repo_gpgcheck;
-  int priority;
-  int keeppackages;
-  int metadata_expire;
-  char **components;
-  int ncomponents;
-  int cookieset;
-  unsigned char cookie[32];
-  int extcookieset;
-  unsigned char extcookie[32];
-  int incomplete;
-};
-
-#define TYPE_UNKNOWN    0
-#define TYPE_SUSETAGS   1
-#define TYPE_RPMMD      2
-#define TYPE_PLAINDIR   3
-#define TYPE_DEBIAN     4
-#define TYPE_MDK        5
-
-#define TYPE_INSTALLED  16
-#define TYPE_CMDLINE    17
-
-#define METADATA_EXPIRE (60 * 15)
-
-extern void sort_repoinfos(struct repoinfo *repoinfos, int nrepoinfos);
-extern void free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos);
-extern void read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos);
-extern struct repoinfo *read_repoinfos(Pool *pool, int *nrepoinfosp);
-
-extern int read_installed_repo(struct repoinfo *cinfo, Pool *pool);
-
-extern int is_cmdline_package(const char *filename);
-extern Id add_cmdline_package(Repo *repo, const char *filename);
-
-extern void commit_transactionelement(Pool *pool, Id type, Id p, FILE *fp);
-
-extern void add_ext_keys(Repodata *data, Id handle, const char *ext);
-extern int load_stub(Pool *pool, Repodata *data, void *dp);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_cache.c b/libsolv-0.6.15/examples/solv/repoinfo_cache.c
deleted file mode 100644 (file)
index ec4fe57..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_solv.h"
-#include "repo_write.h"
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-
-#define COOKIE_IDENT "1.1"
-
-#define SOLVCACHE_PATH "/var/cache/solv"
-
-static char *userhome;
-
-void
-set_userhome()
-{
-  userhome = getenv("HOME");
-  if (userhome && userhome[0] != '/') 
-    userhome = 0; 
-}
-
-void
-calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out)
-{
-  char buf[4096];
-  Chksum *h = solv_chksum_create(chktype);
-  int l;
-
-  solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT));
-  while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
-    solv_chksum_add(h, buf, l);
-  rewind(fp);
-  solv_chksum_free(h, out);
-}
-
-void
-calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out)
-{
-  Chksum *h = solv_chksum_create(chktype);
-  solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT));
-  if (cookie)
-    solv_chksum_add(h, cookie, 32);
-  solv_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev));
-  solv_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino));
-  solv_chksum_add(h, &stb->st_size, sizeof(stb->st_size));
-  solv_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime));
-  solv_chksum_free(h, out);
-}
-
-char *
-calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc)
-{
-  char *q, *p;
-  int l;
-  if (!forcesystemloc && userhome && getuid())
-    p = pool_tmpjoin(repo->pool, userhome, "/.solvcache/", 0);
-  else
-    p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", 0);
-  l = strlen(p);
-  p = pool_tmpappend(repo->pool, p, repo->name, 0);
-  if (repoext)
-    {
-      p = pool_tmpappend(repo->pool, p, "_", repoext);
-      p = pool_tmpappend(repo->pool, p, ".solvx", 0);
-    }
-  else
-    p = pool_tmpappend(repo->pool, p, ".solv", 0);
-  q = p + l;
-  if (*q == '.')
-    *q = '_';
-  for (; *q; q++)
-    if (*q == '/')
-      *q = '_';
-  return p;
-}
-
-int
-usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark)
-{
-  Repo *repo = cinfo->repo;
-  FILE *fp;
-  unsigned char *cookie = repoext ? cinfo->extcookie : (cinfo->cookieset ? cinfo->cookie : 0);
-  unsigned char mycookie[32];
-  unsigned char myextcookie[32];
-  int flags;
-  int forcesystemloc;
-
-  if (repoext && !cinfo->extcookieset)
-    return 0;  /* huh? */
-  forcesystemloc = mark & 2 ? 0 : 1;
-  if (mark < 2 && userhome && getuid())
-    {
-      /* first try home location */
-      int res = usecachedrepo(cinfo, repoext, mark | 2);
-      if (res)
-       return res;
-    }
-  mark &= 1;
-  if (!(fp = fopen(calc_cachepath(repo, repoext, forcesystemloc), "r")))
-    return 0;
-  if (!repoext && !cinfo->cookieset && cinfo->autorefresh && cinfo->metadata_expire != -1)
-    {
-      struct stat stb;         /* no cookie set yet, check cache expiry time */
-      if (fstat(fileno(fp), &stb) || time(0) - stb.st_mtime >= cinfo->metadata_expire)
-       {
-         fclose(fp);
-         return 0;
-       }
-    }
-  if (fseek(fp, -sizeof(mycookie), SEEK_END) || fread(mycookie, sizeof(mycookie), 1, fp) != 1)
-    {
-      fclose(fp);
-      return 0;
-    }
-  if (cookie && memcmp(cookie, mycookie, sizeof(mycookie)) != 0)
-    {
-      fclose(fp);
-      return 0;
-    }
-  if (cinfo->type != TYPE_INSTALLED && !repoext)
-    {
-      if (fseek(fp, -sizeof(mycookie) * 2, SEEK_END) || fread(myextcookie, sizeof(myextcookie), 1, fp) != 1)
-       {
-         fclose(fp);
-         return 0;
-       }
-    }
-  rewind(fp);
-
-  flags = 0;
-  if (repoext)
-    {
-      flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
-      if (strcmp(repoext, "DL") != 0)
-        flags |= REPO_LOCALPOOL;       /* no local pool for DL so that we can compare IDs */
-    }
-  if (repo_add_solv(repo, fp, flags))
-    {
-      fclose(fp);
-      return 0;
-    }
-  if (cinfo->type != TYPE_INSTALLED && !repoext)
-    {
-      memcpy(cinfo->cookie, mycookie, sizeof(mycookie));
-      cinfo->cookieset = 1;
-      memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie));
-      cinfo->extcookieset = 1;
-    }
-  if (mark)
-    futimens(fileno(fp), 0);   /* try to set modification time */
-  fclose(fp);
-  return 1;
-}
-
-static void
-switchtowritten(struct repoinfo *cinfo, const char *repoext, Repodata *repodata, char *tmpl)
-{
-  Repo *repo = cinfo->repo;
-  FILE *fp;
-  int i;
-
-  if (!repoext && repodata)
-    return;    /* rewrite case, don't bother for the added fileprovides */
-  for (i = repo->start; i < repo->end; i++)
-   if (repo->pool->solvables[i].repo != repo)
-     break;
-  if (i < repo->end)
-    return;    /* not a simple block */
-      /* switch to just saved repo to activate paging and save memory */
-  fp = fopen(tmpl, "r");
-  if (!fp)
-    return;
-  if (!repoext)
-    {
-      /* main repo */
-      repo_empty(repo, 1);
-      if (repo_add_solv(repo, fp, SOLV_ADD_NO_STUBS))
-       {
-         /* oops, no way to recover from here */
-         fprintf(stderr, "internal error\n");
-         exit(1);
-       }
-    }
-  else
-    {
-      int flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
-      /* make sure repodata contains complete repo */
-      /* (this is how repodata_write saves it) */
-      repodata_extend_block(repodata, repo->start, repo->end - repo->start);
-      repodata->state = REPODATA_LOADING;
-      if (strcmp(repoext, "DL") != 0)
-       flags |= REPO_LOCALPOOL;
-      repo_add_solv(repo, fp, flags);
-      repodata->state = REPODATA_AVAILABLE;    /* in case the load failed */
-    }
-  fclose(fp);
-}
-
-void
-writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata)
-{
-  Repo *repo = cinfo->repo;
-  FILE *fp;
-  int fd;
-  char *tmpl, *cachedir;
-
-  if (cinfo->incomplete || (repoext && !cinfo->extcookieset) || (!repoext && !cinfo->cookieset))
-    return;
-  cachedir = userhome && getuid() ? pool_tmpjoin(repo->pool, userhome, "/.solvcache", 0) : SOLVCACHE_PATH;
-  if (access(cachedir, W_OK | X_OK) != 0 && mkdir(cachedir, 0755) == 0)
-    printf("[created %s]\n", cachedir);
-  /* use dupjoin instead of tmpjoin because tmpl must survive repo_write */
-  tmpl = solv_dupjoin(cachedir, "/", ".newsolv-XXXXXX");
-  fd = mkstemp(tmpl);
-  if (fd < 0)
-    {
-      free(tmpl);
-      return;
-    }
-  fchmod(fd, 0444);
-  if (!(fp = fdopen(fd, "w")))
-    {
-      close(fd);
-      unlink(tmpl);
-      free(tmpl);
-      return;
-    }
-
-  if (!repodata)
-    repo_write(repo, fp);
-  else if (repoext)
-    repodata_write(repodata, fp);
-  else
-    {
-      int oldnrepodata = repo->nrepodata;
-      repo->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata;   /* XXX: do this right */
-      repo_write(repo, fp);
-      repo->nrepodata = oldnrepodata;
-    }
-
-  if (!repoext && cinfo->type != TYPE_INSTALLED)
-    {
-      if (!cinfo->extcookieset)
-       {
-         /* create the ext cookie and append it */
-         /* we just need some unique ID */
-         struct stat stb;
-         if (fstat(fileno(fp), &stb))
-           memset(&stb, 0, sizeof(stb));
-         calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->cookie, cinfo->extcookie);
-         cinfo->extcookieset = 1;
-       }
-      if (fwrite(cinfo->extcookie, 32, 1, fp) != 1)
-       {
-         fclose(fp);
-         unlink(tmpl);
-         free(tmpl);
-         return;
-       }
-    }
-  /* append our cookie describing the metadata state */
-  if (fwrite(repoext ? cinfo->extcookie : cinfo->cookie, 32, 1, fp) != 1)
-    {
-      fclose(fp);
-      unlink(tmpl);
-      free(tmpl);
-      return;
-    }
-  if (fclose(fp))
-    {
-      unlink(tmpl);
-      free(tmpl);
-      return;
-    }
-
-  switchtowritten(cinfo, repoext, repodata, tmpl);
-
-  if (!rename(tmpl, calc_cachepath(repo, repoext, 0)))
-    unlink(tmpl);
-  free(tmpl);
-}
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_cache.h b/libsolv-0.6.15/examples/solv/repoinfo_cache.h
deleted file mode 100644 (file)
index cc74715..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-struct repoinfo;
-struct stat;
-
-extern void set_userhome(void);
-extern char *calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc);
-extern void calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out);
-extern void calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out);
-
-extern int usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark);
-extern void  writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_debian.c b/libsolv-0.6.15/examples/solv/repoinfo_config_debian.c
deleted file mode 100644 (file)
index b369970..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifdef DEBIAN
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-
-#include "pool.h"
-#include "repo.h"
-
-#include "repoinfo.h"
-#include "repoinfo_config_debian.h"
-
-
-
-struct repoinfo *
-read_repoinfos_debian(Pool *pool, int *nrepoinfosp)
-{
-  FILE *fp;
-  char buf[4096];
-  char buf2[4096];
-  int l;
-  char *kp, *url, *distro;
-  struct repoinfo *repoinfos = 0, *cinfo;
-  int nrepoinfos = 0;
-  DIR *dir = 0;
-  struct dirent *ent;
-
-  fp = fopen("/etc/apt/sources.list", "r");
-  while (1)
-    {
-      if (!fp)
-       {
-         if (!dir)
-           {
-             dir = opendir("/etc/apt/sources.list.d");
-             if (!dir)
-               break;
-           }
-         if ((ent = readdir(dir)) == 0)
-           {
-             closedir(dir);
-             break;
-           }
-         if (ent->d_name[0] == '.')
-           continue;
-         l = strlen(ent->d_name);
-         if (l < 5 || strcmp(ent->d_name + l - 5, ".list") != 0)
-           continue;
-         snprintf(buf, sizeof(buf), "%s/%s", "/etc/apt/sources.list.d", ent->d_name);
-         if (!(fp = fopen(buf, "r")))
-           continue;
-       }
-      while(fgets(buf2, sizeof(buf2), fp))
-       {
-         l = strlen(buf2);
-         if (l == 0)
-           continue;
-         while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
-           buf2[--l] = 0;
-         kp = buf2;
-         while (*kp == ' ' || *kp == '\t')
-           kp++;
-         if (!*kp || *kp == '#')
-           continue;
-         if (strncmp(kp, "deb", 3) != 0)
-           continue;
-         kp += 3;
-         if (*kp != ' ' && *kp != '\t')
-           continue;
-         while (*kp == ' ' || *kp == '\t')
-           kp++;
-         if (!*kp)
-           continue;
-         url = kp;
-         while (*kp && *kp != ' ' && *kp != '\t')
-           kp++;
-         if (*kp)
-           *kp++ = 0;
-         while (*kp == ' ' || *kp == '\t')
-           kp++;
-         if (!*kp)
-           continue;
-         distro = kp;
-         while (*kp && *kp != ' ' && *kp != '\t')
-           kp++;
-         if (*kp)
-           *kp++ = 0;
-         while (*kp == ' ' || *kp == '\t')
-           kp++;
-         if (!*kp)
-           continue;
-         repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
-         cinfo = repoinfos + nrepoinfos++;
-         memset(cinfo, 0, sizeof(*cinfo));
-         cinfo->baseurl = strdup(url);
-         cinfo->alias = solv_dupjoin(url, "/", distro);
-         cinfo->name = strdup(distro);
-         cinfo->type = TYPE_DEBIAN;
-         cinfo->enabled = 1;
-         cinfo->autorefresh = 1;
-         cinfo->repo_gpgcheck = 1;
-         cinfo->metadata_expire = METADATA_EXPIRE;
-         while (*kp)
-           {
-             char *compo;
-             while (*kp == ' ' || *kp == '\t')
-               kp++;
-             if (!*kp)
-               break;
-             compo = kp;
-             while (*kp && *kp != ' ' && *kp != '\t')
-               kp++;
-             if (*kp)
-               *kp++ = 0;
-             cinfo->components = solv_extend(cinfo->components, cinfo->ncomponents, 1, sizeof(*cinfo->components), 15);
-             cinfo->components[cinfo->ncomponents++] = strdup(compo);
-           }
-       }
-      fclose(fp);
-      fp = 0;
-    }
-  *nrepoinfosp = nrepoinfos;
-  return repoinfos;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_debian.h b/libsolv-0.6.15/examples/solv/repoinfo_config_debian.h
deleted file mode 100644 (file)
index 64b3eb6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-extern struct repoinfo *read_repoinfos_debian(Pool *pool, int *nrepoinfosp);
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.c b/libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.c
deleted file mode 100644 (file)
index a79ea9b..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#if defined(MANDRIVA) || defined(MAGEIA)
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-
-#include "pool.h"
-#include "repo.h"
-
-#include "repoinfo.h"
-#include "repoinfo_config_urpmi.h"
-
-
-#define URPMI_CFG "/etc/urpmi/urpmi.cfg"
-
-
-struct repoinfo *
-read_repoinfos_urpmi(Pool *pool, int *nrepoinfosp)
-{
-  char buf[4096], *bp, *arg;
-  FILE *fp;
-  int l, insect = 0;
-  struct repoinfo *cinfo = 0;
-  struct repoinfo *repoinfos = 0;
-  int nrepoinfos = 0;
-
-  if ((fp = fopen(URPMI_CFG, "r")) == 0)
-    {
-      *nrepoinfosp = 0;
-      return 0;
-    }
-  while (fgets(buf, sizeof(buf), fp))
-    {
-      l = strlen(buf);
-      while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
-       buf[--l] = 0;
-      bp = buf;
-      while (l && (*bp == ' ' || *bp == '\t'))
-       {
-         l--;
-         bp++;
-       }
-      if (!l || *bp == '#')
-       continue;
-      if (!insect && bp[l - 1] == '{')
-       {
-         insect++;
-         bp[--l] = 0;
-         if (l > 0)
-           {
-             while (l && (bp[l - 1] == ' ' || bp[l - 1] == '\t'))
-               bp[--l] = 0;
-           }
-         if (l)
-           {
-             char *bbp = bp, *bbp2 = bp;
-             /* unescape */
-             while (*bbp)
-               {
-                 if (*bbp == '\\' && bbp[1])
-                   bbp++;
-                 *bbp2++ = *bbp++;
-               }
-             *bbp2 = 0;
-             repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
-             cinfo = repoinfos + nrepoinfos++;
-             memset(cinfo, 0, sizeof(*cinfo));
-             cinfo->alias = strdup(bp);
-             cinfo->type = TYPE_MDK;
-             cinfo->autorefresh = 1;
-             cinfo->priority = 99;
-             cinfo->enabled = 1;
-             cinfo->metadata_expire = METADATA_EXPIRE;
-           }
-         continue;
-       }
-      if (insect && *bp == '}')
-       {
-         insect--;
-         cinfo = 0;
-         continue;
-       }
-      if (!insect || !cinfo)
-       continue;
-      if ((arg = strchr(bp, ':')) != 0)
-       {
-         *arg++ = 0;
-         while (*arg == ' ' || *arg == '\t')
-           arg++;
-         if (!*arg)
-           arg = 0;
-       }
-      if (strcmp(bp, "ignore") == 0)
-       cinfo->enabled = 0;
-      if (strcmp(bp, "mirrorlist") == 0)
-       cinfo->mirrorlist = solv_strdup(arg);
-      if (strcmp(bp, "with-dir") == 0)
-       cinfo->path = solv_strdup(arg);
-    }
-  fclose(fp);
-  *nrepoinfosp = nrepoinfos;
-  return repoinfos;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.h b/libsolv-0.6.15/examples/solv/repoinfo_config_urpmi.h
deleted file mode 100644 (file)
index bb7374f..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern struct repoinfo *read_repoinfos_urpmi(Pool *pool, int *nrepoinfosp);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_yum.c b/libsolv-0.6.15/examples/solv/repoinfo_config_yum.c
deleted file mode 100644 (file)
index 6e2e66a..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-#if defined(SUSE) || defined(FEDORA)
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/utsname.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_rpmdb.h"
-
-#include "repoinfo.h"
-#include "repoinfo_config_yum.h"
-
-
-#ifdef FEDORA
-# define REPOINFO_PATH "/etc/yum.repos.d"
-#endif
-#ifdef SUSE
-# define REPOINFO_PATH "/etc/zypp/repos.d"
-#endif
-
-char *
-yum_substitute(Pool *pool, char *line)
-{
-  char *p, *p2;
-  static char *releaseevr;
-  static char *basearch;
-
-  if (!line)
-    {
-      solv_free(releaseevr);
-      releaseevr = 0;
-      solv_free(basearch);
-      basearch = 0;
-      return 0;
-    }
-  p = line;
-  while ((p2 = strchr(p, '$')) != 0)
-    {
-      if (!strncmp(p2, "$releasever", 11))
-       {
-         if (!releaseevr)
-           {
-             void *rpmstate;
-             Queue q;
-       
-             queue_init(&q);
-             rpmstate = rpm_state_create(pool, pool_get_rootdir(pool));
-             rpm_installedrpmdbids(rpmstate, "Providename", "redhat-release", &q);
-             if (q.count)
-               {
-                 void *handle;
-                 char *p;
-                 handle = rpm_byrpmdbid(rpmstate, q.elements[0]);
-                 releaseevr = handle ? rpm_query(handle, SOLVABLE_EVR) : 0;
-                 if (releaseevr && (p = strchr(releaseevr, '-')) != 0)
-                   *p = 0;
-               }
-             rpm_state_free(rpmstate);
-             queue_free(&q);
-             if (!releaseevr)
-               {
-                 fprintf(stderr, "no installed package provides 'redhat-release', cannot determine $releasever\n");
-                 exit(1);
-               }
-           }
-         *p2 = 0;
-         p = pool_tmpjoin(pool, line, releaseevr, p2 + 11);
-         p2 = p + (p2 - line);
-         line = p;
-         p = p2 + strlen(releaseevr);
-         continue;
-       }
-      if (!strncmp(p2, "$basearch", 9))
-       {
-         if (!basearch)
-           {
-             struct utsname un;
-             if (uname(&un))
-               {
-                 perror("uname");
-                 exit(1);
-               }
-             basearch = strdup(un.machine);
-             if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86"))
-               basearch[1] = '3';
-           }
-         *p2 = 0;
-         p = pool_tmpjoin(pool, line, basearch, p2 + 9);
-         p2 = p + (p2 - line);
-         line = p;
-         p = p2 + strlen(basearch);
-         continue;
-       }
-      p = p2 + 1;
-    }
-  return line;
-}
-
-struct repoinfo *
-read_repoinfos_yum(Pool *pool, int *nrepoinfosp)
-{
-  const char *reposdir = REPOINFO_PATH;
-  char buf[4096];
-  char buf2[4096], *kp, *vp, *kpe;
-  DIR *dir;
-  FILE *fp;
-  struct dirent *ent;
-  int l, rdlen;
-  struct repoinfo *repoinfos = 0, *cinfo;
-  int nrepoinfos = 0;
-
-  rdlen = strlen(reposdir);
-  dir = opendir(reposdir);
-  if (!dir)
-    {
-      *nrepoinfosp = 0;
-      return 0;
-    }
-  while ((ent = readdir(dir)) != 0)
-    {
-      if (ent->d_name[0] == '.')
-       continue;
-      l = strlen(ent->d_name);
-      if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0)
-       continue;
-      snprintf(buf, sizeof(buf), "%s/%s", reposdir, ent->d_name);
-      if ((fp = fopen(buf, "r")) == 0)
-       {
-         perror(buf);
-         continue;
-       }
-      cinfo = 0;
-      while(fgets(buf2, sizeof(buf2), fp))
-       {
-         l = strlen(buf2);
-         if (l == 0)
-           continue;
-         while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
-           buf2[--l] = 0;
-         kp = buf2;
-         while (*kp == ' ' || *kp == '\t')
-           kp++;
-         if (!*kp || *kp == '#')
-           continue;
-         if (strchr(kp, '$'))
-           kp = yum_substitute(pool, kp);
-         if (*kp == '[')
-           {
-             vp = strrchr(kp, ']');
-             if (!vp)
-               continue;
-             *vp = 0;
-             repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
-             cinfo = repoinfos + nrepoinfos++;
-             memset(cinfo, 0, sizeof(*cinfo));
-             cinfo->alias = strdup(kp + 1);
-             cinfo->type = TYPE_RPMMD;
-             cinfo->autorefresh = 1;
-             cinfo->priority = 99;
-#ifndef FEDORA
-             cinfo->repo_gpgcheck = 1;
-#endif
-             cinfo->metadata_expire = METADATA_EXPIRE;
-             continue;
-           }
-         if (!cinfo)
-           continue;
-          vp = strchr(kp, '=');
-         if (!vp)
-           continue;
-         for (kpe = vp - 1; kpe >= kp; kpe--)
-           if (*kpe != ' ' && *kpe != '\t')
-             break;
-         if (kpe == kp)
-           continue;
-         vp++;
-         while (*vp == ' ' || *vp == '\t')
-           vp++;
-         kpe[1] = 0;
-         if (!strcmp(kp, "name"))
-           cinfo->name = strdup(vp);
-         else if (!strcmp(kp, "enabled"))
-           cinfo->enabled = *vp == '0' ? 0 : 1;
-         else if (!strcmp(kp, "autorefresh"))
-           cinfo->autorefresh = *vp == '0' ? 0 : 1;
-         else if (!strcmp(kp, "gpgcheck"))
-           cinfo->pkgs_gpgcheck = *vp == '0' ? 0 : 1;
-         else if (!strcmp(kp, "repo_gpgcheck"))
-           cinfo->repo_gpgcheck = *vp == '0' ? 0 : 1;
-         else if (!strcmp(kp, "baseurl"))
-           cinfo->baseurl = strdup(vp);
-         else if (!strcmp(kp, "mirrorlist"))
-           {
-             if (strstr(vp, "metalink"))
-               cinfo->metalink = strdup(vp);
-             else
-               cinfo->mirrorlist = strdup(vp);
-           }
-         else if (!strcmp(kp, "path"))
-           {
-             if (vp && strcmp(vp, "/") != 0)
-               cinfo->path = strdup(vp);
-           }
-         else if (!strcmp(kp, "type"))
-           {
-             if (!strcmp(vp, "yast2"))
-               cinfo->type = TYPE_SUSETAGS;
-             else if (!strcmp(vp, "rpm-md"))
-               cinfo->type = TYPE_RPMMD;
-             else if (!strcmp(vp, "plaindir"))
-               cinfo->type = TYPE_PLAINDIR;
-             else if (!strcmp(vp, "mdk"))
-               cinfo->type = TYPE_MDK;
-             else
-               cinfo->type = TYPE_UNKNOWN;
-           }
-         else if (!strcmp(kp, "priority"))
-           cinfo->priority = atoi(vp);
-         else if (!strcmp(kp, "keeppackages"))
-           cinfo->keeppackages = *vp == '0' ? 0 : 1;
-       }
-      fclose(fp);
-      cinfo = 0;
-    }
-  closedir(dir);
-  *nrepoinfosp = nrepoinfos;
-  return repoinfos;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_config_yum.h b/libsolv-0.6.15/examples/solv/repoinfo_config_yum.h
deleted file mode 100644 (file)
index d7cb4f7..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern char *yum_substitute(Pool *pool, char *line);
-extern struct repoinfo *read_repoinfos_yum(Pool *pool, int *nrepoinfosp);
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_download.c b/libsolv-0.6.15/examples/solv/repoinfo_download.c
deleted file mode 100644 (file)
index 5ba3014..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "solv_xfopen.h"
-
-#include "repoinfo.h"
-#include "mirror.h"
-#include "checksig.h"
-#include "repoinfo_download.h"
-
-static inline int
-opentmpfile()
-{
-  char tmpl[100];
-  int fd;
-
-  strcpy(tmpl, "/var/tmp/solvXXXXXX");
-  fd = mkstemp(tmpl);
-  if (fd < 0) 
-    {    
-      perror("mkstemp");
-      exit(1);
-    }    
-  unlink(tmpl);
-  return fd;
-}
-
-int
-verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype)
-{
-  char buf[1024];
-  const unsigned char *sum;
-  Chksum *h;
-  int l;
-
-  h = solv_chksum_create(chksumtype);
-  if (!h)
-    {
-      printf("%s: unknown checksum type\n", file);
-      return 0;
-    }
-  while ((l = read(fd, buf, sizeof(buf))) > 0)
-    solv_chksum_add(h, buf, l);
-  lseek(fd, 0, SEEK_SET);
-  l = 0;
-  sum = solv_chksum_get(h, &l);
-  if (memcmp(sum, chksum, l))
-    {
-      printf("%s: checksum mismatch\n", file);
-      solv_chksum_free(h, 0);
-      return 0;
-    }
-  solv_chksum_free(h, 0);
-  return 1;
-}
-
-FILE *
-curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete)
-{
-  FILE *fp;
-  pid_t pid;
-  int fd;
-  int status;
-  char url[4096];
-  const char *baseurl = cinfo->baseurl;
-
-  if (!baseurl)
-    {
-      if (!cinfo->metalink && !cinfo->mirrorlist)
-        return 0;
-      if (file != cinfo->metalink && file != cinfo->mirrorlist)
-       {
-         unsigned char mlchksum[32];
-         Id mlchksumtype = 0;
-         fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0);
-         if (!fp)
-           return 0;
-         if (cinfo->metalink)
-           cinfo->baseurl = findmetalinkurl(fp, mlchksum, &mlchksumtype);
-         else
-           cinfo->baseurl = findmirrorlisturl(fp);
-         fclose(fp);
-         if (!cinfo->baseurl)
-           return 0;
-#ifdef FEDORA
-         if (strchr(cinfo->baseurl, '$'))
-           {
-             char *b = yum_substitute(cinfo->repo->pool, cinfo->baseurl);
-             free(cinfo->baseurl);
-             cinfo->baseurl = strdup(b);
-           }
-#endif
-         if (!chksumtype && mlchksumtype && !strcmp(file, "repodata/repomd.xml"))
-           {
-             chksumtype = mlchksumtype;
-             chksum = mlchksum;
-           }
-         return curlfopen(cinfo, file, uncompress, chksum, chksumtype, markincomplete);
-       }
-      snprintf(url, sizeof(url), "%s", file);
-    }
-  else
-    {
-      const char *path = cinfo->path && strcmp(cinfo->path, "/") != 0 ? cinfo->path : "";
-      int l = strlen(baseurl);
-      int pl = strlen(path);
-      const char *sep = l && baseurl[l - 1] == '/' ? "" : "/";
-      const char *psep = pl && cinfo->path[pl - 1] == '/' ? "" : "/";
-      snprintf(url, sizeof(url), "%s%s%s%s%s", baseurl, sep, path, psep, file);
-    }
-  fd = opentmpfile();
-  // printf("url: %s\n", url);
-  if ((pid = fork()) == (pid_t)-1)
-    {
-      perror("fork");
-      exit(1);
-    }
-  if (pid == 0)
-    {
-      if (fd != 1)
-       {
-          dup2(fd, 1);
-         close(fd);
-       }
-      execlp("curl", "curl", "-f", "-s", "-L", url, (char *)0);
-      perror("curl");
-      _exit(0);
-    }
-  status = 0;
-  while (waitpid(pid, &status, 0) != pid)
-    ;
-  if (lseek(fd, 0, SEEK_END) == 0 && (!status || !chksumtype))
-    {
-      /* empty file */
-      close(fd);
-      return 0;
-    }
-  lseek(fd, 0, SEEK_SET);
-  if (status)
-    {
-      printf("%s: download error %d\n", file, status >> 8 ? status >> 8 : status);
-      if (markincomplete)
-       cinfo->incomplete = 1;
-      close(fd);
-      return 0;
-    }
-  if (chksumtype && !verify_checksum(fd, file, chksum, chksumtype))
-    {
-      if (markincomplete)
-       cinfo->incomplete = 1;
-      close(fd);
-      return 0;
-    }
-  fcntl(fd, F_SETFD, FD_CLOEXEC);
-  if (uncompress)
-    {
-      if (solv_xfopen_iscompressed(file) < 0)
-       {
-         printf("%s: unsupported compression\n", file);
-         if (markincomplete)
-           cinfo->incomplete = 1;
-         close(fd);
-         return 0;
-       }
-      fp = solv_xfopen_fd(file, fd, "r");
-    }
-  else
-    fp = fdopen(fd, "r");
-  if (!fp)
-    close(fd);
-  return fp;
-}
-
-FILE *
-downloadpackage(Solvable *s, const char *loc)
-{
-  const unsigned char *chksum;
-  Id chksumtype;
-  struct repoinfo *cinfo = s->repo->appdata;
-
-#ifdef ENABLE_SUSEREPO
-  if (cinfo->type == TYPE_SUSETAGS)
-    {
-      const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR);
-      loc = pool_tmpjoin(s->repo->pool, datadir ? datadir : "suse", "/", loc);
-    }
-#endif
-  chksumtype = 0;
-  chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
-  return curlfopen(cinfo, loc, 0, chksum, chksumtype, 0);
-}
-
-int
-downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool)
-{
-  FILE *sigfp;
-  sigfp = curlfopen(cinfo, sigurl, 0, 0, 0, 0); 
-  if (!sigfp)
-    {    
-      printf(" unsigned, skipped\n");
-      return 0;
-    }    
-  if (!*sigpool)
-    *sigpool = read_sigs();
-  if (!checksig(*sigpool, fp, sigfp))
-    {    
-      printf(" checksig failed, skipped\n");
-      fclose(sigfp);
-      return 0;
-    }    
-  fclose(sigfp);
-  return 1;
-}
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_download.h b/libsolv-0.6.15/examples/solv/repoinfo_download.h
deleted file mode 100644 (file)
index 2dfeaa0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-int verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype);
-
-FILE *curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete);
-
-FILE *downloadpackage(Solvable *s, const char *loc);
-int downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_debian.c b/libsolv-0.6.15/examples/solv/repoinfo_system_debian.c
deleted file mode 100644 (file)
index f01be60..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_deb.h"
-#include "transaction.h"
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_system_debian.h"
-
-static void
-rundpkg(const char *arg, const char *name, int dupfd3, const char *rootdir)
-{
-  pid_t pid;
-  int status;
-
-  if ((pid = fork()) == (pid_t)-1)
-    {
-      perror("fork");
-      exit(1);
-    }
-  if (pid == 0)
-    {
-      if (!rootdir)
-       rootdir = "/";
-      if (dupfd3 != -1 && dupfd3 != 3)
-       {
-         dup2(dupfd3, 3);
-         close(dupfd3);
-       }
-      if (dupfd3 != -1)
-       fcntl(3, F_SETFD, 0);   /* clear CLOEXEC */
-      if (strcmp(arg, "--install") == 0)
-       execlp("dpkg", "dpkg", "--install", "--root", rootdir, "--force", "all", name, (char *)0);
-      else
-       execlp("dpkg", "dpkg", "--remove", "--root", rootdir, "--force", "all", name, (char *)0);
-      perror("dpkg");
-      _exit(0);
-    }
-  while (waitpid(pid, &status, 0) != pid)
-    ;
-  if (status)
-    {
-      printf("dpkg failed\n");
-      exit(1);
-    }
-}
-
-int
-read_installed_debian(struct repoinfo *cinfo)
-{
-  struct stat stb;
-  Repo *repo = cinfo->repo;
-  Pool *pool = repo->pool;
-
-  memset(&stb, 0, sizeof(stb));
-  printf("dpgk database:");
-  if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/dpkg/status"), &stb))
-    memset(&stb, 0, sizeof(stb));
-  calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, 0, cinfo->cookie);
-  cinfo->cookieset = 1;
-  if (usecachedrepo(cinfo, 0, 0))
-    {
-      printf(" cached\n");
-      return 1;
-    }
-  if (repo_add_debdb(repo, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
-    {
-      fprintf(stderr, "installed db: %s\n", pool_errstr(pool));
-      return 0;
-    }
-  repo_internalize(repo);
-  writecachedrepo(cinfo, 0, 0);
-  return 1;
-}
-
-void
-commit_transactionelement_debian(Pool *pool, Id type, Id p, FILE *fp)
-{
-  Solvable *s = pool_id2solvable(pool, p);
-  const char *rootdir = pool_get_rootdir(pool);
-
-  switch(type)
-    {   
-    case SOLVER_TRANSACTION_ERASE:
-      rundpkg("--remove", pool_id2str(pool, s->name), 0, rootdir);
-      break;
-    case SOLVER_TRANSACTION_INSTALL:
-    case SOLVER_TRANSACTION_MULTIINSTALL:
-      rewind(fp);
-      lseek(fileno(fp), 0, SEEK_SET);
-      rundpkg("--install", "/dev/fd/3", fileno(fp), rootdir);
-      break;
-    default:
-      break;
-    }   
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_debian.h b/libsolv-0.6.15/examples/solv/repoinfo_system_debian.h
deleted file mode 100644 (file)
index c0e2b29..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-int  read_installed_debian(struct repoinfo *cinfo);
-void commit_transactionelement_debian(Pool *pool, Id type, Id p, FILE *fp);
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.c b/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.c
deleted file mode 100644 (file)
index b385d72..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_rpmdb.h"
-#if defined(ENABLE_SUSEREPO) && defined(SUSE)
-#include "repo_products.h"
-#endif
-#if defined(ENABLE_APPDATA)
-#include "repo_appdata.h"
-#endif
-#include "transaction.h"
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_system_rpm.h"
-
-#ifdef SUSE
-# define PRODUCTS_PATH "/etc/products.d"
-#endif
-#ifdef ENABLE_APPDATA
-# define APPDATA_PATH "/usr/share/appdata"
-#endif
-
-static void
-runrpm(const char *arg, const char *name, int dupfd3, const char *rootdir)
-{
-  pid_t pid;
-  int status;
-
-  if ((pid = fork()) == (pid_t)-1)
-    {
-      perror("fork");
-      exit(1);
-    }
-  if (pid == 0)
-    {
-      if (!rootdir)
-       rootdir = "/";
-      if (dupfd3 != -1 && dupfd3 != 3)
-       {
-         dup2(dupfd3, 3);
-         close(dupfd3);
-       }
-      if (dupfd3 != -1)
-       fcntl(3, F_SETFD, 0);   /* clear CLOEXEC */
-      if (strcmp(arg, "-e") == 0)
-       execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0);
-      else
-       execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0);
-      perror("rpm");
-      _exit(0);
-    }
-  while (waitpid(pid, &status, 0) != pid)
-    ;
-  if (status)
-    {
-      printf("rpm failed\n");
-      exit(1);
-    }
-}
-
-int
-read_installed_rpm(struct repoinfo *cinfo)
-{
-  Repo *repo = cinfo->repo;
-  Pool *pool = repo->pool;
-  FILE *ofp = 0;
-  struct stat stb;
-
-  memset(&stb, 0, sizeof(stb));
-  printf("rpm database:");
-  if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/rpm/Packages"), &stb))
-    memset(&stb, 0, sizeof(stb));
-  calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, 0, cinfo->cookie);
-  cinfo->cookieset = 1;
-  if (usecachedrepo(cinfo, 0, 0))
-    {
-      printf(" cached\n");
-      return 1;
-    }
-  printf(" reading\n");
-#if defined(ENABLE_SUSEREPO) && defined(PRODUCTS_PATH)
-  if (repo_add_products(repo, PRODUCTS_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
-    {
-      fprintf(stderr, "product reading failed: %s\n", pool_errstr(pool));
-      return 0;
-    }
-#endif
-#if defined(ENABLE_APPDATA) && defined(APPDATA_PATH)
-  if (repo_add_appdata_dir(repo, APPDATA_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
-    {
-      fprintf(stderr, "appdata reading failed: %s\n", pool_errstr(pool));
-      return 0;
-    }
-#endif
-  ofp = fopen(calc_cachepath(repo, 0, 0), "r");
-  if (repo_add_rpmdb_reffp(repo, ofp, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
-    {
-      fprintf(stderr, "installed db: %s\n", pool_errstr(pool));
-      return 0;
-    }
-  if (ofp)
-    fclose(ofp);
-  repo_internalize(repo);
-  writecachedrepo(cinfo, 0, 0);
-  return 1;
-}
-
-void
-commit_transactionelement_rpm(Pool *pool, Id type, Id p, FILE *fp)
-{
-  Solvable *s = pool_id2solvable(pool, p);
-  const char *rootdir = pool_get_rootdir(pool);
-  const char *evr, *evrp, *nvra;
-
-  switch(type)
-    {
-    case SOLVER_TRANSACTION_ERASE:
-      if (!s->repo->rpmdbid || !s->repo->rpmdbid[p - s->repo->start])
-       break;
-      /* strip epoch from evr */
-      evr = evrp = pool_id2str(pool, s->evr);
-      while (*evrp >= '0' && *evrp <= '9')
-       evrp++;
-      if (evrp > evr && evrp[0] == ':' && evrp[1])
-       evr = evrp + 1;
-      nvra = pool_tmpjoin(pool, pool_id2str(pool, s->name), "-", evr);
-      nvra = pool_tmpappend(pool, nvra, ".", pool_id2str(pool, s->arch));
-      runrpm("-e", nvra, -1, rootdir);      /* too bad that --querybynumber doesn't work */
-      break;
-    case SOLVER_TRANSACTION_INSTALL:
-    case SOLVER_TRANSACTION_MULTIINSTALL:
-      rewind(fp);
-      lseek(fileno(fp), 0, SEEK_SET);
-      runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp), rootdir);
-      break;
-    default:
-      break;
-    }
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.h b/libsolv-0.6.15/examples/solv/repoinfo_system_rpm.h
deleted file mode 100644 (file)
index db63a8d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-int  read_installed_rpm(struct repoinfo *cinfo);
-void commit_transactionelement_rpm(Pool *pool, Id type, Id p, FILE *fp);
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_debian.c b/libsolv-0.6.15/examples/solv/repoinfo_type_debian.c
deleted file mode 100644 (file)
index 7a15ff4..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-#ifdef ENABLE_DEBIAN
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_deb.h"
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_download.h"
-#include "repoinfo_type_debian.h"
-
-static const char *
-debian_find_component(struct repoinfo *cinfo, FILE *fp, char *comp, const unsigned char **chksump, Id *chksumtypep)
-{
-  char buf[4096];
-  Id chksumtype;
-  unsigned char *chksum;
-  Id curchksumtype;
-  int l, compl;
-  char *ch, *fn, *bp;
-  char *filename;
-  static char *basearch;
-  char *binarydir;
-  int lbinarydir;
-
-  if (!basearch)
-    {
-      struct utsname un;
-      if (uname(&un))
-       {
-         perror("uname");
-         exit(1);
-       }
-      basearch = strdup(un.machine);
-      if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86"))
-       basearch[1] = '3';
-    }
-  binarydir = solv_dupjoin("binary-", basearch, "/");
-  lbinarydir = strlen(binarydir);
-  compl = strlen(comp);
-  rewind(fp);
-  curchksumtype = 0;
-  filename = 0;
-  chksum = solv_malloc(32);
-  chksumtype = 0;
-  while(fgets(buf, sizeof(buf), fp))
-    {
-      l = strlen(buf);
-      if (l == 0)
-       continue;
-      while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
-       buf[--l] = 0;
-      if (!strncasecmp(buf, "MD5Sum:", 7))
-       {
-         curchksumtype = REPOKEY_TYPE_MD5;
-         continue;
-       }
-      if (!strncasecmp(buf, "SHA1:", 5))
-       {
-         curchksumtype = REPOKEY_TYPE_SHA1;
-         continue;
-       }
-      if (!strncasecmp(buf, "SHA256:", 7))
-       {
-         curchksumtype = REPOKEY_TYPE_SHA256;
-         continue;
-       }
-      if (!curchksumtype)
-       continue;
-      bp = buf;
-      if (*bp++ != ' ')
-       {
-         curchksumtype = 0;
-         continue;
-       }
-      ch = bp;
-      while (*bp && *bp != ' ' && *bp != '\t')
-       bp++;
-      if (!*bp)
-       continue;
-      *bp++ = 0;
-      while (*bp == ' ' || *bp == '\t')
-       bp++;
-      while (*bp && *bp != ' ' && *bp != '\t')
-       bp++;
-      if (!*bp)
-       continue;
-      while (*bp == ' ' || *bp == '\t')
-       bp++;
-      fn = bp;
-      if (strncmp(fn, comp, compl) != 0 || fn[compl] != '/')
-       continue;
-      bp += compl + 1;
-      if (strncmp(bp, binarydir, lbinarydir))
-       continue;
-      bp += lbinarydir;
-      if (!strcmp(bp, "Packages") || !strcmp(bp, "Packages.gz"))
-       {
-         unsigned char curchksum[32];
-         int curl;
-         if (filename && !strcmp(bp, "Packages"))
-           continue;
-         curl = solv_chksum_len(curchksumtype);
-         if (!curl || (chksumtype && solv_chksum_len(chksumtype) > curl))
-           continue;
-          if (solv_hex2bin((const char **)&ch, curchksum, sizeof(curchksum)) != curl)
-           continue;
-         solv_free(filename);
-         filename = strdup(fn);
-         chksumtype = curchksumtype;
-         memcpy(chksum, curchksum, curl);
-       }
-    }
-  free(binarydir);
-  if (filename)
-    {
-      fn = solv_dupjoin("/", filename, 0);
-      solv_free(filename);
-      filename = solv_dupjoin("dists/", cinfo->name, fn);
-      solv_free(fn);
-    }
-  if (!chksumtype)
-    chksum = solv_free(chksum);
-  *chksump = chksum;
-  *chksumtypep = chksumtype;
-  return filename;
-}
-
-int
-debian_load(struct repoinfo *cinfo, Pool **sigpoolp)
-{
-  Repo *repo = cinfo->repo;
-  Pool *pool = repo->pool;
-  const char *filename;
-  const unsigned char *filechksum;
-  Id filechksumtype;
-  FILE *fp, *fpr;
-  int j;
-
-  printf("debian repo '%s':", cinfo->alias);
-  fflush(stdout);
-  filename = solv_dupjoin("dists/", cinfo->name, "/Release");
-  if ((fpr = curlfopen(cinfo, filename, 0, 0, 0, 0)) == 0)
-    {
-      printf(" no Release file\n");
-      free((char *)filename);
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  solv_free((char *)filename);
-  if (cinfo->repo_gpgcheck)
-    {
-      filename = solv_dupjoin("dists/", cinfo->name, "/Release.gpg");
-      if (!downloadchecksig(cinfo, fpr, filename, sigpoolp))
-       {
-         fclose(fpr);
-         solv_free((char *)filename);
-         cinfo->incomplete = 1;
-         return 0;
-       }
-      solv_free((char *)filename);
-    }
-  calc_cookie_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie);
-  cinfo->cookieset = 1;
-  if (usecachedrepo(cinfo, 0, 1))
-    {
-      printf(" cached\n");
-      fclose(fpr);
-      return 1;
-    }
-  printf(" fetching\n");
-  for (j = 0; j < cinfo->ncomponents; j++)
-    {
-      if (!(filename = debian_find_component(cinfo, fpr, cinfo->components[j], &filechksum, &filechksumtype)))
-       {
-         printf("[component %s not found]\n", cinfo->components[j]);
-         continue;
-       }
-      if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
-       {
-         if (repo_add_debpackages(repo, fp, 0))
-           {
-             printf("component %s: %s\n", cinfo->components[j], pool_errstr(pool));
-             cinfo->incomplete = 1;
-           }
-         fclose(fp);
-       }
-      solv_free((char *)filechksum);
-      solv_free((char *)filename);
-    }
-  fclose(fpr);
-  writecachedrepo(cinfo, 0, 0);
-  return 1;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_debian.h b/libsolv-0.6.15/examples/solv/repoinfo_type_debian.h
deleted file mode 100644 (file)
index 3dfc827..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern int debian_load(struct repoinfo *cinfo, Pool **sigpoolp);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.c b/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.c
deleted file mode 100644 (file)
index 96b005f..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-#ifdef ENABLE_MDKREPO
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_mdk.h"
-#include "solv_xfopen.h"
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_download.h"
-#include "repoinfo_type_mdk.h"
-
-static int
-mdk_find(const char *md5sums, const char *what, unsigned char *chksum)
-{
-  const char *sp, *ep;
-  int wl = strlen(what);
-  for (sp = md5sums; (ep = strchr(sp, '\n')) != 0; sp = ep + 1)
-    {
-      int l = ep - sp;
-      if (l <= 34)
-       continue;
-      if (sp[32] != ' ' || sp[33] != ' ')
-       continue;
-      if (wl != l - 34 || strncmp(what, sp + 34, wl) != 0)
-       continue;
-      if (solv_hex2bin(&sp, chksum, 16) != 16)
-       continue;
-      return 1;
-    }
-  return 0;
-}
-
-static char *
-slurp(FILE *fp)
-{
-  int l, ll;
-  char *buf = 0;
-  int bufl = 0;
-
-  for (l = 0; ; l += ll)
-    {
-      if (bufl - l < 4096)
-        {
-          bufl += 4096;
-          buf = solv_realloc(buf, bufl);
-        }
-      ll = fread(buf + l, 1, bufl - l, fp);
-      if (ll < 0)
-        {
-          buf = solv_free(buf);
-          l = 0;
-          break;
-        }
-      if (ll == 0)
-        {
-          buf[l] = 0;
-          break;
-        }
-    }
-  return buf;
-}
-
-int
-mdk_load_ext(Repo *repo, Repodata *data)
-{
-  struct repoinfo *cinfo = repo->appdata;
-  const char *type, *ext, *filename;
-  const unsigned char *filechksum;
-  Id filechksumtype;
-  int r = 0;
-  FILE *fp;
-
-  type = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE);
-  if (strcmp(type, "filelists") != 0)
-    return 0;
-  ext = "FL";
-  printf("[%s:%s", repo->name, ext);
-  if (usecachedrepo(cinfo, ext, 0))
-    {
-      printf(" cached]\n"); fflush(stdout);
-      return 1;
-    }
-  printf(" fetching]\n"); fflush(stdout);
-  filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION);
-  filechksumtype = 0;
-  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype);
-  if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 0)) == 0)
-    return 0;
-  r = repo_add_mdk_info(repo, fp, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
-  fclose(fp);
-  if (r)
-    {
-      printf("%s\n", pool_errstr(repo->pool));
-      return 0;
-    }
-  writecachedrepo(cinfo, ext, data);
-  return 1;
-}
-
-int
-mdk_load(struct repoinfo *cinfo, Pool **sigpoolp)
-{
-  Repo *repo = cinfo->repo;
-  Pool *pool = repo->pool;
-  Repodata *data;
-  const char *compression;
-  FILE *fp, *cfp;
-  char *md5sums;
-  unsigned char probe[5];
-  unsigned char md5[16];
-
-  printf("mdk repo '%s':", cinfo->alias);
-  fflush(stdout);
-  if ((fp = curlfopen(cinfo, "media_info/MD5SUM", 0, 0, 0, 0)) == 0)
-    {
-      printf(" no media_info/MD5SUM file\n");
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
-  cinfo->cookieset = 1;
-  if (usecachedrepo(cinfo, 0, 1))
-    {
-      printf(" cached\n");
-      fclose(fp);
-      return 1;
-    }
-  md5sums = slurp(fp);
-  fclose(fp);
-  printf(" fetching\n");
-  if (!mdk_find(md5sums, "synthesis.hdlist.cz", md5))
-    {
-      solv_free(md5sums);
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  if ((fp = curlfopen(cinfo, "media_info/synthesis.hdlist.cz", 0, md5, REPOKEY_TYPE_MD5, 1)) == 0)
-    {
-      solv_free(md5sums);
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  /* probe compression */
-  if (fread(probe, 5, 1, fp) != 1)
-    {
-      fclose(fp);
-      solv_free(md5sums);
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  if (probe[0] == 0xfd && memcmp(probe + 1, "7zXZ", 4) == 0)
-    compression = "synthesis.hdlist.xz";
-  else
-    compression = "synthesis.hdlist.gz";
-  lseek(fileno(fp), 0, SEEK_SET);
-  cfp = solv_xfopen_fd(compression, dup(fileno(fp)), "r");
-  fclose(fp);
-  fp = cfp;
-  if (!fp)
-    {
-      solv_free(md5sums);
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  if (repo_add_mdk(repo, fp, REPO_NO_INTERNALIZE))
-    {
-      printf("synthesis.hdlist.cz: %s\n", pool_errstr(pool));
-      fclose(fp);
-      solv_free(md5sums);
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  fclose(fp);
-  /* add info, could do this on demand, but always having the summary is nice */
-  if (mdk_find(md5sums, "info.xml.lzma", md5))
-    {
-      if ((fp = curlfopen(cinfo, "media_info/info.xml.lzma", 1, md5, REPOKEY_TYPE_MD5, 1)) != 0)
-       {
-         if (repo_add_mdk_info(repo, fp, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES))
-           {
-             printf("info.xml.lzma: %s\n", pool_errstr(pool));
-             cinfo->incomplete = 1;
-           }
-         fclose(fp);
-       }
-    }
-  repo_internalize(repo);
-  data = repo_add_repodata(repo, 0);
-  /* setup on-demand loading of filelist data */
-  if (mdk_find(md5sums, "files.xml.lzma", md5))
-    {
-      Id handle = repodata_new_handle(data);
-      /* we mis-use the repomd ids here... need something generic in the future */
-      repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, "filelists");
-      repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, "media_info/files.xml.lzma");
-      repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, REPOKEY_TYPE_MD5, md5);
-      add_ext_keys(data, handle, "FL");
-      repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
-    }
-  solv_free(md5sums);
-  repodata_internalize(data);
-  writecachedrepo(cinfo, 0, 0);
-  repodata_create_stubs(repo_last_repodata(repo));
-  return 1;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.h b/libsolv-0.6.15/examples/solv/repoinfo_type_mdk.h
deleted file mode 100644 (file)
index e98bc48..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-extern int mdk_load(struct repoinfo *cinfo, Pool **sigpoolp);
-extern int mdk_load_ext(Repo *repo, Repodata *data);
-
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.c b/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.c
deleted file mode 100644 (file)
index 98c5d36..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-#ifdef ENABLE_RPMMD
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_rpmmd.h"
-#include "repo_deltainfoxml.h"
-#include "repo_updateinfoxml.h"
-#include "repo_repomdxml.h"
-#ifdef ENABLE_APPDATA
-#include "repo_appdata.h"
-#endif
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_download.h"
-#include "repoinfo_type_rpmmd.h"
-
-
-
-static const char *
-repomd_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep)
-{
-  Pool *pool = repo->pool;
-  Dataiterator di;
-  const char *filename;
-
-  filename = 0;
-  *chksump = 0;
-  *chksumtypep = 0;
-  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING);
-  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
-  if (dataiterator_step(&di))
-    {
-      dataiterator_setpos_parent(&di);
-      filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
-      *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, REPOSITORY_REPOMD_CHECKSUM, chksumtypep);
-    }
-  dataiterator_free(&di);
-  if (filename && !*chksumtypep)
-    {
-      printf("no %s file checksum!\n", what);
-      filename = 0;
-    }
-  return filename;
-}
-
-static void
-repomd_add_ext(Repo *repo, Repodata *data, const char *what, const char *ext)
-{
-  Id chksumtype, handle;
-  const unsigned char *chksum;
-  const char *filename;
-
-  filename = repomd_find(repo, what, &chksum, &chksumtype);
-  if (!filename && !strcmp(what, "deltainfo"))
-    filename = repomd_find(repo, "prestodelta", &chksum, &chksumtype);
-  if (!filename)
-    return;
-  handle = repodata_new_handle(data);
-  repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, what);
-  repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, filename);
-  repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, chksumtype, chksum);
-  add_ext_keys(data, handle, ext);
-  repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
-}
-
-int
-repomd_load_ext(Repo *repo, Repodata *data)
-{
-  const char *filename, *repomdtype;
-  char ext[3];
-  FILE *fp;
-  struct repoinfo *cinfo;
-  const unsigned char *filechksum;
-  Id filechksumtype;
-  int r = 0;
-
-  cinfo = repo->appdata;
-  repomdtype = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE);
-  if (!repomdtype)
-    return 0;
-  if (!strcmp(repomdtype, "filelists"))
-    strcpy(ext, "FL");
-  else if (!strcmp(repomdtype, "deltainfo"))
-    strcpy(ext, "DL");
-  else
-    return 0;
-  printf("[%s:%s", repo->name, ext);
-  if (usecachedrepo(cinfo, ext, 0))
-    {
-      printf(" cached]\n"); fflush(stdout);
-      return 1;
-    }
-  printf(" fetching]\n"); fflush(stdout);
-  filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION);
-  filechksumtype = 0;
-  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype);
-  if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 0)) == 0)
-    return 0;
-  if (!strcmp(ext, "FL"))
-    r = repo_add_rpmmd(repo, fp, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
-  else if (!strcmp(ext, "DL"))
-    r = repo_add_deltainfoxml(repo, fp, REPO_USE_LOADING);
-  fclose(fp);
-  if (r)
-    {
-      printf("%s\n", pool_errstr(repo->pool));
-      return 0;
-    }
-  if (cinfo->extcookieset)
-    writecachedrepo(cinfo, ext, data);
-  return 1;
-}
-
-int
-repomd_load(struct repoinfo *cinfo, Pool **sigpoolp)
-{
-  Repo *repo = cinfo->repo;
-  Pool *pool = repo->pool;
-  Repodata *data;
-  const char *filename;
-  const unsigned char *filechksum;
-  Id filechksumtype;
-  FILE *fp;
-
-  printf("rpmmd repo '%s':", cinfo->alias);
-  fflush(stdout);
-  if ((fp = curlfopen(cinfo, "repodata/repomd.xml", 0, 0, 0, 0)) == 0)
-    {
-      printf(" no repomd.xml file\n");
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
-  cinfo->cookieset = 1;
-  if (usecachedrepo(cinfo, 0, 1))
-    {
-      printf(" cached\n");
-      fclose(fp);
-      return 1;
-    }
-  if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "repodata/repomd.xml.asc", sigpoolp))
-    {
-      fclose(fp);
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  if (repo_add_repomdxml(repo, fp, 0))
-    {
-      printf("repomd.xml: %s\n", pool_errstr(pool));
-      cinfo->incomplete = 1;
-      fclose(fp);
-      return 0;
-    }
-  fclose(fp);
-  printf(" fetching\n");
-  filename = repomd_find(repo, "primary", &filechksum, &filechksumtype);
-  if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
-    {
-      if (repo_add_rpmmd(repo, fp, 0, 0))
-       {
-         printf("primary: %s\n", pool_errstr(pool));
-         cinfo->incomplete = 1;
-       }
-      fclose(fp);
-    }
-  if (cinfo->incomplete)
-    return 0;  /* hopeless */
-
-  filename = repomd_find(repo, "updateinfo", &filechksum, &filechksumtype);
-  if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
-    {
-      if (repo_add_updateinfoxml(repo, fp, 0))
-       {
-         printf("updateinfo: %s\n", pool_errstr(pool));
-         cinfo->incomplete = 1;
-       }
-      fclose(fp);
-    }
-
-#ifdef ENABLE_APPDATA
-  filename = repomd_find(repo, "appdata", &filechksum, &filechksumtype);
-  if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
-    {
-      if (repo_add_appdata(repo, fp, 0))
-       {
-         printf("appdata: %s\n", pool_errstr(pool));
-         cinfo->incomplete = 1;
-       }
-      fclose(fp);
-    }
-#endif
-  data = repo_add_repodata(repo, 0);
-  repomd_add_ext(repo, data, "deltainfo", "DL");
-  repomd_add_ext(repo, data, "filelists", "FL");
-  repodata_internalize(data);
-  writecachedrepo(cinfo, 0, 0);
-  repodata_create_stubs(repo_last_repodata(repo));
-  return 1;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.h b/libsolv-0.6.15/examples/solv/repoinfo_type_rpmmd.h
deleted file mode 100644 (file)
index 275dfc1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern int repomd_load_ext(Repo *repo, Repodata *data);
-extern int repomd_load(struct repoinfo *cinfo, Pool **sigpoolp);
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.c b/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.c
deleted file mode 100644 (file)
index 596171c..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifdef ENABLE_SUSEREPO
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_content.h"
-#include "repo_susetags.h"
-#ifdef ENABLE_APPDATA
-#include "repo_appdata.h"
-#endif
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_download.h"
-#include "repoinfo_type_susetags.h"
-
-/* susetags helpers */
-
-static const char *
-susetags_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep)
-{
-  Pool *pool = repo->pool;
-  Dataiterator di;
-  const char *filename;
-
-  filename = 0;
-  *chksump = 0;
-  *chksumtypep = 0;
-  dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, what, SEARCH_STRING);
-  dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
-  if (dataiterator_step(&di))
-    {
-      dataiterator_setpos_parent(&di);
-      *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, SUSETAGS_FILE_CHECKSUM, chksumtypep);
-      filename = what;
-    }
-  dataiterator_free(&di);
-  if (filename && !*chksumtypep)
-    {
-      printf("no %s file checksum!\n", what);
-      filename = 0;
-    }
-  return filename;
-}
-
-void
-susetags_add_ext(Repo *repo, Repodata *data)
-{
-  Pool *pool = repo->pool;
-  Dataiterator di;
-  char ext[3];
-  Id handle, filechksumtype;
-  const unsigned char *filechksum;
-
-  dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, 0, 0);
-  dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
-  while (dataiterator_step(&di))
-    {
-      if (strncmp(di.kv.str, "packages.", 9) != 0)
-       continue;
-      if (!strcmp(di.kv.str + 9, "gz"))
-       continue;
-      if (!di.kv.str[9] || !di.kv.str[10] || (di.kv.str[11] && di.kv.str[11] != '.'))
-       continue;
-      ext[0] = di.kv.str[9];
-      ext[1] = di.kv.str[10];
-      ext[2] = 0;
-      if (!strcmp(ext, "en"))
-       continue;
-      if (!susetags_find(repo, di.kv.str, &filechksum, &filechksumtype))
-       continue;
-      handle = repodata_new_handle(data);
-      repodata_set_str(data, handle, SUSETAGS_FILE_NAME, di.kv.str);
-      if (filechksumtype)
-       repodata_set_bin_checksum(data, handle, SUSETAGS_FILE_CHECKSUM, filechksumtype, filechksum);
-      add_ext_keys(data, handle, ext);
-      repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
-    }
-  dataiterator_free(&di);
-}
-
-int
-susetags_load_ext(Repo *repo, Repodata *data)
-{
-  const char *filename, *descrdir;
-  Id defvendor;
-  char ext[3];
-  FILE *fp;
-  struct repoinfo *cinfo;
-  const unsigned char *filechksum;
-  Id filechksumtype;
-  int flags;
-
-  cinfo = repo->appdata;
-  filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME);
-  if (!filename)
-    return 0;
-  /* susetags load */
-  ext[0] = filename[9];
-  ext[1] = filename[10];
-  ext[2] = 0;
-  printf("[%s:%s", repo->name, ext);
-  if (usecachedrepo(cinfo, ext, 0))
-    {
-      printf(" cached]\n"); fflush(stdout);
-      return 1;
-    }
-  printf(" fetching]\n"); fflush(stdout);
-  defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
-  descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
-  if (!descrdir)
-    descrdir = "suse/setup/descr";
-  filechksumtype = 0;
-  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, SUSETAGS_FILE_CHECKSUM, &filechksumtype);
-  if ((fp = curlfopen(cinfo, pool_tmpjoin(repo->pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 0)) == 0)
-    return 0;
-  flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
-  if (strcmp(ext, "DL") != 0)
-    flags |= REPO_LOCALPOOL;
-  if (repo_add_susetags(repo, fp, defvendor, ext, flags))
-    {
-      fclose(fp);
-      printf("%s\n", pool_errstr(repo->pool));
-      return 0;
-    }
-  fclose(fp);
-  writecachedrepo(cinfo, ext, data);
-  return 1;
-}
-
-int
-susetags_load(struct repoinfo *cinfo, Pool **sigpoolp)
-{
-  Repo *repo = cinfo->repo;
-  Pool *pool = repo->pool;
-  Repodata *data;
-  const char *filename;
-  const unsigned char *filechksum;
-  Id filechksumtype;
-  FILE *fp;
-  const char *descrdir;
-  int defvendor;
-
-  printf("susetags repo '%s':", cinfo->alias);
-  fflush(stdout);
-  descrdir = 0;
-  defvendor = 0;
-  if ((fp = curlfopen(cinfo, "content", 0, 0, 0, 0)) == 0)
-    {
-      printf(" no content file\n");
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
-  cinfo->cookieset = 1;
-  if (usecachedrepo(cinfo, 0, 1))
-    {
-      printf(" cached\n");
-      fclose(fp);
-      return 1;
-    }
-  if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "content.asc", sigpoolp))
-    {
-      fclose(fp);
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  if (repo_add_content(repo, fp, 0))
-    {
-      printf("content: %s\n", pool_errstr(pool));
-      fclose(fp);
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  fclose(fp);
-  defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
-  descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
-  if (!descrdir)
-    descrdir = "suse/setup/descr";
-  filename = susetags_find(repo, "packages.gz", &filechksum, &filechksumtype);
-  if (!filename)
-    filename = susetags_find(repo, "packages", &filechksum, &filechksumtype);
-  if (!filename)
-    {
-      printf(" no packages file entry, skipped\n");
-      cinfo->incomplete = 1;
-      return 0;
-    }
-  printf(" fetching\n");
-  if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) == 0)
-    {
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES))
-    {
-      printf("packages: %s\n", pool_errstr(pool));
-      fclose(fp);
-      cinfo->incomplete = 1;
-      return 0;        /* hopeless */
-    }
-  fclose(fp);
-  /* add default language */
-  filename = susetags_find(repo, "packages.en.gz", &filechksum, &filechksumtype);
-  if (!filename)
-    filename = susetags_find(repo, "packages.en", &filechksum, &filechksumtype);
-  if (filename)
-    {
-      if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
-       {
-         if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES))
-           {
-             printf("packages.en: %s\n", pool_errstr(pool));
-             cinfo->incomplete = 1;
-           }
-         fclose(fp);
-       }
-    }
-  filename = susetags_find(repo, "patterns", &filechksum, &filechksumtype);
-  if (filename)
-    {
-      if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
-       {
-         char pbuf[256];
-         while (fgets(pbuf, sizeof(pbuf), fp))
-           {
-             int l = strlen(pbuf);
-             FILE *fp2;
-             if (l && pbuf[l - 1] == '\n')
-               pbuf[--l] = 0;
-             if (!*pbuf || *pbuf == '.' || strchr(pbuf, '/') != 0)
-               continue;
-             filename = susetags_find(repo, pbuf, &filechksum, &filechksumtype);
-             if (filename && (fp2 = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
-               {
-                 if (repo_add_susetags(repo, fp2, defvendor, 0, REPO_NO_INTERNALIZE))
-                   {
-                     printf("%s: %s\n", pbuf, pool_errstr(pool));
-                     cinfo->incomplete = 1;
-                   }
-                 fclose(fp2);
-               }
-           }
-         fclose(fp);
-       }
-    }
-#ifdef ENABLE_APPDATA
-  filename = susetags_find(repo, "appdata.xml.gz", &filechksum, &filechksumtype);
-  if (!filename)
-    filename = susetags_find(repo, "appdata.xml", &filechksum, &filechksumtype);
-  if (filename && (fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
-    {
-      if (repo_add_appdata(repo, fp, 0))
-       {
-         printf("appdata: %s\n", pool_errstr(pool));
-         cinfo->incomplete = 1;
-       }
-      fclose(fp);
-    }
-#endif
-  repo_internalize(repo);
-  data = repo_add_repodata(repo, 0);
-  susetags_add_ext(repo, data);
-  repodata_internalize(data);
-  writecachedrepo(cinfo, 0, 0);
-  repodata_create_stubs(repo_last_repodata(repo));
-  return 1;
-}
-
-#endif
diff --git a/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.h b/libsolv-0.6.15/examples/solv/repoinfo_type_susetags.h
deleted file mode 100644 (file)
index 2ad5778..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-extern int susetags_load_ext(Repo *repo, Repodata *data);
-extern int susetags_load(struct repoinfo *cinfo, Pool **sigpoolp);
diff --git a/libsolv-0.6.15/examples/solv/solv.c b/libsolv-0.6.15/examples/solv/solv.c
deleted file mode 100644 (file)
index 6840a6e..0000000
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * Copyright (c) 2009-2015, SUSE LLC.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/* solv, a little software installer demoing the sat solver library */
-
-/* things it does:
- * - understands globs for package names / dependencies
- * - understands .arch suffix
- * - installation of commandline packages
- * - repository data caching
- * - on demand loading of secondary repository data
- * - gpg and checksum verification
- * - file conflicts
- * - deltarpm support
- * - fastestmirror implementation
- *
- * things available in the library but missing from solv:
- * - vendor policy loading
- * - multi version handling
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-
-#include "pool.h"
-#include "poolarch.h"
-#include "evr.h"
-#include "selection.h"
-#include "repo.h"
-#include "solver.h"
-#include "solverdebug.h"
-#include "transaction.h"
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-
-#include "repoinfo.h"
-#include "repoinfo_cache.h"
-#include "repoinfo_download.h"
-
-#if defined(ENABLE_RPMDB)
-#include "fileprovides.h"
-#include "fileconflicts.h"
-#include "deltarpm.h"
-#endif
-#if defined(SUSE) || defined(FEDORA)
-#include "patchjobs.h"
-#endif
-
-void
-setarch(Pool *pool)
-{
-  struct utsname un;
-  if (uname(&un))
-    {
-      perror("uname");
-      exit(1);
-    }
-  pool_setarch(pool, un.machine);
-}
-
-
-int
-yesno(const char *str)
-{
-  char inbuf[128], *ip;
-
-  for (;;)
-    {
-      printf("%s", str);
-      fflush(stdout);
-      *inbuf = 0;
-      if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
-       {
-         printf("Abort.\n");
-         exit(1);
-       }
-      while (*ip == ' ' || *ip == '\t')
-       ip++;
-      if (*ip == 'q')
-       {
-         printf("Abort.\n");
-         exit(1);
-       }
-      if (*ip == 'y' || *ip == 'n')
-       return *ip == 'y' ? 1 : 0;
-    }
-}
-
-#ifdef SUSE
-static Id
-nscallback(Pool *pool, void *data, Id name, Id evr)
-{
-#if 0
-  if (name == NAMESPACE_LANGUAGE)
-    {
-      if (!strcmp(pool_id2str(pool, evr), "ja"))
-       return 1;
-      if (!strcmp(pool_id2str(pool, evr), "de"))
-       return 1;
-      if (!strcmp(pool_id2str(pool, evr), "en"))
-       return 1;
-      if (!strcmp(pool_id2str(pool, evr), "en_US"))
-       return 1;
-    }
-#endif
-  return 0;
-}
-#endif
-
-#ifdef SUSE
-static void
-add_autopackages(Pool *pool)
-{
-  int i;
-  Repo *repo;
-  FOR_REPOS(i, repo)
-    repo_add_autopattern(repo, 0);
-}
-#endif
-
-#ifdef SUSE
-static void
-showdiskusagechanges(Transaction *trans)
-{
-  DUChanges duc[4];
-  int i;
-
-  /* XXX: use mountpoints here */
-  memset(duc, 0, sizeof(duc));
-  duc[0].path = "/";
-  duc[1].path = "/usr/share/man";
-  duc[2].path = "/sbin";
-  duc[3].path = "/etc";
-  transaction_calc_duchanges(trans, duc, 4);
-  for (i = 0; i < 4; i++)
-    printf("duchanges %s: %d K  %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files);
-}
-#endif
-
-static Id
-find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
-{
-  const char *rp;
-  int i;
-
-  for (rp = name; *rp; rp++)
-    if (*rp <= '0' || *rp >= '9')
-      break;
-  if (!*rp)
-    {
-      /* repo specified by number */
-      int rnum = atoi(name);
-      for (i = 0; i < nrepoinfos; i++)
-       {
-         struct repoinfo *cinfo = repoinfos + i;
-         if (!cinfo->enabled || !cinfo->repo)
-           continue;
-         if (--rnum == 0)
-           return cinfo->repo->repoid;
-       }
-    }
-  else
-    {
-      /* repo specified by alias */
-      Repo *repo;
-      FOR_REPOS(i, repo)
-       {
-         if (!strcasecmp(name, repo->name))
-           return repo->repoid;
-       }
-    }
-  return 0;
-}
-
-
-#define MODE_LIST        0
-#define MODE_INSTALL     1
-#define MODE_ERASE       2
-#define MODE_UPDATE      3
-#define MODE_DISTUPGRADE 4
-#define MODE_VERIFY      5
-#define MODE_PATCH       6
-#define MODE_INFO        7
-#define MODE_REPOLIST    8
-#define MODE_SEARCH     9
-
-void
-usage(int r)
-{
-  fprintf(stderr, "Usage: solv COMMAND <select>\n");
-  fprintf(stderr, "\n");
-  fprintf(stderr, "    dist-upgrade: replace installed packages with\n");
-  fprintf(stderr, "                  versions from the repositories\n");
-  fprintf(stderr, "    erase:        erase installed packages\n");
-  fprintf(stderr, "    info:         display package information\n");
-  fprintf(stderr, "    install:      install packages\n");
-  fprintf(stderr, "    list:         list packages\n");
-  fprintf(stderr, "    repos:        list enabled repositories\n");
-  fprintf(stderr, "    search:       search name/summary/description\n");
-  fprintf(stderr, "    update:       update installed packages\n");
-  fprintf(stderr, "    verify:       check dependencies of installed packages\n");
-#if defined(SUSE) || defined(FEDORA)
-  fprintf(stderr, "    patch:        install newest maintenance updates\n");
-#endif
-  fprintf(stderr, "\n");
-  exit(r);
-}
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool;
-  Repo *commandlinerepo = 0;
-  Id *commandlinepkgs = 0;
-  Id p;
-  struct repoinfo *repoinfos, installedrepoinfo;
-  int nrepoinfos = 0;
-  int mainmode = 0, mode = 0;
-  int i, newpkgs;
-  Queue job, checkq;
-  Solver *solv = 0;
-  Transaction *trans;
-  FILE **newpkgsfps;
-  Queue repofilter;
-  Queue kindfilter;
-  Queue archfilter;
-  int archfilter_src = 0;
-  int cleandeps = 0;
-  int forcebest = 0;
-  char *rootdir = 0;
-  char *keyname = 0;
-  int debuglevel = 0;
-
-  argc--;
-  argv++;
-  while (argc && !strcmp(argv[0], "-d"))
-    {
-      debuglevel++;
-      argc--;
-      argv++;
-    }
-  if (!argv[0])
-    usage(1);
-  if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in"))
-    {
-      mainmode = MODE_INSTALL;
-      mode = SOLVER_INSTALL;
-    }
-#if defined(SUSE) || defined(FEDORA)
-  else if (!strcmp(argv[0], "patch"))
-    {
-      mainmode = MODE_PATCH;
-      mode = SOLVER_INSTALL;
-    }
-#endif
-  else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm"))
-    {
-      mainmode = MODE_ERASE;
-      mode = SOLVER_ERASE;
-    }
-  else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "ls"))
-    {
-      mainmode = MODE_LIST;
-      mode = 0;
-    }
-  else if (!strcmp(argv[0], "info"))
-    {
-      mainmode = MODE_INFO;
-      mode = 0;
-    }
-  else if (!strcmp(argv[0], "search") || !strcmp(argv[0], "se"))
-    {
-      mainmode = MODE_SEARCH;
-      mode = 0;
-    }
-  else if (!strcmp(argv[0], "verify"))
-    {
-      mainmode = MODE_VERIFY;
-      mode = SOLVER_VERIFY;
-    }
-  else if (!strcmp(argv[0], "update") || !strcmp(argv[0], "up"))
-    {
-      mainmode = MODE_UPDATE;
-      mode = SOLVER_UPDATE;
-    }
-  else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup"))
-    {
-      mainmode = MODE_DISTUPGRADE;
-      mode = SOLVER_DISTUPGRADE;
-    }
-  else if (!strcmp(argv[0], "repos") || !strcmp(argv[0], "repolist") || !strcmp(argv[0], "lr"))
-    {
-      mainmode = MODE_REPOLIST;
-      mode = 0;
-    }
-  else
-    usage(1);
-
-  for (;;)
-    {
-      if (argc > 2 && !strcmp(argv[1], "--root"))
-       {
-         rootdir = argv[2];
-         argc -= 2;
-         argv += 2;
-       }
-      else if (argc > 1 && !strcmp(argv[1], "--clean"))
-       {
-         cleandeps = 1;
-         argc--;
-         argv++;
-       }
-      else if (argc > 1 && !strcmp(argv[1], "--best"))
-       {
-         forcebest = 1;
-         argc--;
-         argv++;
-       }
-      if (argc > 2 && !strcmp(argv[1], "--keyname"))
-       {
-         keyname = argv[2];
-         argc -= 2;
-         argv += 2;
-       }
-      else
-       break;
-    }
-
-  set_userhome();
-  pool = pool_create();
-  pool_set_rootdir(pool, rootdir);
-
-#if 0
-  {
-    const char *langs[] = {"de_DE", "de", "en"};
-    pool_set_languages(pool, langs, sizeof(langs)/sizeof(*langs));
-  }
-#endif
-
-  pool_setloadcallback(pool, load_stub, 0);
-#ifdef SUSE
-  pool->nscallback = nscallback;
-#endif
-  if (debuglevel)
-    pool_setdebuglevel(pool, debuglevel);
-  setarch(pool);
-  pool_set_flag(pool, POOL_FLAG_ADDFILEPROVIDESFILTERED, 1);
-  repoinfos = read_repoinfos(pool, &nrepoinfos);
-  sort_repoinfos(repoinfos, nrepoinfos);
-
-  if (mainmode == MODE_REPOLIST)
-    {
-      int j = 1;
-      for (i = 0; i < nrepoinfos; i++)
-       {
-         struct repoinfo *cinfo = repoinfos + i;
-         if (!cinfo->enabled)
-           continue;
-         printf("%d: %-20s %s (prio %d)\n", j++, cinfo->alias, cinfo->name, cinfo->priority);
-       }
-      exit(0);
-    }
-  memset(&installedrepoinfo, 0, sizeof(installedrepoinfo));
-  if (!read_installed_repo(&installedrepoinfo, pool))
-    exit(1);
-  read_repos(pool, repoinfos, nrepoinfos);
-
-  /* setup filters */
-  queue_init(&repofilter);
-  queue_init(&kindfilter);
-  queue_init(&archfilter);
-  while (argc > 1)
-    {
-      if (!strcmp(argv[1], "-i"))
-       {
-         queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, pool->installed->repoid);
-         argc--;
-         argv++;
-       }
-      else if (argc > 2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "--repo")))
-       {
-         Id repoid = find_repo(argv[2], pool, repoinfos, nrepoinfos);
-         if (!repoid)
-           {
-             fprintf(stderr, "%s: no such repo\n", argv[2]);
-             exit(1);
-           }
-         /* SETVENDOR is actually wrong but useful */
-         queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO | SOLVER_SETVENDOR, repoid);
-         argc -= 2;
-         argv += 2;
-       }
-      else if (argc > 2 && !strcmp(argv[1], "--arch"))
-       {
-         if (!strcmp(argv[2], "src") || !strcmp(argv[2], "nosrc"))
-           archfilter_src = 1;
-         queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, argv[2], 1), REL_ARCH, 1));
-         argc -= 2;
-         argv += 2;
-       }
-      else if (argc > 2 && (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--type")))
-       {
-         const char *kind = argv[2];
-         if (!strcmp(kind, "srcpackage"))
-           {
-             /* hey! should use --arch! */
-             queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, ARCH_SRC, REL_ARCH, 1));
-             archfilter_src = 1;
-             argc -= 2;
-             argv += 2;
-             continue;
-           }
-         if (!strcmp(kind, "package"))
-           kind = "";
-         if (!strcmp(kind, "all"))
-           queue_push2(&kindfilter, SOLVER_SOLVABLE_ALL, 0);
-         else
-           queue_push2(&kindfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, kind, 1), REL_KIND, 1));
-         argc -= 2;
-         argv += 2;
-       }
-      else
-       break;
-    }
-
-  if (mainmode == MODE_SEARCH)
-    {
-      Queue sel, q;
-      Dataiterator di;
-      if (argc != 2)
-       usage(1);
-      pool_createwhatprovides(pool);
-      queue_init(&sel);
-      dataiterator_init(&di, pool, 0, 0, 0, argv[1], SEARCH_SUBSTRING|SEARCH_NOCASE);
-      dataiterator_set_keyname(&di, SOLVABLE_NAME);
-      dataiterator_set_search(&di, 0, 0);
-      while (dataiterator_step(&di))
-       queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
-      dataiterator_set_keyname(&di, SOLVABLE_SUMMARY);
-      dataiterator_set_search(&di, 0, 0);
-      while (dataiterator_step(&di))
-       queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
-      dataiterator_set_keyname(&di, SOLVABLE_DESCRIPTION);
-      dataiterator_set_search(&di, 0, 0);
-      while (dataiterator_step(&di))
-       queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
-      dataiterator_free(&di);
-      if (repofilter.count)
-       selection_filter(pool, &sel, &repofilter);
-       
-      queue_init(&q);
-      selection_solvables(pool, &sel, &q);
-      queue_free(&sel);
-      for (i = 0; i < q.count; i++)
-       {
-         Solvable *s = pool_id2solvable(pool, q.elements[i]);
-         printf("  - %s [%s]: %s\n", pool_solvable2str(pool, s), s->repo->name, solvable_lookup_str(s, SOLVABLE_SUMMARY));
-       }
-      queue_free(&q);
-      exit(0);
-    }
-
-  /* process command line packages */
-  if (mainmode == MODE_LIST || mainmode == MODE_INFO || mainmode == MODE_INSTALL)
-    {
-      for (i = 1; i < argc; i++)
-       {
-         if (!is_cmdline_package((const char *)argv[i]))
-           continue;
-         if (access(argv[i], R_OK))
-           {
-             perror(argv[i]);
-             exit(1);
-           }
-         if (!commandlinepkgs)
-           commandlinepkgs = solv_calloc(argc, sizeof(Id));
-         if (!commandlinerepo)
-           commandlinerepo = repo_create(pool, "@commandline");
-         p = add_cmdline_package(commandlinerepo, (const char *)argv[i]);
-         if (!p)
-           {
-             fprintf(stderr, "could not add '%s'\n", argv[i]);
-             exit(1);
-           }
-         commandlinepkgs[i] = p;
-       }
-      if (commandlinerepo)
-       repo_internalize(commandlinerepo);
-    }
-
-#if defined(ENABLE_RPMDB)
-  if (pool->disttype == DISTTYPE_RPM)
-    addfileprovides(pool);
-#endif
-#ifdef SUSE
-  add_autopackages(pool);
-#endif
-  pool_createwhatprovides(pool);
-
-  if (keyname)
-    keyname = solv_dupjoin("solvable:", keyname, 0);
-  queue_init(&job);
-  for (i = 1; i < argc; i++)
-    {
-      Queue job2;
-      int flags, rflags;
-
-      if (commandlinepkgs && commandlinepkgs[i])
-       {
-         queue_push2(&job, SOLVER_SOLVABLE, commandlinepkgs[i]);
-         continue;
-       }
-      queue_init(&job2);
-      flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB;
-      flags |= SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL;
-      if (kindfilter.count)
-       flags |= SELECTION_SKIP_KIND;
-      if (mode == MODE_LIST || archfilter_src)
-       flags |= SELECTION_WITH_SOURCE;
-      if (argv[i][0] == '/')
-       flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
-      if (!keyname)
-        rflags = selection_make(pool, &job2, argv[i], flags);
-      else
-        rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
-      if (repofilter.count)
-       selection_filter(pool, &job2, &repofilter);
-      if (archfilter.count)
-       selection_filter(pool, &job2, &archfilter);
-      if (kindfilter.count)
-       selection_filter(pool, &job2, &kindfilter);
-      if (!job2.count)
-       {
-         flags |= SELECTION_NOCASE;
-         if (!keyname)
-            rflags = selection_make(pool, &job2, argv[i], flags);
-         else
-           rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
-         if (repofilter.count)
-           selection_filter(pool, &job2, &repofilter);
-         if (archfilter.count)
-           selection_filter(pool, &job2, &archfilter);
-         if (kindfilter.count)
-           selection_filter(pool, &job2, &kindfilter);
-         if (job2.count)
-           printf("[ignoring case for '%s']\n", argv[i]);
-       }
-      if (!job2.count)
-       {
-         fprintf(stderr, "nothing matches '%s'\n", argv[i]);
-         exit(1);
-       }
-      if (rflags & SELECTION_FILELIST)
-        printf("[using file list match for '%s']\n", argv[i]);
-      if (rflags & SELECTION_PROVIDES)
-       printf("[using capability match for '%s']\n", argv[i]);
-      queue_insertn(&job, job.count, job2.count, job2.elements);
-      queue_free(&job2);
-    }
-  keyname = solv_free(keyname);
-
-  if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count || archfilter.count || kindfilter.count))
-    {
-      queue_push2(&job, SOLVER_SOLVABLE_ALL, 0);
-      if (repofilter.count)
-       selection_filter(pool, &job, &repofilter);
-      if (archfilter.count)
-       selection_filter(pool, &job, &archfilter);
-      if (kindfilter.count)
-       selection_filter(pool, &job, &kindfilter);
-    }
-  queue_free(&repofilter);
-  queue_free(&archfilter);
-  queue_free(&kindfilter);
-
-  if (!job.count && mainmode != MODE_PATCH)
-    {
-      printf("no package matched\n");
-      exit(1);
-    }
-
-  if (mainmode == MODE_LIST || mainmode == MODE_INFO)
-    {
-      /* list mode, no solver needed */
-      Queue q;
-      queue_init(&q);
-      for (i = 0; i < job.count; i += 2)
-       {
-         int j;
-         queue_empty(&q);
-         pool_job2solvables(pool, &q, job.elements[i], job.elements[i + 1]);
-         for (j = 0; j < q.count; j++)
-           {
-             Solvable *s = pool_id2solvable(pool, q.elements[j]);
-             if (mainmode == MODE_INFO)
-               {
-                 const char *str;
-                 printf("Name:        %s\n", pool_solvable2str(pool, s));
-                 printf("Repo:        %s\n", s->repo->name);
-                 printf("Summary:     %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY));
-                 str = solvable_lookup_str(s, SOLVABLE_URL);
-                 if (str)
-                   printf("Url:         %s\n", str);
-                 str = solvable_lookup_str(s, SOLVABLE_LICENSE);
-                 if (str)
-                   printf("License:     %s\n", str);
-                 printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION));
-                 printf("\n");
-               }
-             else
-               {
-#if 1
-                 const char *sum = solvable_lookup_str_lang(s, SOLVABLE_SUMMARY, "de", 1);
-#else
-                 const char *sum = solvable_lookup_str_poollang(s, SOLVABLE_SUMMARY);
-#endif
-                 printf("  - %s [%s]\n", pool_solvable2str(pool, s), s->repo->name);
-                 if (sum)
-                   printf("    %s\n", sum);
-               }
-           }
-       }
-      queue_free(&q);
-      queue_free(&job);
-      pool_free(pool);
-      free_repoinfos(repoinfos, nrepoinfos);
-      solv_free(commandlinepkgs);
-      exit(0);
-    }
-
-#if defined(SUSE) || defined(FEDORA)
-  if (mainmode == MODE_PATCH)
-    add_patchjobs(pool, &job);
-#endif
-
-  // add mode
-  for (i = 0; i < job.count; i += 2)
-    {
-      job.elements[i] |= mode;
-      if (mode == SOLVER_UPDATE && pool_isemptyupdatejob(pool, job.elements[i], job.elements[i + 1]))
-       job.elements[i] ^= SOLVER_UPDATE ^ SOLVER_INSTALL;
-      if (cleandeps)
-        job.elements[i] |= SOLVER_CLEANDEPS;
-      if (forcebest)
-        job.elements[i] |= SOLVER_FORCEBEST;
-    }
-
-  // multiversion test
-  // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1));
-  // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1));
-  // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1));
-#if 0
-  queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
-  queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
-#endif
-
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-rerunsolver:
-#endif
-  solv = solver_create(pool);
-  solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1);
-#ifdef FEDORA
-  solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1);
-#endif
-  if (mainmode == MODE_ERASE)
-    solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1);     /* don't nag */
-  solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
-
-  for (;;)
-    {
-      Id problem, solution;
-      int pcnt, scnt;
-
-      if (!solver_solve(solv, &job))
-       break;
-      pcnt = solver_problem_count(solv);
-      printf("Found %d problems:\n", pcnt);
-      for (problem = 1; problem <= pcnt; problem++)
-       {
-         int take = 0;
-         printf("Problem %d/%d:\n", problem, pcnt);
-         solver_printprobleminfo(solv, problem);
-         printf("\n");
-         scnt = solver_solution_count(solv, problem);
-         for (solution = 1; solution <= scnt; solution++)
-           {
-             printf("Solution %d:\n", solution);
-             solver_printsolution(solv, problem, solution);
-             printf("\n");
-           }
-         for (;;)
-           {
-             char inbuf[128], *ip;
-             printf("Please choose a solution: ");
-             fflush(stdout);
-             *inbuf = 0;
-             if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
-               {
-                 printf("Abort.\n");
-                 exit(1);
-               }
-             while (*ip == ' ' || *ip == '\t')
-               ip++;
-             if (*ip >= '0' && *ip <= '9')
-               {
-                 take = atoi(ip);
-                 if (take >= 1 && take <= scnt)
-                   break;
-               }
-             if (*ip == 's')
-               {
-                 take = 0;
-                 break;
-               }
-             if (*ip == 'q')
-               {
-                 printf("Abort.\n");
-                 exit(1);
-               }
-           }
-         if (!take)
-           continue;
-         solver_take_solution(solv, problem, take, &job);
-       }
-    }
-
-  trans = solver_create_transaction(solv);
-  if (!trans->steps.count)
-    {
-      printf("Nothing to do.\n");
-      transaction_free(trans);
-      solver_free(solv);
-      queue_free(&job);
-      pool_free(pool);
-      free_repoinfos(repoinfos, nrepoinfos);
-      solv_free(commandlinepkgs);
-      exit(1);
-    }
-
-  /* display transaction to the user and ask for confirmation */
-  printf("\n");
-  printf("Transaction summary:\n\n");
-  transaction_print(trans);
-#if defined(SUSE)
-  showdiskusagechanges(trans);
-#endif
-  printf("install size change: %d K\n", transaction_calc_installsizechange(trans));
-  printf("\n");
-
-  if (!yesno("OK to continue (y/n)? "))
-    {
-      printf("Abort.\n");
-      transaction_free(trans);
-      solver_free(solv);
-      queue_free(&job);
-      pool_free(pool);
-      free_repoinfos(repoinfos, nrepoinfos);
-      solv_free(commandlinepkgs);
-      exit(1);
-    }
-
-  /* download all new packages */
-  queue_init(&checkq);
-  newpkgs = transaction_installedresult(trans, &checkq);
-  newpkgsfps = 0;
-  if (newpkgs)
-    {
-      int downloadsize = 0;
-      for (i = 0; i < newpkgs; i++)
-       {
-         Solvable *s;
-
-         p = checkq.elements[i];
-         s = pool_id2solvable(pool, p);
-         downloadsize += solvable_lookup_sizek(s, SOLVABLE_DOWNLOADSIZE, 0);
-       }
-      printf("Downloading %d packages, %d K\n", newpkgs, downloadsize);
-      newpkgsfps = solv_calloc(newpkgs, sizeof(*newpkgsfps));
-      for (i = 0; i < newpkgs; i++)
-       {
-         const char *loc;
-         Solvable *s;
-         struct repoinfo *cinfo;
-
-         p = checkq.elements[i];
-         s = pool_id2solvable(pool, p);
-         if (s->repo == commandlinerepo)
-           {
-             loc = solvable_lookup_location(s, 0);
-             if (!loc)
-               continue;
-             if (!(newpkgsfps[i] = fopen(loc, "r")))
-               {
-                 perror(loc);
-                 exit(1);
-               }
-             putchar('.');
-             continue;
-           }
-         cinfo = s->repo->appdata;
-         if (!cinfo || cinfo->type == TYPE_INSTALLED)
-           {
-             printf("%s: no repository information\n", s->repo->name);
-             exit(1);
-           }
-         loc = solvable_lookup_location(s, 0);
-         if (!loc)
-            continue;  /* pseudo package? */
-#if defined(ENABLE_RPMDB)
-         if (pool->installed && pool->installed->nsolvables)
-           {
-             if ((newpkgsfps[i] = trydeltadownload(s, loc)) != 0)
-               {
-                 putchar('d');
-                 fflush(stdout);
-                 continue;             /* delta worked! */
-               }
-           }
-#endif
-         if ((newpkgsfps[i] = downloadpackage(s, loc)) == 0)
-           {
-             printf("\n%s: %s not found in repository\n", s->repo->name, loc);
-             exit(1);
-           }
-         putchar('.');
-         fflush(stdout);
-       }
-      putchar('\n');
-    }
-
-#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
-  /* check for file conflicts */
-  if (newpkgs)
-    {
-      Queue conflicts;
-      queue_init(&conflicts);
-      if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts))
-       {
-         if (yesno("Re-run solver (y/n/q)? "))
-           {
-             for (i = 0; i < newpkgs; i++)
-               if (newpkgsfps[i])
-                 fclose(newpkgsfps[i]);
-             newpkgsfps = solv_free(newpkgsfps);
-             solver_free(solv);
-             solv = 0;
-             pool_add_fileconflicts_deps(pool, &conflicts);
-             queue_free(&conflicts);
-             goto rerunsolver;
-           }
-       }
-      queue_free(&conflicts);
-    }
-#endif
-
-  /* and finally commit the transaction */
-  printf("Committing transaction:\n\n");
-  transaction_order(trans, 0);
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      int j;
-      FILE *fp;
-      Id type;
-
-      p = trans->steps.elements[i];
-      type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY);
-      switch(type)
-       {
-       case SOLVER_TRANSACTION_ERASE:
-         printf("erase %s\n", pool_solvid2str(pool, p));
-         commit_transactionelement(pool, type, p, 0);
-         break;
-       case SOLVER_TRANSACTION_INSTALL:
-       case SOLVER_TRANSACTION_MULTIINSTALL:
-         printf("install %s\n", pool_solvid2str(pool, p));
-         for (j = 0; j < newpkgs; j++)
-           if (checkq.elements[j] == p)
-             break;
-         fp = j < newpkgs ? newpkgsfps[j] : 0;
-         if (!fp)
-           continue;
-         commit_transactionelement(pool, type, p, fp);
-         fclose(fp);
-         newpkgsfps[j] = 0;
-         break;
-       default:
-         break;
-       }
-    }
-
-  for (i = 0; i < newpkgs; i++)
-    if (newpkgsfps[i])
-      fclose(newpkgsfps[i]);
-  solv_free(newpkgsfps);
-  queue_free(&checkq);
-  transaction_free(trans);
-  solver_free(solv);
-  queue_free(&job);
-  pool_free(pool);
-  free_repoinfos(repoinfos, nrepoinfos);
-  solv_free(commandlinepkgs);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/examples/tclsolv b/libsolv-0.6.15/examples/tclsolv
deleted file mode 100755 (executable)
index 0fc4e2a..0000000
+++ /dev/null
@@ -1,803 +0,0 @@
-#!/usr/bin/tclsh
-
-package require solv
-package require inifile
-package require fileutil
-
-set reposdir /etc/zypp/repos.d
-
-### some helpers
-
-proc fileno {file} {
-  if [regexp -- {^file(\d+)$} $file match fd] {
-    return $fd
-  }
-  error "file not open"
-}
-
-set ::globalarray_cnt 0
-
-proc globalarray {} {
-  set name "::globalarray_[incr ::globalarray_cnt]"
-  array set $name [list varName $name]
-  return $name
-}
-
-### generic repo handling (cache reading/writing)
-
-proc repo_calc_cookie_file {selfName filename} {
-  upvar $selfName self
-  set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256]
-  $chksum add "1.1"
-  $chksum add_stat $filename
-  return [$chksum raw]
-}
-
-proc repo_calc_cookie_fp {selfName fp} {
-  upvar $selfName self
-  set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256]
-  $chksum add "1.1"
-  $chksum add_fp $fp
-  return [$chksum raw]
-}
-
-proc repo_calc_cookie_ext {selfName f cookie} {
-  upvar $selfName self
-  set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256]
-  $chksum add "1.1"
-  $chksum add $cookie
-  $chksum add_fstat [$f fileno]
-  return [$chksum raw]
-}
-
-proc repo_cachepath {selfName {ext "-"}} {
-  upvar $selfName self
-  regsub {^\.} $self(name) _ path
-  if {$ext ne "-"} {
-    set path "${path}_$ext.solvx"
-  } else {
-    set path "${path}.solv"
-  }
-  regsub -all / $path _ path
-  return "/var/cache/solv/$path"
-}
-
-proc repo_generic_load {selfName pool} {
-  upvar $selfName self
-  set handle [ $pool add_repo $self(name) ]
-  set self(handle) $handle
-  $handle configure -priority [expr 99 - $self(priority)] -appdata $self(varName)
-  set dorefresh $self(autorefresh)
-  set metadata_expire $self(metadata_expire)
-  catch {
-    if {$metadata_expire == -1 || [clock seconds] - [file mtime [repo_cachepath self]] < $metadata_expire} {
-      set dorefresh 0
-    }
-  }
-  set self(cookie) {}
-  set self(extcookie) {}
-  if { !$dorefresh && [repo_usecachedrepo self] } {
-    puts "repo $self(name): cached"
-    return 1 
-  }
-  return 0 
-}
-
-proc repo_free_handle {selfName} {
-  upvar $selfName self
-  set handle $self(handle)
-  unset self(handle)
-  $handle free 1
-}
-
-proc repo_usecachedrepo {selfName {ext "-"} {mark 0}} {
-  upvar $selfName self
-  set repopath [repo_cachepath self $ext]
-  set code [catch {
-    set f [open $repopath "rb"]
-    seek $f -32 end
-    set fcookie [read $f 32]
-    set cookie [expr {$ext eq "-" ? $self(cookie) : $self(extcookie)}]
-    if {$cookie ne {} && $cookie ne $fcookie} {
-      close $f
-      return 0
-    }
-    set fextcookie {}
-    if {$ext eq "-" && $self(type) ne "system"} {
-      seek $f -64 end
-      set fextcookie [read $f 32]
-    }
-    seek $f 0 start
-    set ff [solv::xfopen_fd {} [fileno $f]]
-    close $f
-    set flags 0
-    if {$ext ne "-"} {
-      set flags [expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES]
-      if {$ext ne "DL"} {
-       set flags [expr $flags | $solv::Repo_REPO_LOCALPOOL]
-      }
-    }
-    if {! [$self(handle) add_solv $ff $flags]} {
-      $ff close
-      return 0
-    }
-    $ff close
-    if {$self(type) ne "system" && $ext eq "-"} {
-      set self(cookie) $fcookie
-      set self(extcookie) $fextcookie
-    }
-    if {$mark} {
-      catch {
-        ::fileutil::touch -c -m -t [clock seconds] $repopath
-      }
-    }
-    return 1
-  } res]
-  return [expr {$code == 2 ? $res : 0}]
-}
-
-proc repo_writecachedrepo {selfName {ext "-"} {repodata "NULL"}} {
-  upvar $selfName self
-  if [info exists self(incomplete)] {
-    return
-  }
-  file mkdir "/var/cache/solv"
-  ::fileutil::tempdir "/var/cache/solv"
-  set tempfilename [::fileutil::tempfile ".newsolv-"]
-  ::fileutil::tempdirReset
-  set f [solv::xfopen $tempfilename "w+"]
-  file attributes $tempfilename -permissions 0444
-  if {$repodata eq {NULL}} {
-    $self(handle) write $f
-  } else {
-    $repodata write $f
-  }
-  $f flush
-  if {$self(type) ne "system" && $ext eq "-"} {
-    if {$self(extcookie) eq {}} {
-      set self(extcookie) [repo_calc_cookie_ext self $f $self(cookie)]
-    }
-    $f write $self(extcookie)
-  }
-  $f write [expr {$ext eq "-" ? $self(cookie) : $self(extcookie)}]
-  $f close
-  file rename -force -- $tempfilename [repo_cachepath self $ext]
-}
-
-proc repo_download {selfName file uncompress chksum {markincomplete 0}} {
-  upvar $selfName self
-  regsub {/$} $self(baseurl) {} url
-  set url "$url/$file"
-  set tempfilename [::fileutil::tempfile]
-  set f [open $tempfilename rb+]
-  file delete -- $tempfilename
-  if [catch {
-    exec -ignorestderr -- curl -f -s -L $url ">@$f"
-  }] {
-    seek $f 0 end
-    if {($chksum ne "" && $chksum ne "NULL") || [tell $f] != 0} {
-      puts "$file: download error"
-    }
-    close $f
-    return {NULL}
-  }
-  seek $f 0 start
-  if {$chksum ne "" && $chksum ne "NULL"} {
-    set fchksum [solv::new_Chksum [$chksum cget -type]]
-    if {$fchksum eq "" || $fchksum eq "NULL"} {
-      puts "$file: unknown checksum type"
-      if {$markincomplete} {
-       set self(incomplete) 1
-      }
-      close $f
-      return {NULL}
-    }
-    $fchksum add_fd [fileno $f]
-    if {[$fchksum != $chksum]} {
-      puts "$file: checksum mismatch"
-      if {$markincomplete} {
-       set self(incomplete) 1
-      }
-      close $f
-      return {NULL}
-    }
-  }
-  set ff [solv::xfopen_fd [expr {$uncompress ? $file : ""}] [fileno $f]]
-  close $f
-  return $ff
-}
-
-proc repo_generic_add_ext_keys {selfName ext repodata h} {
-  upvar $selfName self
-  if {$ext eq "DL"} {
-    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOSITORY_DELTAINFO
-    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_FLEXARRAY
-  } elseif {$ext eq "DU"} {
-    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::SOLVABLE_DISKUSAGE
-    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_DIRNUMNUMARRAY
-  } elseif {$ext eq "FL"} {
-    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::SOLVABLE_FILELIST
-    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_DIRSTRARRAY
-  }
-}
-
-### system
-
-proc repo_system_load {selfName pool} {
-  upvar $selfName self
-  set handle [ $pool add_repo $self(name) ]
-  set self(handle) $handle
-  $handle configure -appdata $self(varName)
-  $pool configure -installed $handle
-  puts -nonewline "rpm database: "
-  set self(cookie) [repo_calc_cookie_file self "/var/lib/rpm/Packages"]
-  if [repo_usecachedrepo self] {
-    puts "cached"
-    return 1
-  }
-  puts "reading"
-  set f [solv::xfopen [repo_cachepath self]]
-  $handle add_rpmdb_reffp $f $solv::Repo_REPO_REUSE_REPODATA
-  repo_writecachedrepo self
-}
-
-### repomd
-
-proc repo_repomd_add_ext {selfName repodata what ext} {
-  upvar $selfName self
-  set where [repo_repomd_find self $what]
-  if {$where eq {}} {
-    return
-  }
-  set h [$repodata new_handle]
-  $repodata set_poolstr $h $solv::REPOSITORY_REPOMD_TYPE $what
-  $repodata set_str $h $solv::REPOSITORY_REPOMD_LOCATION [lindex $where 0]
-  $repodata set_checksum $h $solv::REPOSITORY_REPOMD_CHECKSUM [lindex $where 1]
-  repo_generic_add_ext_keys self $ext $repodata $h
-  $repodata add_flexarray $solv::SOLVID_META $solv::REPOSITORY_EXTERNAL $h
-}
-
-proc repo_repomd_add_exts {selfName} {
-  upvar $selfName self
-  set repodata [$self(handle) add_repodata 0]
-  repo_repomd_add_ext self $repodata "filelists" "FL"
-  $repodata internalize
-}
-
-proc repo_repomd_find {selfName what} {
-  upvar $selfName self
-  set di [$self(handle) Dataiterator_meta $solv::REPOSITORY_REPOMD_TYPE $what $solv::Dataiterator_SEARCH_STRING]
-  $di prepend_keyname $solv::REPOSITORY_REPOMD
-  solv::iter d $di {
-    set dp [$d parentpos]
-    set filename [$dp lookup_str $solv::REPOSITORY_REPOMD_LOCATION]
-    set checksum [$dp lookup_checksum $solv::REPOSITORY_REPOMD_CHECKSUM]
-    if {$filename ne "" && $checksum eq "NULL"} {
-      puts "no $filename file checksum"
-    } elseif {$filename ne ""} {
-      return [list $filename $checksum]
-    }
-  }
-  return {}
-}
-
-proc repo_repomd_load {selfName pool} {
-  upvar $selfName self
-  if [repo_generic_load self $pool] {
-    return 1
-  }
-  puts -nonewline "rpmmd repo '$self(name)': "
-  set f [repo_download self {repodata/repomd.xml} 0 {}]
-  if {$f eq {NULL}} {
-    puts "no repomd.xml file, skipped"
-    repo_free_handle self
-    return 0
-  }
-  set self(cookie) [repo_calc_cookie_fp self $f]
-  if [repo_usecachedrepo self "-" 1] {
-    puts "cached"
-    return 1
-  }
-  set handle $self(handle)
-  $handle add_repomdxml $f
-  puts "fetching"
-  set primary [repo_repomd_find self primary]
-  if {$primary ne {}} {
-    set f [repo_download self [lindex $primary 0] 1 [lindex $primary 1] 1]
-    if {$f ne {NULL}} {
-      $handle add_rpmmd $f {}
-      $f close
-    }
-    if [info exists self(incomplete)] {
-      return 0
-    }
-  }
-  set updateinfo [repo_repomd_find self primary]
-  if {$updateinfo ne {}} {
-    set f [repo_download self [lindex $updateinfo  0] 1 [lindex $updateinfo 1] 1]
-    if {$f ne {NULL}} {
-      $handle add_updateinfoxml $f
-      $f close
-    }
-  }
-  repo_repomd_add_exts self
-  repo_writecachedrepo self
-  $self(handle) create_stubs
-  return 1
-}
-
-proc repo_repomd_packagespath {selfName} {
-  return ""
-}
-
-proc repo_repomd_load_ext {selfName repodata} {
-  upvar $selfName self
-  switch -- [$repodata lookup_str $solv::SOLVID_META $solv::REPOSITORY_REPOMD_TYPE] {
-    "deltainfo" {
-      set ext DL
-    }
-    "filelists" {
-      set ext FL
-    }
-    default {
-      return 0
-    }
-  }
-  puts -nonewline "\[$self(name):$ext: "
-  flush stdout
-  if [repo_usecachedrepo self $ext] {
-    puts "cached]"
-    return 1
-  }
-  puts "fetching]"
-  set handle $self(handle)
-  set filename [$repodata lookup_str $solv::SOLVID_META $solv::REPOSITORY_REPOMD_LOCATION]
-  set filechecksum [$repodata lookup_checksum $solv::SOLVID_META $solv::REPOSITORY_REPOMD_CHECKSUM]
-  set f [repo_download self $filename 1 $filechecksum]
-  if {$f eq {NULL}} {
-    return 0
-  }
-  if {$ext eq "FL"} {
-    $handle add_rpmmd $f "FL" [ expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES | $solv::Repo_REPO_LOCALPOOL]
-  }
-  $f close
-  repo_writecachedrepo self $ext $repodata
-  return 1
-}
-
-### susetags
-
-proc repo_susetags_add_ext {selfName repodata what ext} {
-  upvar $selfName self
-  set where [repo_susetags_find self $what]
-  if {$where eq {}} {
-    return
-  }
-  set h [$repodata new_handle]
-  $repodata set_str $h $solv::SUSETAGS_FILE_NAME [lindex $where 0]
-  $repodata set_checksum $h $solv::SUSETAGS_FILE_CHECKSUM [lindex $where 1]
-  repo_generic_add_ext_keys self $ext $repodata $h
-  $repodata add_flexarray $solv::SOLVID_META $solv::REPOSITORY_EXTERNAL $h
-}
-
-proc repo_susetags_add_exts {selfName} {
-  upvar $selfName self
-  set repodata [$self(handle) add_repodata 0]
-  repo_susetags_add_ext self $repodata "packages.FL" "FL"
-  repo_susetags_add_ext self $repodata "packages.FL.gz" "FL"
-  $repodata internalize
-}
-
-proc repo_susetags_find {selfName what} {
-  upvar $selfName self
-  set di [$self(handle) Dataiterator_meta $solv::SUSETAGS_FILE_NAME $what $solv::Dataiterator_SEARCH_STRING]
-  $di prepend_keyname $solv::SUSETAGS_FILE
-  solv::iter d $di {
-    set dp [$d parentpos]
-    set checksum [$dp lookup_checksum $solv::SUSETAGS_FILE_CHECKSUM]
-    return [list $what $checksum]
-  }
-  return {}
-}
-
-proc repo_susetags_load {selfName pool} {
-  upvar $selfName self
-  if [repo_generic_load self $pool] {
-    return 1
-  }
-  puts -nonewline "susetags repo '$self(name)': "
-  set f [repo_download self {content} 0 {}]
-  if {$f eq {NULL}} {
-    puts "no content file, skipped"
-    repo_free_handle self
-    return 0
-  }
-  set self(cookie) [repo_calc_cookie_fp self $f]
-  if [repo_usecachedrepo self "-" 1] {
-    puts "cached"
-    return 1
-  }
-  set handle $self(handle)
-  $handle add_content $f
-  puts "fetching"
-  set defvendorid [[$handle cget -meta] lookup_id $solv::SUSETAGS_DEFAULTVENDOR]
-  set descrdir [[$handle cget -meta] lookup_str $solv::SUSETAGS_DESCRDIR]
-  if {$descrdir eq {NULL}} {
-    set descrdir "suse/setup/descr"
-  }
-  set packages [repo_susetags_find self "packages.gz"]
-  if {$packages eq {}} {
-    set packages [repo_susetags_find self "packages"]
-  }
-  if {$packages ne {}} {
-    set f [repo_download self "$descrdir/[lindex $packages 0]" 1 [lindex $packages 1] 1]
-    if {$f ne {NULL}} {
-      $handle add_susetags $f $defvendorid {} [expr $solv::Repo_REPO_NO_INTERNALIZE | $solv::Repo_SUSETAGS_RECORD_SHARES]
-      $f close
-      set packages [repo_susetags_find self "packages.en.gz"]
-      if {$packages eq {}} {
-       set packages [repo_susetags_find self "packages.en"]
-      }
-      if {$packages ne {}} {
-       set f [repo_download self "$descrdir/[lindex $packages 0]" 1 [lindex $packages 1] 1]
-       if {$f ne {NULL}} {
-          $handle add_susetags $f $defvendorid {} [expr $solv::Repo_REPO_NO_INTERNALIZE | $solv::Repo_REPO_REUSE_REPODATA | $solv::Repo_REPO_EXTEND_SOLVABLES ]
-         $f close
-       }
-      }
-      $handle internalize
-    }
-  }
-  repo_susetags_add_exts self
-  repo_writecachedrepo self
-  $self(handle) create_stubs
-  return 1
-}
-
-proc repo_susetags_packagespath {selfName} {
-  upvar $selfName self
-  set datadir [[$self(handle) cget -meta] lookup_str $solv::SUSETAGS_DATADIR]
-  return [expr {$datadir ne {} ? "$datadir/" : "suse/"}]
-}
-
-proc repo_susetags_load_ext {selfName repodata} {
-  upvar $selfName self
-  set filename [$repodata lookup_str $solv::SOLVID_META $solv::SUSETAGS_FILE_NAME]
-  set ext [string range $filename 9 10]
-  puts -nonewline "\[$self(name):$ext: "
-  flush stdout
-  if [repo_usecachedrepo self $ext] {
-    puts "cached]"
-    return 1
-  }
-  puts "fetching]"
-  set handle $self(handle)
-  set defvendorid [[$handle cget -meta] lookup_id $solv::SUSETAGS_DEFAULTVENDOR]
-  set descrdir [[$handle cget -meta] lookup_str $solv::SUSETAGS_DESCRDIR]
-  if {$descrdir eq {NULL}} {
-    set descrdir "suse/setup/descr"
-  }
-  set filechecksum [$repodata lookup_checksum $solv::SOLVID_META $solv::SUSETAGS_FILE_CHECKSUM]
-  set f [repo_download self "$descrdir/$filename" 1 $filechecksum]
-  if {$f eq {NULL}} {
-    return 0
-  }
-  set flags [expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES]
-  if {$ext ne "DL"} {
-    set flags [expr $flags | $solv::Repo_REPO_LOCALPOOL]
-  }
-  $handle add_susetags $f $defvendorid $ext $flags
-  $f close
-  repo_writecachedrepo self $ext $repodata
-  return 1
-}
-
-### unknown
-
-proc repo_unknown_load {selfName pool} {
-  upvar $selfName self
-  puts "unsupported repo '$self(name)': skipped"
-  return 0
-}
-
-### poor man's OO
-
-proc repo_load {selfName pool} {
-  upvar $selfName self
-  "repo_$self(type)_load" self $pool
-}
-
-proc repo_packagespath {selfName} {
-  upvar $selfName self
-  "repo_$self(type)_packagespath" self
-}
-
-proc repo_load_ext {selfName repodata} {
-  upvar $selfName self
-  "repo_$self(type)_load_ext" self $repodata
-}
-
-###
-
-proc load_stub {repodata} {
-  set code [catch {
-    upvar #0 [[$repodata cget -repo] cget -appdata] repo
-    if [info exists repo(handle)] {
-      return [repo_load_ext repo $repodata]
-    }
-    return 0
-  } res]
-  if {$code == 2} {
-    return $res
-  }
-  puts stderr $res
-  return 0
-}
-
-###
-
-set repoNames {}
-foreach reponame [lsort [glob -nocomplain -directory $reposdir *.repo]] {
-  set ini [::ini::open $reponame r]
-  foreach alias [::ini::sections $ini] {
-    upvar #0 [globalarray] repo
-    array set repo {enabled 0 priority 99 autorefresh 1 type rpm-md metadata_expire 900}
-    array set repo [::ini::get $ini $alias]
-    set repo(name) $alias
-    switch -exact -- $repo(type) {
-      rpm-md  { set repo(type) repomd }
-      yast2   { set repo(type) susetags }
-      default { set repo(type) unknown }
-    }
-    lappend repoNames $repo(varName)
-  }
-  ::ini::close $ini
-}
-
-set pool [solv::new_Pool]
-$pool setarch
-$pool set_loadcallback load_stub
-
-upvar #0 [globalarray] sysrepo
-array set sysrepo [list name {@System} type system]
-repo_load sysrepo $pool
-
-foreach repoName $repoNames {
-  upvar 0 $repoName repo
-  if {$repo(enabled)} {
-    repo_load repo $pool
-  }
-}
-
-
-set cmd [lindex $::argv 0]
-set ::argv [lreplace $::argv 0 0]
-
-array set cmdabbrev [ list \
-  in install \
-  rm erase \
-  ls list \
-  ve verify \
-  se search \
-]
-if [info exists cmdabbrev($cmd)] {
-  set cmd $cmdabbrev($cmd)
-}
-
-if {$cmd eq "search"} {
-  set arg [lindex $::argv 0]
-  $pool createwhatprovides
-  set sel [$pool Selection]
-  set di [$pool Dataiterator $solv::SOLVABLE_NAME $arg [ expr $solv::Dataiterator_SEARCH_SUBSTRING | $solv::Dataiterator_SEARCH_NOCASE ]]
-  solv::iter d $di {
-    $sel add_raw $solv::Job_SOLVER_SOLVABLE [$d cget -solvid]
-  }
-  foreach s [$sel solvables] {
-    puts [format { - %s [%s]: %s} [$s str] [[$s cget -repo] cget -name] [$s lookup_str $solv::SOLVABLE_SUMMARY]]
-  }
-  exit
-}
-
-$pool addfileprovides
-$pool createwhatprovides
-
-array set cmdactionmap [ list \
-  install $solv::Job_SOLVER_INSTALL \
-  erase $solv::Job_SOLVER_ERASE \
-  up $solv::Job_SOLVER_UPDATE \
-  dup $solv::Job_SOLVER_DISTUPGRADE \
-  verify $solv::Job_SOLVER_VERIFY \
-  list 0 \
-  info 0 \
-]
-
-set jobs {}
-foreach arg $::argv {
-  set flags [expr $solv::Selection_SELECTION_NAME | $solv::Selection_SELECTION_PROVIDES | $solv::Selection_SELECTION_GLOB | \
-                  $solv::Selection_SELECTION_CANON | $solv::Selection_SELECTION_DOTARCH | $solv::Selection_SELECTION_REL ]
-  switch -glob -- $arg {
-    "/*" {
-      set flags [expr $flags | $solv::Selection_SELECTION_FILELIST ]
-      if {$cmd eq "erase"} {
-        set flags [expr $flags | $solv::Selection_SELECTION_INSTALLED_ONLY ]
-      }
-    }
-  }
-  set sel [$pool select $arg $flags]
-  if [$sel isempty] {
-    set sel [$pool select $arg [expr $flags | $solv::Selection_SELECTION_NOCASE]]
-    if {![$sel isempty]} {
-      puts "\[ignoring case for '$arg']"
-    }
-  }
-  if [$sel isempty] {
-    puts "nothing matches '$arg'"
-    exit 1
-  }
-  if {[$sel flags] & $solv::Selection_SELECTION_FILELIST} {
-    puts "\[using file list match for '$arg']"
-  }
-  if {[$sel flags] & $solv::Selection_SELECTION_PROVIDES} {
-    puts "\[using capability match for '$arg']"
-  }
-  lappend jobs {*}[$sel jobs $cmdactionmap($cmd)]
-}
-
-if {$jobs eq {} && ($cmd eq "up" || $cmd eq "dup" || $cmd eq "verify") } {
-  set sel [$pool Selection_all]
-  lappend jobs {*}[$sel jobs $cmdactionmap($cmd)]
-}
-
-if {$jobs eq {}} {
-  puts "no package matched."
-  exit 1
-}
-
-if {$cmd eq "list" || $cmd eq "info"} {
-  foreach job $jobs {
-    foreach s [$job solvables] {
-      if {$cmd eq "info"} {
-        puts [format {Name:        %s} [$s str]]
-        puts [format {Repo:        %s} [[$s cget -repo] cget -name]]
-        puts [format {Summary:     %s} [$s lookup_str $solv::SOLVABLE_SUMMARY]]
-        set str [$s lookup_str $solv::SOLVABLE_URL]
-       if {$str ne {}} {
-          puts [format {Url:         %s} $str]
-       }
-        set str [$s lookup_str $solv::SOLVABLE_LICENSE]
-       if {$str ne {}} {
-          puts [format {License      %s} $str]
-       }
-        puts [format {Description: %s} [$s lookup_str $solv::SOLVABLE_DESCRIPTION]]
-       puts {}
-      } else {
-        puts [format {  - %s [%s]} [$s str] [[$s cget -repo] cget -name]]
-        puts [format {    %s} [$s lookup_str $solv::SOLVABLE_SUMMARY]]
-      }
-    }
-  }
-  exit
-}
-
-#$pool set_debuglevel 1
-set solver [$pool Solver]
-$solver set_flag $solv::Solver_SOLVER_FLAG_SPLITPROVIDES 1
-if {$cmd eq "erase"} {
-  $solver set_flag $solv::Solver_SOLVER_FLAG_ALLOW_UNINSTALL 1
-}
-
-set problems [$solver solve $jobs]
-if {$problems ne {}} {
-  set pcnt 1
-  foreach problem $problems {
-    puts [format {Problem %d/%d:} $pcnt [llength $problems]]
-    puts [$problem str]
-    incr pcnt
-  }
-  exit 1
-}
-
-set trans [$solver transaction]
-
-if [$trans isempty] {
-  puts "Nothing to do."
-  exit
-}
-
-puts {}
-puts "Transaction summary:"
-puts {}
-foreach cl [$trans classify [expr $solv::Transaction_SOLVER_TRANSACTION_SHOW_OBSOLETES | $solv::Transaction_SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE]] {
-  switch -- [$cl cget -type] \
-    $solv::Transaction_SOLVER_TRANSACTION_ERASE {
-      puts [format {%d erased packages:} [$cl cget -count]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_INSTALL {
-      puts [format {%d installed packages:} [$cl cget -count]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_REINSTALLED {
-      puts [format {%d reinstalled packages:} [$cl cget -count]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_DOWNGRADED {
-      puts [format {%d downgraded packages:} [$cl cget -count]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_CHANGED {
-      puts [format {%d changed packages:} [$cl cget -count]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_UPGRADED {
-      puts [format {%d upgraded packages:} [$cl cget -count]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_VENDORCHANGE {
-      puts [format {%d vendor changes from '%s' to '%s':} [$cl cget -count] [$cl cget -fromstr] [$cl cget -tostr]]
-    } \
-    $solv::Transaction_SOLVER_TRANSACTION_ARCHCHANGE {
-      puts [format {%d archchanges from '%s' to '%s':} [$cl cget -count] [$cl cget -fromstr] [$cl cget -tostr]]
-    } \
-    default continue
-  foreach p [$cl solvables] {
-    set cltype [$cl cget -type]
-    if {$cltype == $solv::Transaction_SOLVER_TRANSACTION_UPGRADED || $cltype ==$solv::Transaction_SOLVER_TRANSACTION_DOWNGRADED} {
-      set op [$trans othersolvable $p]
-      puts [format {  - %s -> %s} [$p str] [$op str]]
-    } else {
-      puts [format {  - %s} [$p str]]
-    }
-  }
-  puts {}
-}
-puts [format {install size change: %d K} [$trans calc_installsizechange]]
-puts {}
-
-while 1 {
-  puts -nonewline "OK to continue (y/n)? "
-  flush stdout
-  set yn [gets stdin]
-  if {$yn eq "y"} {
-    break
-  }
-  if {$yn eq "n" || $yn eq "q"} {
-    exit
-  }
-}
-
-set newpkgs [$trans newsolvables]
-array set newpkgs_f {}
-if {$newpkgs ne {}} {
-  set downloadsize 0
-  foreach p $newpkgs {
-    set downloadsize [expr $downloadsize + [$p lookup_num $solv::SOLVABLE_DOWNLOADSIZE]]
-  }
-  puts [format {Downloading %d packages, %d K} [llength $newpkgs] [expr $downloadsize / 1024]]
-  foreach p $newpkgs {
-    upvar #0 [[$p cget -repo] cget -appdata] repo
-    set location [$p lookup_location]
-    if {$location eq {}} {
-      continue
-    }
-    set location "[repo_packagespath repo][lindex $location 0]"
-    set checksum [$p lookup_checksum $solv::SOLVABLE_CHECKSUM]
-    set f [repo_download repo $location 0 $checksum]
-    set newpkgs_f([$p cget -id]) $f
-    puts -nonewline "."
-    flush stdout
-  }
-  puts {}
-}
-
-puts "Committing transaction:"
-$trans order
-foreach p [$trans steps] {
-  set steptype [$trans steptype $p $solv::Transaction_SOLVER_TRANSACTION_RPM_ONLY]
-  if {$steptype == $solv::Transaction_SOLVER_TRANSACTION_ERASE} {
-    puts "erase [$p str]"
-    regsub {^[0-9]+:} [$p cget -evr] {} nvr
-    set nvr "[$p cget -name]-$nvr.[$p cget -arch]"
-    exec -ignorestderr -- rpm -e --nodeps --nodigest --nosignature $nvr
-  } elseif {$steptype == $solv::Transaction_SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction_SOLVER_TRANSACTION_MULTIINSTALL} {
-    puts "install [$p str]"
-    set f $newpkgs_f([$p cget -id])
-    set mode [expr {$steptype == $solv::Transaction_SOLVER_TRANSACTION_INSTALL ? "-U" : "-i"}]
-    $f cloexec 0
-    exec -ignorestderr -- rpm $mode --force --nodeps --nodigest --nosignature "/dev/fd/[$f fileno]"
-  }
-}
diff --git a/libsolv-0.6.15/ext/CMakeLists.txt b/libsolv-0.6.15/ext/CMakeLists.txt
deleted file mode 100644 (file)
index ad52495..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-SET (libsolvext_SRCS
-    solv_xfopen.c testcase.c)
-
-SET (libsolvext_HEADERS
-    tools_util.h solv_xfopen.h testcase.h)
-
-IF (ENABLE_RPMDB)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-        pool_fileconflicts.c repo_rpmdb.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-        pool_fileconflicts.h repo_rpmdb.h)
-ENDIF (ENABLE_RPMDB)
-
-IF (ENABLE_PUBKEY)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_pubkey.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_pubkey.h)
-ENDIF (ENABLE_PUBKEY)
-
-IF (ENABLE_PGPVRFY)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       solv_pgpvrfy.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       solv_pgpvrfy.h)
-ENDIF (ENABLE_PGPVRFY)
-
-IF (ENABLE_RPMMD)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_repomdxml.c repo_rpmmd.c
-       repo_deltainfoxml.c repo_updateinfoxml.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_repomdxml.h repo_rpmmd.h
-       repo_deltainfoxml.h repo_updateinfoxml.h)
-ENDIF (ENABLE_RPMMD)
-
-IF (ENABLE_SUSEREPO)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_content.c repo_products.c repo_releasefile_products.c
-       repo_susetags.c repo_zyppdb.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_content.h repo_products.h repo_releasefile_products.h
-       repo_susetags.h repo_zyppdb.h)
-ENDIF (ENABLE_SUSEREPO)
-
-# old cmake does not support parenthetical expressions...
-IF (ENABLE_COMPLEX_DEPS)
-IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       pool_parserpmrichdep.c)
-ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB)
-ENDIF (ENABLE_COMPLEX_DEPS)
-
-IF (SUSE)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_autopattern.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_autopattern.h)
-ENDIF (SUSE)
-
-IF (ENABLE_COMPS)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_comps.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_comps.h)
-ENDIF (ENABLE_COMPS)
-
-IF (ENABLE_DEBIAN)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_deb.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_deb.h)
-ENDIF (ENABLE_DEBIAN)
-
-IF (ENABLE_HELIXREPO)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_helix.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_helix.h)
-ENDIF (ENABLE_HELIXREPO)
-
-IF (ENABLE_MDKREPO)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_mdk.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_mdk.h)
-ENDIF (ENABLE_MDKREPO)
-
-IF (ENABLE_ARCHREPO)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_arch.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_arch.h)
-ENDIF (ENABLE_ARCHREPO)
-
-IF (ENABLE_CUDFREPO)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_cudf.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_cudf.h)
-ENDIF (ENABLE_CUDFREPO)
-
-IF (ENABLE_HAIKU)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_haiku.cpp)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_haiku.h)
-ENDIF (ENABLE_HAIKU)
-
-IF (ENABLE_APPDATA)
-    SET (libsolvext_SRCS ${libsolvext_SRCS}
-       repo_appdata.c)
-    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
-       repo_appdata.h)
-ENDIF (ENABLE_APPDATA)
-
-SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
-IF (HAVE_LINKER_VERSION_SCRIPT)
-SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
-ENDIF (HAVE_LINKER_VERSION_SCRIPT)
-
-IF (DISABLE_SHARED)
-ADD_LIBRARY (libsolvext STATIC ${libsolvext_SRCS})
-ELSE (DISABLE_SHARED)
-ADD_LIBRARY (libsolvext SHARED ${libsolvext_SRCS})
-TARGET_LINK_LIBRARIES(libsolvext libsolv ${SYSTEM_LIBRARIES})
-ENDIF (DISABLE_SHARED)
-
-SET_TARGET_PROPERTIES(libsolvext PROPERTIES OUTPUT_NAME "solvext")
-SET_TARGET_PROPERTIES(libsolvext PROPERTIES SOVERSION ${LIBSOLVEXT_SOVERSION})
-SET_TARGET_PROPERTIES(libsolvext PROPERTIES INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
-
-INSTALL (FILES ${libsolvext_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/solv")
-INSTALL (TARGETS libsolvext LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
-
-IF (ENABLE_STATIC AND NOT DISABLE_SHARED)
-ADD_LIBRARY (libsolvext_static STATIC ${libsolvext_SRCS})
-SET_TARGET_PROPERTIES(libsolvext_static PROPERTIES OUTPUT_NAME "solvext")
-SET_TARGET_PROPERTIES(libsolvext_static PROPERTIES SOVERSION ${LIBSOLVEXT_SOVERSION})
-INSTALL (TARGETS libsolvext_static LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
-ENDIF (ENABLE_STATIC AND NOT DISABLE_SHARED)
diff --git a/libsolv-0.6.15/ext/libsolvext.ver b/libsolv-0.6.15/ext/libsolvext.ver
deleted file mode 100644 (file)
index 654469b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-SOLV_1.0 {
-       global:
-               pool_deb_get_autoinstalled;
-               pool_findfileconflicts;
-               repo_add_appdata;
-               repo_add_appdata_dir;
-               repo_add_arch_local;
-               repo_add_arch_pkg;
-               repo_add_arch_repo;
-               repo_add_autopattern;
-               repo_add_code11_products;
-               repo_add_content;
-               repo_add_comps;
-               repo_add_cudf;
-               repo_add_deb;
-               repo_add_debdb;
-               repo_add_debpackages;
-               repo_add_deltainfoxml;
-               repo_add_haiku_installed_packages;
-               repo_add_haiku_package;
-               repo_add_haiku_package_info;
-               repo_add_haiku_packages;
-               repo_add_helix;
-               repo_add_keydir;
-               repo_add_keyring;
-               repo_add_mdk;
-               repo_add_mdk_info;
-               repo_add_products;
-               repo_add_pubkey;
-               repo_add_releasefile_products;
-               repo_add_repomdxml;
-               repo_add_rpm;
-               repo_add_rpm_handle;
-               repo_add_rpmdb;
-               repo_add_rpmdb_pubkeys;
-               repo_add_rpmdb_reffp;
-               repo_add_rpmmd;
-               repo_add_susetags;
-               repo_add_updateinfoxml;
-               repo_add_zyppdb_products;
-               repo_find_all_pubkeys;
-               repo_find_pubkey;
-               repo_verify_sigdata;
-               rpm_byfp;
-               rpm_byrpmdbid;
-               rpm_byrpmh;
-               rpm_installedrpmdbids;
-               rpm_iterate_filelist;
-               rpm_query;
-               rpm_query_num;
-               rpm_state_create;
-               rpm_state_free;
-               solv_verify_sig;
-               solv_xfopen;
-               solv_xfopen_buf;
-               solv_xfopen_fd;
-               solv_xfopen_iscompressed;
-               solvsig_create;
-               solvsig_free;
-               solvsig_verify;
-               testcase_add_testtags;
-               testcase_dep2str;
-               testcase_job2str;
-               testcase_solvid2str;
-               testcase_str2dep;
-               testcase_str2job;
-               testcase_str2repo;
-               testcase_read;
-               testcase_resultdiff;
-               testcase_solverresult;
-               testcase_write;
-               testcase_write_testtags;
-       local:
-               *;
-};
diff --git a/libsolv-0.6.15/ext/pool_fileconflicts.c b/libsolv-0.6.15/ext/pool_fileconflicts.c
deleted file mode 100644 (file)
index 4238d2d..0000000
+++ /dev/null
@@ -1,1125 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "hash.h"
-#include "repo_rpmdb.h"
-#include "pool_fileconflicts.h"
-
-struct cbdata {
-  Pool *pool;
-  int create;
-  int aliases;
-
-  Queue lookat;                /* conflict candidates */
-  Queue lookat_dir;    /* not yet conflicting directories */
-
-  Hashtable cflmap;
-  Hashval cflmapn;
-  unsigned int cflmapused;
-
-  Hashtable dirmap;
-  Hashval dirmapn;
-  unsigned int dirmapused;
-  int dirconflicts;
-
-  Map idxmap;
-
-  unsigned int lastdiridx;     /* last diridx we have seen */
-  unsigned int lastdirhash;    /* strhash of last dir we have seen */
-
-  Id idx;      /* index of package we're looking at */
-  Id hx;       /* used in findfileconflicts2_cb, limit to files matching hx */
-
-  Id dirid;    /* used in findfileconflicts2_cb, limit to dirs matching dirid */
-  Id dirhash;  /* used in findfileconflicts2_cb, limit to dirs matching dirhash */
-
-  Queue files;
-  unsigned char *filesspace;
-  unsigned int filesspacen;
-
-  Hashtable normap;
-  Hashval normapn;
-  unsigned int normapused;
-  Queue norq;
-
-  Hashtable statmap;
-  Hashval statmapn;
-  unsigned int statmapused;
-
-  int usestat;
-  int statsmade;
-
-  const char *rootdir;
-  int rootdirl;
-
-  char *canonspace;
-  int canonspacen;
-};
-
-#define FILESSPACE_BLOCK 255
-
-static Hashtable
-growhash(Hashtable map, Hashval *mapnp)
-{
-  Hashval mapn = *mapnp;
-  Hashval newn = (mapn + 1) * 2 - 1;
-  Hashval i, h, hh;
-  Hashtable m;
-  Id hx, qx;
-
-  m = solv_calloc(newn + 1, 2 * sizeof(Id));
-  for (i = 0; i <= mapn; i++)
-    {
-      hx = map[2 * i];
-      if (!hx)
-       continue;
-      h = hx & newn;
-      hh = HASHCHAIN_START;
-      for (;;)
-       {
-         qx = m[2 * h];
-         if (!qx)
-           break;
-         h = HASHCHAIN_NEXT(h, hh, newn);
-       }
-      m[2 * h] = hx;
-      m[2 * h + 1] = map[2 * i + 1];
-    }
-  solv_free(map);
-  *mapnp = newn;
-  return m;
-}
-
-static void
-finddirs_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
-{
-  struct cbdata *cbdata = cbdatav;
-  Hashval h, hh;
-  Id hx, qx;
-  Id oidx, idx = cbdata->idx;
-
-  hx = strhash(fn);
-  if (!hx)
-    hx = strlen(fn) + 1;
-  h = hx & cbdata->dirmapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->dirmap[2 * h];
-      if (!qx)
-       break;
-      if (qx == hx)
-       break;
-      h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn);
-    }
-  if (!qx)
-    {
-      /* a miss */
-      if (!cbdata->create)
-       return;
-      cbdata->dirmap[2 * h] = hx;
-      cbdata->dirmap[2 * h + 1] = idx;
-      if (++cbdata->dirmapused * 2 > cbdata->dirmapn)
-       cbdata->dirmap = growhash(cbdata->dirmap, &cbdata->dirmapn);
-      return;
-    }
-  oidx = cbdata->dirmap[2 * h + 1];
-  if (oidx == idx)
-    return;
-  /* found a conflict, this dir may be used in multiple packages */
-  if (oidx != -1)
-    {
-      MAPSET(&cbdata->idxmap, oidx);
-      cbdata->dirmap[2 * h + 1] = -1;
-      cbdata->dirconflicts++;
-    }
-  MAPSET(&cbdata->idxmap, idx);
-}
-
-static inline int
-isindirmap(struct cbdata *cbdata, Id hx)
-{
-  Hashval h, hh;
-  Id qx;
-
-  h = hx & cbdata->dirmapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->dirmap[2 * h];
-      if (!qx)
-       return 0;
-      if (qx == hx)
-       return cbdata->dirmap[2 * h + 1] == -1 ? 1 : 0;
-      h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn);
-    }
-}
-
-static void
-findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
-{
-  struct cbdata *cbdata = cbdatav;
-  int isdir = S_ISDIR(info->mode);
-  const char *dp;
-  Id idx, oidx;
-  Id hx, qx;
-  Hashval h, hh, dhx;
-
-  idx = cbdata->idx;
-
-  if (!info->dirlen)
-    return;
-  dp = fn + info->dirlen;
-  if (info->diridx != cbdata->lastdiridx)
-    {
-      cbdata->lastdiridx = info->diridx;
-      cbdata->lastdirhash = strnhash(fn, dp - fn);
-    }
-  dhx = cbdata->lastdirhash;
-  /* this mirrors the "if (!hx) hx = strlen(fn) + 1" in finddirs_cb */
-  if (!isindirmap(cbdata, dhx ? dhx : dp - fn + 1))
-    return;
-  hx = strhash_cont(dp, dhx);
-  if (!hx)
-    hx = strlen(fn) + 1;
-
-  h = hx & cbdata->cflmapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->cflmap[2 * h];
-      if (!qx)
-       break;
-      if (qx == hx)
-       break;
-      h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
-    }
-  if (!qx)
-    {
-      /* a miss */
-      if (!cbdata->create)
-       return;
-      cbdata->cflmap[2 * h] = hx;
-      cbdata->cflmap[2 * h + 1] = (isdir ? ~idx : idx);
-      if (++cbdata->cflmapused * 2 > cbdata->cflmapn)
-       cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn);
-      return;
-    }
-  oidx = cbdata->cflmap[2 * h + 1];
-  if (oidx < 0)
-    {
-      int i;
-      if (isdir)
-       {
-         /* both are directories. delay the conflict, keep oidx in slot */
-          queue_push2(&cbdata->lookat_dir, hx, idx);
-         return;
-       }
-      oidx = ~oidx;
-      /* now have file, had directories before. */
-      cbdata->cflmap[2 * h + 1] = oidx;        /* make it a file */
-      /* dump all delayed directory hits for hx */
-      for (i = 0; i < cbdata->lookat_dir.count; i += 2)
-       if (cbdata->lookat_dir.elements[i] == hx)
-         {
-           queue_push2(&cbdata->lookat, hx, cbdata->lookat_dir.elements[i + 1]);
-           queue_push2(&cbdata->lookat, 0, 0);
-         }
-    }
-  else if (oidx == idx)
-    return;    /* no conflicts with ourself, please */
-  queue_push2(&cbdata->lookat, hx, oidx);
-  queue_push2(&cbdata->lookat, 0, 0);
-  queue_push2(&cbdata->lookat, hx, idx);
-  queue_push2(&cbdata->lookat, 0, 0);
-}
-
-/* same as findfileconflicts_cb, but
- * - hashes with just the basename
- * - sets idx in a map instead of pushing to lookat
- * - sets the hash element to -1 if there may be a conflict
- */
-static void
-findfileconflicts_basename_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
-{
-  struct cbdata *cbdata = cbdatav;
-  int isdir = S_ISDIR(info->mode);
-  const char *dp;
-  Id idx, oidx;
-  Id hx, qx;
-  Hashval h, hh;
-
-  idx = cbdata->idx;
-
-  if (!info->dirlen)
-    return;
-  dp = fn + info->dirlen;
-  hx = strhash(dp);
-  if (!hx)
-    hx = strlen(fn) + 1;
-
-  h = hx & cbdata->cflmapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->cflmap[2 * h];
-      if (!qx)
-       break;
-      if (qx == hx)
-       break;
-      h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
-    }
-  if (!qx)
-    {
-      /* a miss */
-      if (!cbdata->create)
-       return;
-      cbdata->cflmap[2 * h] = hx;
-      cbdata->cflmap[2 * h + 1] = (isdir ? -idx - 2 : idx);
-      if (++cbdata->cflmapused * 2 > cbdata->cflmapn)
-       cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn);
-      return;
-    }
-  oidx = cbdata->cflmap[2 * h + 1];
-  if (oidx < -1)
-    {
-      int i;
-      if (isdir)
-       {
-         /* both are directories. delay the conflict, keep oidx in slot */
-          queue_push2(&cbdata->lookat_dir, hx, idx);
-         return;
-       }
-      oidx = -idx - 2;
-      /* now have file, had directories before. */
-      cbdata->cflmap[2 * h + 1] = oidx;        /* make it a file */
-      /* dump all delayed directory hits for hx */
-      for (i = 0; i < cbdata->lookat_dir.count; i += 2)
-       if (cbdata->lookat_dir.elements[i] == hx)
-         MAPSET(&cbdata->idxmap, cbdata->lookat_dir.elements[i + 1]);
-    }
-  else if (oidx == idx)
-    return;    /* no conflicts with ourself, please */
-  if (oidx >= 0)
-    MAPSET(&cbdata->idxmap, oidx);
-  MAPSET(&cbdata->idxmap, idx);
-  if (oidx != -1)
-    cbdata->cflmap[2 * h + 1] = -1;
-}
-
-static inline Id
-addfilesspace(struct cbdata *cbdata, int len)
-{
-  unsigned int off = cbdata->filesspacen;
-  cbdata->filesspace = solv_extend(cbdata->filesspace, cbdata->filesspacen, len, 1, FILESSPACE_BLOCK);
-  cbdata->filesspacen += len;
-  return off;
-}
-
-static Id
-unifywithstat(struct cbdata *cbdata, Id diroff, int dirl)
-{
-  struct stat stb;
-  int i;
-  Hashval h, hh;
-  Id hx, qx;
-  Id nspaceoff;
-  unsigned char statdata[16 + sizeof(stb.st_dev) + sizeof(stb.st_ino)];
-
-  if (dirl > 1 && cbdata->filesspace[diroff + dirl - 1] == '/')
-    cbdata->filesspace[diroff + dirl - 1] = 0;
-  cbdata->statsmade++;
-  i = stat((char *)cbdata->filesspace + diroff, &stb);
-  if (dirl > 1 && cbdata->filesspace[diroff + dirl - 1] == 0)
-    cbdata->filesspace[diroff + dirl - 1] = '/';
-  if (i)
-    return diroff;
-  memset(statdata, 0, 16);
-  memcpy(statdata + 8, &stb.st_dev, sizeof(stb.st_dev));
-  memcpy(statdata, &stb.st_ino, sizeof(stb.st_ino));
-  hx = 0;
-  for (i = 15; i >= 0; i--)
-    hx = (unsigned int)hx * 13 + statdata[i];
-  h = hx & cbdata->statmapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->statmap[2 * h];
-      if (!qx)
-       break;
-      if (qx == hx)
-       {
-         Id off = cbdata->statmap[2 * h + 1];
-         char *dp = (char *)cbdata->filesspace + cbdata->norq.elements[off];
-         if (!memcmp(dp, statdata, 16))
-           return cbdata->norq.elements[off + 1];
-       }
-      h = HASHCHAIN_NEXT(h, hh, cbdata->statmapn);
-    }
-  /* new stat result. work. */
-  nspaceoff = addfilesspace(cbdata, 16);
-  memcpy(cbdata->filesspace + nspaceoff, statdata, 16);
-  queue_push2(&cbdata->norq, nspaceoff, nspaceoff);
-  cbdata->statmap[2 * h] = hx;
-  cbdata->statmap[2 * h + 1] = cbdata->norq.count - 2;
-  if (++cbdata->statmapused * 2 > cbdata->statmapn)
-    cbdata->statmap = growhash(cbdata->statmap, &cbdata->statmapn);
-  return nspaceoff;
-}
-
-/* forward declaration */
-static Id normalizedir(struct cbdata *cbdata, const char *dir, int dirl, Id hx, int create);
-
-static Id
-unifywithcanon(struct cbdata *cbdata, Id diroff, int dirl)
-{
-  Id dirnameid;
-  int i, l, ll, lo;
-  struct stat stb;
-
-#if 0
-  printf("UNIFY %.*s\n", dirl, (char *)cbdata->filesspace + diroff);
-#endif
-  if (!dirl || cbdata->filesspace[diroff] != '/')
-    return diroff;
-  /* strip / at end*/
-  while (dirl && cbdata->filesspace[diroff + dirl - 1] == '/')
-    dirl--;
-  if (!dirl)
-    return diroff;
-
-  /* find dirname */
-  for (i = dirl - 1; i > 0; i--)
-    if (cbdata->filesspace[diroff + i] == '/')
-      break;
-  i++;                         /* include trailing / */
-
-  /* normalize dirname */
-  dirnameid = normalizedir(cbdata, (char *)cbdata->filesspace + diroff, i, strnhash((char *)cbdata->filesspace + diroff, i), 1);
-  if (dirnameid == -1)
-    return diroff;             /* hit "in progress" marker, some cyclic link */
-
-  /* sanity check result */
-  if (cbdata->filesspace[dirnameid] != '/')
-    return diroff;             /* hmm */
-  l = strlen((char *)cbdata->filesspace + dirnameid);
-  if (l && cbdata->filesspace[dirnameid + l - 1] != '/')
-    return diroff;             /* hmm */
-
-  /* special handling for "." and ".." basename */
-  if (cbdata->filesspace[diroff + i] == '.')
-    {
-      if (dirl - i == 1)
-       return dirnameid;
-      if (dirl - i == 2 && cbdata->filesspace[diroff + i + 1] == '.')
-       {
-         if (l <= 2)
-           return dirnameid;   /* we hit our root */
-         for (i = l - 2; i > 0; i--)
-           if (cbdata->filesspace[dirnameid + i] == '/')
-             break;
-         i++;  /* include trailing / */
-         dirnameid = normalizedir(cbdata, (char *)cbdata->filesspace + dirnameid, i, strnhash((char *)cbdata->filesspace + dirnameid, i), 1);
-         return dirnameid == -1 ? diroff : dirnameid;
-       }
-    }
-
-  /* append basename to normalized dirname */
-  if (cbdata->rootdirl + l + dirl - i + 1 > cbdata->canonspacen)
-    {
-      cbdata->canonspacen = cbdata->rootdirl + l + dirl - i + 20;
-      cbdata->canonspace = solv_realloc(cbdata->canonspace, cbdata->canonspacen);
-      strcpy(cbdata->canonspace, cbdata->rootdir);
-    }
-  strcpy(cbdata->canonspace + cbdata->rootdirl, (char *)cbdata->filesspace + dirnameid);
-  strncpy(cbdata->canonspace + cbdata->rootdirl + l, (char *)cbdata->filesspace + diroff + i, dirl - i);
-  cbdata->canonspace[cbdata->rootdirl + l + dirl - i] = 0;
-
-#if 0
-  printf("stat()ing %s\n", cbdata->canonspace);
-#endif
-  cbdata->statsmade++;
-  if (lstat(cbdata->canonspace, &stb) != 0 || !S_ISLNK(stb.st_mode))
-    {
-      /* not a symlink or stat failed, have new canon entry */
-      diroff = addfilesspace(cbdata, l + dirl - i + 2);
-      strcpy((char *)cbdata->filesspace + diroff, cbdata->canonspace + cbdata->rootdirl);
-      l += dirl - i;
-      /* add trailing / */
-      if (cbdata->filesspace[diroff + l - 1] != '/')
-       {
-         cbdata->filesspace[diroff + l++] = '/';
-         cbdata->filesspace[diroff + l] = 0;
-       }
-      /* call normalizedir on new entry for unification purposes */
-      dirnameid = normalizedir(cbdata, (char *)cbdata->filesspace + diroff, l, strnhash((char *)cbdata->filesspace + diroff, l), 1);
-      return dirnameid == -1 ? diroff : dirnameid;
-    }
-  /* oh no, a symlink! follow */
-  lo = cbdata->rootdirl + l + dirl - i + 1;
-  if (lo + stb.st_size + 2 > cbdata->canonspacen)
-    {
-      cbdata->canonspacen = lo + stb.st_size + 20;
-      cbdata->canonspace = solv_realloc(cbdata->canonspace, cbdata->canonspacen);
-    }
-  ll = readlink(cbdata->canonspace, cbdata->canonspace + lo, stb.st_size);
-  if (ll < 0 || ll > stb.st_size)
-    return diroff;             /* hmm */
-  if (ll == 0)
-    return dirnameid;          /* empty means current dir */
-  if (cbdata->canonspace[lo + ll - 1] != '/')
-    cbdata->canonspace[lo + ll++] = '/';       /* add trailing / */
-  cbdata->canonspace[lo + ll] = 0;             /* zero terminate */
-  if (cbdata->canonspace[lo] != '/')
-    {
-      /* relative link, concatenate to dirname */
-      memmove(cbdata->canonspace + cbdata->rootdirl + l, cbdata->canonspace + lo, ll + 1);
-      lo = cbdata->rootdirl;
-      ll += l;
-    }
-  dirnameid = normalizedir(cbdata, cbdata->canonspace + lo, ll, strnhash(cbdata->canonspace + lo, ll), 1);
-  return dirnameid == -1 ? diroff : dirnameid;
-}
-
-/*
- * map a directory (containing a trailing /) into a number.
- * for unifywithstat this is the offset to the 16 byte stat result.
- * for unifywithcanon this is the offset to the normailzed dir.
- */
-static Id
-normalizedir(struct cbdata *cbdata, const char *dir, int dirl, Id hx, int create)
-{
-  Hashval h, hh;
-  Id qx;
-  Id nspaceoff;
-  int mycnt;
-
-  if (!hx)
-    hx = dirl + 1;
-  h = hx & cbdata->normapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->normap[2 * h];
-      if (!qx)
-       break;
-      if (qx == hx)
-       {
-         Id off = cbdata->normap[2 * h + 1];
-         char *dp = (char *)cbdata->filesspace + cbdata->norq.elements[off];
-         if (!strncmp(dp, dir, dirl) && dp[dirl] == 0)
-           return cbdata->norq.elements[off + 1];
-       }
-      h = HASHCHAIN_NEXT(h, hh, cbdata->normapn);
-    }
-  if (!create)
-    return 0;
-  /* new dir. work. */
-  if (dir >= (const char *)cbdata->filesspace && dir < (const char *)cbdata->filesspace + cbdata->filesspacen)
-    {
-      /* can happen when called from unifywithcanon */
-      Id off = dir - (const char *)cbdata->filesspace;
-      nspaceoff = addfilesspace(cbdata, dirl + 1);
-      dir = (const char *)cbdata->filesspace + off;
-    }
-  else
-    nspaceoff = addfilesspace(cbdata, dirl + 1);
-  if (dirl)
-    memcpy(cbdata->filesspace + nspaceoff, dir, dirl);
-  cbdata->filesspace[nspaceoff + dirl] = 0;
-  mycnt = cbdata->norq.count;
-  queue_push2(&cbdata->norq, nspaceoff, -1);   /* -1: in progress */
-  cbdata->normap[2 * h] = hx;
-  cbdata->normap[2 * h + 1] = mycnt;
-  if (++cbdata->normapused * 2 > cbdata->normapn)
-    cbdata->normap = growhash(cbdata->normap, &cbdata->normapn);
-  /* unify */
-  if (cbdata->usestat)
-    nspaceoff = unifywithstat(cbdata, nspaceoff, dirl);
-  else
-    nspaceoff = unifywithcanon(cbdata, nspaceoff, dirl);
-  cbdata->norq.elements[mycnt + 1] = nspaceoff;        /* patch in result */
-#if 0
-  if (!cbdata->usestat)
-    printf("%s normalized to %d: %s\n", cbdata->filesspace + cbdata->norq.elements[mycnt], nspaceoff, cbdata->filesspace + nspaceoff);
-#endif
-  return nspaceoff;
-}
-
-static void
-findfileconflicts_alias_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
-{
-  int isdir = S_ISDIR(info->mode);
-  struct cbdata *cbdata = cbdatav;
-  const char *dp;
-  Id idx, dirid;
-  Id hx, qx;
-  Hashval h, hh;
-
-  idx = cbdata->idx;
-
-  if (!info->dirlen)
-    return;
-  dp = fn + info->dirlen;
-  if (info->diridx != cbdata->lastdiridx)
-    {
-      cbdata->lastdiridx = info->diridx;
-      cbdata->lastdirhash = 0;
-    }
-  dp = fn + info->dirlen;
-  hx = strhash(dp);
-  if (!hx)
-    hx = strlen(fn) + 1;
-
-  h = hx & cbdata->cflmapn;
-  hh = HASHCHAIN_START;
-  for (;;)
-    {
-      qx = cbdata->cflmap[2 * h];
-      if (!qx)
-       break;
-      if (qx == hx)
-       break;
-      h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
-    }
-  if (!qx || cbdata->cflmap[2 * h + 1] != -1)
-    return;
-  if (!cbdata->lastdirhash)
-    cbdata->lastdirhash = strnhash(fn, dp - fn);
-  dirid = normalizedir(cbdata, fn, dp - fn, cbdata->lastdirhash, 1);
-  queue_push2(&cbdata->lookat, hx, idx);
-  queue_push2(&cbdata->lookat, cbdata->lastdirhash, isdir ? -dirid : dirid);
-}
-
-static void
-findfileconflicts2_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
-{
-  struct cbdata *cbdata = cbdatav;
-  Hashval hx;
-  const char *dp;
-  char md5padded[34];
-  Id off;
-
-  if (!info->dirlen)
-    return;
-  dp = fn + info->dirlen;
-  if (info->diridx != cbdata->lastdiridx)
-    {
-      cbdata->lastdiridx = info->diridx;
-      cbdata->lastdirhash = strnhash(fn, dp - fn);
-    }
-  if (cbdata->aliases)
-    {
-      if (cbdata->lastdirhash != cbdata->dirhash)
-       return;
-      hx = strhash(dp);
-    }
-  else
-    {
-      hx = cbdata->lastdirhash;
-      hx = strhash_cont(dp, hx);
-    }
-  if (!hx)
-    hx = strlen(fn) + 1;
-  if ((Id)hx != cbdata->hx)
-    return;
-  if (cbdata->dirid && cbdata->dirid != normalizedir(cbdata, fn, dp - fn, cbdata->dirhash, 0))
-    return;
-  strncpy(md5padded, info->digest, 32);
-  md5padded[32] = 0;
-  md5padded[33] = info->color;
-  /* printf("%d, hx %x -> %s   %d %s\n", cbdata->idx, hx, fn, info->mode, info->digest); */
-  off = addfilesspace(cbdata, strlen(fn) + (34 + 1));
-  memcpy(cbdata->filesspace + off, (unsigned char *)md5padded, 34);
-  strcpy((char *)cbdata->filesspace + off + 34, fn);
-  queue_push(&cbdata->files, off);
-}
-
-static int
-lookat_idx_cmp(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap, *b = bp;
-  unsigned int ahx, bhx;
-  if (a[1] - b[1] != 0)                /* idx */
-    return a[1] - b[1];
-  if (a[3] - b[3] != 0)                /* dirid */
-    return a[3] - b[3];
-  ahx = (unsigned int)a[0];    /* can be < 0 */
-  bhx = (unsigned int)b[0];
-  if (ahx != bhx)
-    return ahx < bhx ? -1 : 1;
-  ahx = (unsigned int)a[2];    /* dhx */
-  bhx = (unsigned int)b[2];
-  if (ahx != bhx)
-    return ahx < bhx ? -1 : 1;
-  return 0;
-}
-
-static int
-lookat_hx_cmp(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap, *b = bp;
-  unsigned int ahx, bhx;
-  Id adirid, bdirid;
-  ahx = (unsigned int)a[0];    /* can be < 0 */
-  bhx = (unsigned int)b[0];
-  if (ahx != bhx)
-    return ahx < bhx ? -1 : 1;
-  adirid = a[3] < 0 ? -a[3] : a[3];
-  bdirid = b[3] < 0 ? -b[3] : b[3];
-  if (adirid - bdirid != 0)    /* dirid */
-    return adirid - bdirid;
-  if (a[3] != b[3])
-    return a[3] > 0 ? -1 : 1;  /* bring positive dirids to front */
-  if (a[1] - b[1] != 0)                /* idx */
-    return a[1] - b[1];
-  ahx = (unsigned int)a[2];    /* dhx */
-  bhx = (unsigned int)b[2];
-  if (ahx != bhx)
-    return ahx < bhx ? -1 : 1;
-  return 0;
-}
-
-static int
-conflicts_cmp(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  const Id *a = ap;
-  const Id *b = bp;
-  if (a[0] != b[0])    /* filename1 */
-    return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
-  if (a[3] != b[3])    /* filename2 */
-    return strcmp(pool_id2str(pool, a[3]), pool_id2str(pool, b[3]));
-  if (a[1] != b[1])    /* pkgid1 */
-    return a[1] - b[1];
-  if (a[4] != b[4])    /* pkgid2 */
-    return a[4] - b[4];
-  return 0;
-}
-
-static void
-iterate_solvable_dirs(Pool *pool, Id p, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata)
-{
-  Repodata *lastdata = 0;
-  Id lastdirid = -1;
-  Dataiterator di;
-
-  dataiterator_init(&di, pool, 0, p, SOLVABLE_FILELIST, 0, SEARCH_COMPLETE_FILELIST);
-  while (dataiterator_step(&di))
-    {
-      if (di.data == lastdata && di.kv.id == lastdirid)
-       continue;
-      lastdata = di.data;
-      lastdirid = di.kv.id;
-      cb(cbdata, repodata_dir2str(di.data, di.kv.id, ""), 0);
-    }
-  dataiterator_free(&di);
-}
-
-/* before calling the expensive findfileconflicts_cb we check if any of
- * the files match. This only makes sense when cbdata->create is off.
- */
-static int
-precheck_solvable_files(struct cbdata *cbdata, Pool *pool, Id p)
-{
-  Dataiterator di;
-  Id hx, qx;
-  Hashval h, hh;
-  int found = 0;
-  int aliases = cbdata->aliases;
-  unsigned int lastdirid = -1;
-  Hashval lastdirhash = 0;
-  int lastdirlen = 0;
-  int checkthisdir = 0;
-  Repodata *lastrepodata = 0;
-
-  dataiterator_init(&di, pool, 0, p, SOLVABLE_FILELIST, 0, SEARCH_COMPLETE_FILELIST);
-  while (dataiterator_step(&di))
-    {
-      if (aliases)
-       {
-         /* hash just the basename */
-         hx = strhash(di.kv.str);
-         if (!hx)
-           hx = strlen(di.kv.str) + 1;
-       }
-      else
-       {
-         /* hash the full path */
-         if (di.data != lastrepodata || di.kv.id != lastdirid)
-           {
-             const char *dir;
-             lastrepodata = di.data;
-             lastdirid = di.kv.id;
-             dir = repodata_dir2str(lastrepodata, lastdirid, "");
-             lastdirlen = strlen(dir);
-             lastdirhash = strhash(dir);
-             checkthisdir =  isindirmap(cbdata, lastdirhash ? lastdirhash : lastdirlen + 1);
-           }
-         if (!checkthisdir)
-           continue;
-         hx = strhash_cont(di.kv.str, lastdirhash);
-         if (!hx)
-           hx = lastdirlen + strlen(di.kv.str) + 1;
-       }
-      h = hx & cbdata->cflmapn;
-      hh = HASHCHAIN_START;
-      for (;;)
-       {
-         qx = cbdata->cflmap[2 * h];
-         if (!qx)
-           break;
-         if (qx == hx)
-           {
-             found = 1;
-             break;
-           }
-         h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
-       }
-      if (found)
-       break;
-    }
-  dataiterator_free(&di);
-  return found;
-}
-
-
-int
-pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, int flags, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata)
-{
-  int i, j, cflmapn, idxmapset;
-  struct cbdata cbdata;
-  unsigned int now, start;
-  void *handle;
-  Repo *installed = pool->installed;
-  Id p;
-  int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
-  int hdrfetches;
-
-  queue_empty(conflicts);
-  if (!pkgs->count)
-    return 0;
-
-  now = start = solv_timems(0);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "searching for file conflicts\n");
-  POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d\n", pkgs->count, cutoff);
-
-  memset(&cbdata, 0, sizeof(cbdata));
-  cbdata.aliases = flags & FINDFILECONFLICTS_CHECK_DIRALIASING;
-  cbdata.pool = pool;
-  if (cbdata.aliases && (flags & FINDFILECONFLICTS_USE_ROOTDIR) != 0)
-    {
-      cbdata.rootdir = pool_get_rootdir(pool);
-      if (cbdata.rootdir && !strcmp(cbdata.rootdir, "/"))
-       cbdata.rootdir = 0;
-      if (cbdata.rootdir)
-       cbdata.rootdirl = strlen(cbdata.rootdir);
-      if (!cbdata.rootdir)
-       cbdata.usestat = 1;
-    }
-  queue_init(&cbdata.lookat);
-  queue_init(&cbdata.lookat_dir);
-  map_init(&cbdata.idxmap, pkgs->count);
-
-  if (cutoff <= 0)
-    cutoff = pkgs->count;
-
-  /* avarage file list size: 200 files per package */
-  /* avarage dir count: 20 dirs per package */
-
-  /* first pass: scan dirs */
-  if (!cbdata.aliases)
-    {
-      hdrfetches = 0;
-      cflmapn = (cutoff + 3) * 64;
-      while ((cflmapn & (cflmapn - 1)) != 0)
-       cflmapn = cflmapn & (cflmapn - 1);
-      cbdata.dirmap = solv_calloc(cflmapn, 2 * sizeof(Id));
-      cbdata.dirmapn = cflmapn - 1;    /* make it a mask */
-      cbdata.create = 1;
-      idxmapset = 0;
-      for (i = 0; i < pkgs->count; i++)
-       {
-         if (i == cutoff)
-           cbdata.create = 0;
-         cbdata.idx = i;
-         p = pkgs->elements[i];
-         if ((flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed)
-           {
-             if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed)
-               {
-                 iterate_solvable_dirs(pool, p, finddirs_cb, &cbdata);
-                 if (MAPTST(&cbdata.idxmap, i))
-                   idxmapset++;
-                 continue;
-               }
-           }
-         handle = (*handle_cb)(pool, p, handle_cbdata);
-         if (!handle)
-           continue;
-         hdrfetches++;
-         rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_ONLYDIRS, finddirs_cb, &cbdata);
-         if (MAPTST(&cbdata.idxmap, i))
-           idxmapset++;
-       }
-      POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap size: %d, used %d\n", cbdata.dirmapn + 1, cbdata.dirmapused);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap memory usage: %d K\n", (cbdata.dirmapn + 1) * 2 * (int)sizeof(Id) / 1024);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap creation took %d ms\n", solv_timems(now));
-      POOL_DEBUG(SOLV_DEBUG_STATS, "dir conflicts found: %d, idxmap %d of %d\n", cbdata.dirconflicts, idxmapset, pkgs->count);
-    }
-
-  /* second pass: scan files */
-  now = solv_timems(0);
-  cflmapn = (cutoff + 3) * 128;
-  while ((cflmapn & (cflmapn - 1)) != 0)
-    cflmapn = cflmapn & (cflmapn - 1);
-  cbdata.cflmap = solv_calloc(cflmapn, 2 * sizeof(Id));
-  cbdata.cflmapn = cflmapn - 1;        /* make it a mask */
-  cbdata.create = 1;
-  hdrfetches = 0;
-  for (i = 0; i < pkgs->count; i++)
-    {
-      if (i == cutoff)
-       cbdata.create = 0;
-      if (!cbdata.aliases && !MAPTST(&cbdata.idxmap, i))
-       continue;
-      cbdata.idx = i;
-      p = pkgs->elements[i];
-      if (!cbdata.create && (flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed)
-       {
-         if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed)
-           if (!precheck_solvable_files(&cbdata, pool, p))
-             continue;
-       }
-      /* can't use FINDFILECONFLICTS_USE_SOLVABLEFILELIST because we have to know if
-       * the file is a directory or not */
-      handle = (*handle_cb)(pool, p, handle_cbdata);
-      if (!handle)
-       continue;
-      hdrfetches++;
-      cbdata.lastdiridx = -1;
-      rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, cbdata.aliases ? findfileconflicts_basename_cb : findfileconflicts_cb, &cbdata);
-    }
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "filemap size: %d, used %d\n", cbdata.cflmapn + 1, cbdata.cflmapused);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "filemap memory usage: %d K\n", (cbdata.cflmapn + 1) * 2 * (int)sizeof(Id) / 1024);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "filemap creation took %d ms\n", solv_timems(now));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "lookat_dir size: %d\n", cbdata.lookat_dir.count);
-  queue_free(&cbdata.lookat_dir);
-
-  /* we need another pass for aliases */
-  if (cbdata.aliases)
-    {
-      now = solv_timems(0);
-      /* make sure the first offset is not zero */
-      addfilesspace(&cbdata, 1);
-      cflmapn = (cutoff + 3) * 16;
-      while ((cflmapn & (cflmapn - 1)) != 0)
-       cflmapn = cflmapn & (cflmapn - 1);
-      cbdata.normap = solv_calloc(cflmapn, 2 * sizeof(Id));
-      cbdata.normapn = cflmapn - 1;    /* make it a mask */
-      if (cbdata.usestat)
-       {
-         cbdata.statmap = solv_calloc(cflmapn, 2 * sizeof(Id));
-         cbdata.statmapn = cflmapn - 1;        /* make it a mask */
-       }
-      cbdata.create = 0;
-      hdrfetches = 0;
-      for (i = 0; i < pkgs->count; i++)
-       {
-         if (!MAPTST(&cbdata.idxmap, i))
-           continue;
-         p = pkgs->elements[i];
-         cbdata.idx = i;
-         /* can't use FINDFILECONFLICTS_USE_SOLVABLEFILELIST because we have to know if
-          * the file is a directory or not */
-         handle = (*handle_cb)(pool, p, handle_cbdata);
-         if (!handle)
-           continue;
-         hdrfetches++;
-         cbdata.lastdiridx = -1;
-         rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, findfileconflicts_alias_cb, &cbdata);
-       }
-      POOL_DEBUG(SOLV_DEBUG_STATS, "normap size: %d, used %d\n", cbdata.normapn + 1, cbdata.normapused);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "normap memory usage: %d K\n", (cbdata.normapn + 1) * 2 * (int)sizeof(Id) / 1024);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "stats made: %d\n", cbdata.statsmade);
-      if (cbdata.usestat)
-       {
-         POOL_DEBUG(SOLV_DEBUG_STATS, "statmap size: %d, used %d\n", cbdata.statmapn + 1, cbdata.statmapused);
-         POOL_DEBUG(SOLV_DEBUG_STATS, "statmap memory usage: %d K\n", (cbdata.statmapn + 1) * 2 * (int)sizeof(Id) / 1024);
-       }
-      cbdata.statmap = solv_free(cbdata.statmap);
-      cbdata.statmapn = 0;
-      cbdata.canonspace = solv_free(cbdata.canonspace);
-      cbdata.canonspacen = 0;
-      POOL_DEBUG(SOLV_DEBUG_STATS, "alias processing took %d ms\n", solv_timems(now));
-    }
-
-  cbdata.dirmap = solv_free(cbdata.dirmap);
-  cbdata.dirmapn = 0;
-  cbdata.dirmapused = 0;
-  cbdata.cflmap = solv_free(cbdata.cflmap);
-  cbdata.cflmapn = 0;
-  cbdata.cflmapused = 0;
-
-  map_free(&cbdata.idxmap);
-
-  /* sort and unify/prune */
-  now = solv_timems(0);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "raw candidates: %d, pruning\n", cbdata.lookat.count / 4);
-  solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool);
-  for (i = j = 0; i < cbdata.lookat.count; )
-    {
-      int first = 1;
-      Id hx = cbdata.lookat.elements[i];
-      Id idx = cbdata.lookat.elements[i + 1];
-      Id dhx = cbdata.lookat.elements[i + 2];
-      Id dirid = cbdata.lookat.elements[i + 3];
-      i += 4;
-      for (; i < cbdata.lookat.count && hx == cbdata.lookat.elements[i] && (dirid == cbdata.lookat.elements[i + 3] || dirid == -cbdata.lookat.elements[i + 3]); i += 4)
-       {
-         if (idx == cbdata.lookat.elements[i + 1] && dhx == cbdata.lookat.elements[i + 2])
-           continue;   /* ignore duplicates */
-         if (first)
-           {
-             if (dirid < 0)
-               continue;       /* all have a neg dirid */
-             cbdata.lookat.elements[j++] = hx;
-             cbdata.lookat.elements[j++] = idx;
-             cbdata.lookat.elements[j++] = dhx;
-             cbdata.lookat.elements[j++] = dirid;
-             first = 0;
-           }
-         idx = cbdata.lookat.elements[i + 1];
-         dhx = cbdata.lookat.elements[i + 2];
-         cbdata.lookat.elements[j++] = hx;
-         cbdata.lookat.elements[j++] = idx;
-         cbdata.lookat.elements[j++] = dhx;
-         cbdata.lookat.elements[j++] = dirid;
-       }
-    }
-  queue_truncate(&cbdata.lookat, j);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "candidates now: %d\n", cbdata.lookat.count / 4);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "pruning took %d ms\n", solv_timems(now));
-
-  /* third pass: collect file info for all files that match a hx */
-  now = solv_timems(0);
-  solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_idx_cmp, pool);
-  queue_init(&cbdata.files);
-  hdrfetches = 0;
-  for (i = 0; i < cbdata.lookat.count; i += 4)
-    {
-      Id idx = cbdata.lookat.elements[i + 1];
-      int iterflags = RPM_ITERATE_FILELIST_WITHMD5 | RPM_ITERATE_FILELIST_NOGHOSTS;
-      if (obsoleteusescolors)
-       iterflags |= RPM_ITERATE_FILELIST_WITHCOL;
-      p = pkgs->elements[idx];
-      handle = (*handle_cb)(pool, p, handle_cbdata);
-      if (handle)
-       hdrfetches++;
-      for (;; i += 4)
-       {
-         int fstart = cbdata.files.count;
-         queue_push(&cbdata.files, idx);
-         queue_push(&cbdata.files, 0);
-         cbdata.idx = idx;
-         cbdata.hx = cbdata.lookat.elements[i];
-         cbdata.dirhash = cbdata.lookat.elements[i + 2];
-         cbdata.dirid = cbdata.lookat.elements[i + 3];
-         cbdata.lastdiridx = -1;
-         if (handle)
-           rpm_iterate_filelist(handle, iterflags, findfileconflicts2_cb, &cbdata);
-         cbdata.files.elements[fstart + 1] = cbdata.files.count;
-         cbdata.lookat.elements[i + 1] = fstart;
-         if (i + 4 >= cbdata.lookat.count || cbdata.lookat.elements[i + 4 + 1] != idx)
-           break;
-       }
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "file info fetching took %d ms\n", solv_timems(now));
-
-  cbdata.normap = solv_free(cbdata.normap);
-  cbdata.normapn = 0;
-
-  /* forth pass: for each hx we have, compare all matching files against all other matching files */
-  now = solv_timems(0);
-  solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool);
-  for (i = 0; i < cbdata.lookat.count - 4; i += 4)
-    {
-      Id hx = cbdata.lookat.elements[i];
-      Id pstart = cbdata.lookat.elements[i + 1];
-      Id dirid = cbdata.lookat.elements[i + 3];
-      Id pidx = cbdata.files.elements[pstart];
-      Id pend = cbdata.files.elements[pstart + 1];
-      if (cbdata.lookat.elements[i + 4] != hx)
-       continue;       /* no package left with that hx */
-      for (j = i + 4; j < cbdata.lookat.count && cbdata.lookat.elements[j] == hx && cbdata.lookat.elements[j + 3] == dirid; j += 4)
-       {
-         Id qstart = cbdata.lookat.elements[j + 1];
-         Id qidx = cbdata.files.elements[qstart];
-         Id qend = cbdata.files.elements[qstart + 1];
-         int ii, jj;
-         if (pidx >= cutoff && qidx >= cutoff)
-           continue;   /* no conflicts between packages with idx >= cutoff */
-          for (ii = pstart + 2; ii < pend; ii++)
-           for (jj = qstart + 2; jj < qend; jj++)
-             {
-               char *fsi = (char *)cbdata.filesspace + cbdata.files.elements[ii];
-               char *fsj = (char *)cbdata.filesspace + cbdata.files.elements[jj];
-               if (cbdata.aliases)
-                 {
-                   /* compare just the basenames, the dirs match because of the dirid */
-                   char *bsi = strrchr(fsi + 34, '/');
-                   char *bsj = strrchr(fsj + 34, '/');
-                   if (!bsi || !bsj)
-                     continue;
-                   if (strcmp(bsi, bsj))
-                     continue; /* different base names */
-                 }
-               else
-                 {
-                   if (strcmp(fsi + 34, fsj + 34))
-                     continue; /* different file names */
-                 }
-               if (!strcmp(fsi, fsj))
-                 continue;     /* file digests match, no conflict */
-               if (obsoleteusescolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0)
-                 continue;     /* colors do not conflict */
-               queue_push(conflicts, pool_str2id(pool, fsi + 34, 1));
-               queue_push(conflicts, pkgs->elements[pidx]);
-               queue_push(conflicts, pool_str2id(pool, fsi, 1));
-               queue_push(conflicts, pool_str2id(pool, fsj + 34, 1));
-               queue_push(conflicts, pkgs->elements[qidx]);
-               queue_push(conflicts, pool_str2id(pool, fsj, 1));
-             }
-       }
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "filespace size: %d K\n", cbdata.filesspacen / 1024);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "candidate check took %d ms\n", solv_timems(now));
-  cbdata.filesspace = solv_free(cbdata.filesspace);
-  cbdata.filesspacen = 0;
-  queue_free(&cbdata.lookat);
-  queue_free(&cbdata.files);
-  if (conflicts->count > 6)
-    solv_sort(conflicts->elements, conflicts->count / 6, 6 * sizeof(Id), conflicts_cmp, pool);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file conflicts\n", conflicts->count / 6);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "file conflict detection took %d ms\n", solv_timems(start));
-
-  return conflicts->count / 6;
-}
-
diff --git a/libsolv-0.6.15/ext/pool_fileconflicts.h b/libsolv-0.6.15/ext/pool_fileconflicts.h
deleted file mode 100644 (file)
index 13abdc7..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2009-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef POOL_FILECONFLICTS_H
-#define POOL_FILECONFLICTS_H
-
-#include "pool.h"
-
-extern int pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, int flags, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata);
-
-#define FINDFILECONFLICTS_USE_SOLVABLEFILELIST (1 << 0)
-#define FINDFILECONFLICTS_CHECK_DIRALIASING    (1 << 1)
-#define FINDFILECONFLICTS_USE_ROOTDIR          (1 << 2)
-
-#endif
diff --git a/libsolv-0.6.15/ext/pool_parserpmrichdep.c b/libsolv-0.6.15/ext/pool_parserpmrichdep.c
deleted file mode 100644 (file)
index d3e559e..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2015, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/* this is used by repo_rpmmd, repo_rpmdb, and repo_susetags */
-
-#include <stdio.h>
-
-#include "pool.h"
-#include "pool_parserpmrichdep.h"
-
-static struct RichOpComp {
-  const char *n;
-  int l;
-  Id fl;
-} RichOps[] = {
-  { "and",  3, REL_AND },
-  { "or",   2, REL_OR },
-  { "if",   2, REL_COND },
-  { "else", 4, REL_ELSE },
-  { NULL, 0, 0},
-};
-
-static Id
-parseRichDep(Pool *pool, const char **depp, Id chainfl)
-{
-  const char *p = *depp;
-  const char *n;
-  Id id, evr;
-  int fl, bl;
-  struct RichOpComp *op;
-
-  if (!chainfl && *p++ != '(')
-    return 0;
-  while (*p == ' ')
-    p++;
-  if (*p == ')')
-    return 0;
-  if (*p == '(')
-    {
-      id = parseRichDep(pool, &p, 0);
-      if (!id)
-       return 0;
-    }
-  else
-    {
-      n = p;
-      bl = 0;
-      while (*p && !(*p == ' ' || *p == ',' || (*p == ')' && bl-- <= 0)))
-       if (*p++ == '(')
-         bl++;
-      if (n == p)
-       return 0;
-      id = pool_strn2id(pool, n, p - n, 1);
-      while (*p == ' ')
-       p++;
-      if (*p)
-       {
-         fl = 0;
-         for (;; p++)
-           {
-             if (*p == '<')
-               fl |= REL_LT;
-             else if (*p == '=')
-               fl |= REL_EQ;
-             else if (*p == '>')
-               fl |= REL_GT;
-             else
-               break;
-           }
-         if (fl)
-           {
-             while (*p == ' ')
-               p++;
-             n = p;
-             bl = 0;
-             while (*p && !(*p == ' ' || *p == ',' || (*p == ')' && bl-- <= 0)))
-               if (*p++ == '(')
-                 bl++;
-             if (p - n > 2 && n[0] == '0' && n[1] == ':')
-               n += 2;         /* strip zero epoch */
-             if (n == p)
-               return 0;
-             id = pool_rel2id(pool, id, pool_strn2id(pool, n, p - n, 1), fl, 1);
-           }
-       }
-    }
-  while (*p == ' ')
-    p++;
-  if (!*p)
-    return 0;
-  if (*p == ')')
-    {
-      *depp = p + 1;
-      return id;
-    }
-  n = p;
-  while (*p && *p != ' ')
-    p++;
-  for (op = RichOps; op->n; op++)
-    if (p - n == op->l && !strncmp(n, op->n, op->l))
-      break;
-  fl = op->fl;
-  if (!fl)
-    return 0;
-  if (chainfl == REL_COND && fl == REL_ELSE)
-    chainfl = 0;
-  if (chainfl && fl != chainfl)
-    return 0;
-  evr = parseRichDep(pool, &p, fl);
-  if (!evr)
-    return 0;
-  *depp = p;
-  return pool_rel2id(pool, id, evr, fl, 1);
-}
-
-Id
-pool_parserpmrichdep(Pool *pool, const char *dep)
-{
-  Id id = parseRichDep(pool, &dep, 0);
-  if (id && *dep)
-    id = 0;
-  return id;
-}
-
diff --git a/libsolv-0.6.15/ext/pool_parserpmrichdep.h b/libsolv-0.6.15/ext/pool_parserpmrichdep.h
deleted file mode 100644 (file)
index 09dce2c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2014, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef POOL_PARSERPMRICHDEP_H
-#define POOL_PARSERPMRICHDEP_H
-
-#include "pool.h"
-
-extern Id pool_parserpmrichdep(Pool *pool, const char *dep);
-
-#endif
diff --git a/libsolv-0.6.15/ext/repo_appdata.c b/libsolv-0.6.15/ext/repo_appdata.c
deleted file mode 100644 (file)
index cbc42e4..0000000
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * repo_appdatadb.c
- *
- * Parses AppSteam Data files.
- * See http://people.freedesktop.org/~hughsient/appdata/
- *
- *
- * Copyright (c) 2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <dirent.h>
-#include <expat.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "repo_appdata.h"
-
-
-enum state {
-  STATE_START,
-  STATE_APPLICATION,
-  STATE_ID,
-  STATE_PKGNAME,
-  STATE_LICENCE,
-  STATE_NAME,
-  STATE_SUMMARY,
-  STATE_DESCRIPTION,
-  STATE_P,
-  STATE_UL,
-  STATE_UL_LI,
-  STATE_OL,
-  STATE_OL_LI,
-  STATE_URL,
-  STATE_GROUP,
-  STATE_KEYWORDS,
-  STATE_KEYWORD,
-  STATE_EXTENDS,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
-  { STATE_START,       "applications",  STATE_START,         0 },
-  { STATE_START,       "components",    STATE_START,         0 },
-  { STATE_START,       "application",   STATE_APPLICATION,   0 },
-  { STATE_START,       "component",     STATE_APPLICATION,   0 },
-  { STATE_APPLICATION, "id",            STATE_ID,            1 },
-  { STATE_APPLICATION, "pkgname",       STATE_PKGNAME,       1 },
-  { STATE_APPLICATION, "product_license", STATE_LICENCE,     1 },
-  { STATE_APPLICATION, "name",          STATE_NAME,          1 },
-  { STATE_APPLICATION, "summary",       STATE_SUMMARY,       1 },
-  { STATE_APPLICATION, "description",   STATE_DESCRIPTION,   0 },
-  { STATE_APPLICATION, "url",           STATE_URL,           1 },
-  { STATE_APPLICATION, "project_group", STATE_GROUP,         1 },
-  { STATE_APPLICATION, "keywords",      STATE_KEYWORDS,      0 },
-  { STATE_APPLICATION, "extends",       STATE_EXTENDS,       1 },
-  { STATE_DESCRIPTION, "p",             STATE_P,             1 },
-  { STATE_DESCRIPTION, "ul",            STATE_UL,            0 },
-  { STATE_DESCRIPTION, "ol",            STATE_OL,            0 },
-  { STATE_UL,          "li",            STATE_UL_LI,         1 },
-  { STATE_OL,          "li",            STATE_OL_LI,         1 },
-  { STATE_KEYWORDS,    "keyword",       STATE_KEYWORD,       1 },
-  { NUMSTATES }
-};
-
-struct parsedata {
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-
-  Solvable *solvable;
-  Id handle;
-
-  char *description;
-  int licnt;
-  int skip_depth;
-  int flags;
-  char *desktop_file;
-  int havesummary;
-  const char *filename;
-  Queue *owners;
-};
-
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    if (!strcmp(*atts, txt))
-      return atts[1];
-  return 0;
-}
-
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-  const char *type;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  if (!pd->skip_depth && find_attr("xml:lang", atts))
-    pd->skip_depth = pd->depth;
-  if (pd->skip_depth)
-    {
-      pd->docontent = 0;
-      return;
-    }
-
-  switch(pd->state)
-    {
-    case STATE_APPLICATION:
-      s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-      pd->handle = s - pool->solvables;
-      pd->havesummary = 0;
-      type = find_attr("type", atts);
-      if (!type || !*type)
-        type = "desktop";
-      repodata_set_poolstr(pd->data, pd->handle, SOLVABLE_CATEGORY, type);
-      break;
-    case STATE_DESCRIPTION:
-      pd->description = solv_free(pd->description);
-      break;
-    case STATE_OL:
-    case STATE_UL:
-      pd->licnt = 0;
-      break;
-    default:
-      break;
-    }
-}
-
-/* replace whitespace with one space/newline */
-/* also strip starting/ending whitespace */
-static void
-wsstrip(struct parsedata *pd)
-{
-  int i, j;
-  int ws = 0;
-  for (i = j = 0; pd->content[i]; i++)
-    {
-      if (pd->content[i] == ' ' || pd->content[i] == '\t' || pd->content[i] == '\n')
-       {
-         ws |= pd->content[i] == '\n' ? 2 : 1;
-         continue;
-       }
-      if (ws && j)
-       pd->content[j++] = (ws & 2) ? '\n' : ' ';
-      ws = 0;
-      pd->content[j++] = pd->content[i];
-    }
-  pd->content[j] = 0;
-  pd->lcontent = j;
-}
-
-/* indent all lines */
-static void
-indent(struct parsedata *pd, int il)
-{
-  int i, l;
-  for (l = 0; pd->content[l]; )
-    {
-      if (pd->content[l] == '\n')
-       {
-         l++;
-         continue;
-       }
-      if (pd->lcontent + il + 1 > pd->acontent)
-       {
-         pd->acontent = pd->lcontent + il + 256;
-         pd->content = realloc(pd->content, pd->acontent);
-       }
-      memmove(pd->content + l + il, pd->content + l, pd->lcontent - l + 1);
-      for (i = 0; i < il; i++)
-       pd->content[l + i] = ' ';
-      pd->lcontent += il;
-      while (pd->content[l] && pd->content[l] != '\n')
-       l++;
-    }
-}
-
-static void
-add_missing_tags_from_desktop_file(struct parsedata *pd, Solvable *s, const char *desktop_file)
-{
-  Pool *pool = pd->pool;
-  FILE *fp;
-  const char *filepath;
-  char buf[1024];
-  char *p, *p2, *p3;
-  int inde = 0;
-
-  filepath = pool_tmpjoin(pool, "/usr/share/applications/", desktop_file, 0);
-  if (pd->flags & REPO_USE_ROOTDIR)
-    filepath = pool_prepend_rootdir_tmp(pool, filepath);
-  if (!(fp = fopen(filepath, "r")))
-    return;
-  while (fgets(buf, sizeof(buf), fp) > 0)
-    {
-      int c, l = strlen(buf);
-      if (!l)
-       continue;
-      if (buf[l - 1] != '\n')
-       {
-         /* ignore overlong lines */
-         while ((c = getc(fp)) != EOF)
-           if (c == '\n')
-             break;
-         if (c == EOF)
-           break;
-         continue;
-       }
-      buf[--l] = 0;
-      while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
-        buf[--l] = 0;
-      p = buf;
-      while (*p == ' ' || *p == '\t')
-       p++;
-      if (!*p || *p == '#')
-       continue;
-      if (*p == '[')
-       inde = 0;
-      if (!strcmp(p, "[Desktop Entry]"))
-       {
-         inde = 1;
-         continue;
-       }
-      if (!inde)
-       continue;
-      p2 = strchr(p, '=');
-      if (!p2 || p2 == p)
-       continue;
-      *p2 = 0;
-      for (p3 = p2 - 1; *p3 == ' ' || *p3 == '\t'; p3--)
-       *p3 = 0;
-      p2++;
-      while (*p2 == ' ' || *p2 == '\t')
-       p2++;
-      if (!*p2)
-       continue;
-      if (!s->name && !strcmp(p, "Name"))
-       s->name = pool_str2id(pool, pool_tmpjoin(pool, "application:", p2, 0), 1);
-      else if (!pd->havesummary && !strcmp(p, "Comment"))
-       {
-         pd->havesummary = 1;
-         repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, p2);
-       }
-      else
-       continue;
-      if (s->name && pd->havesummary)
-       break;  /* our work is done */
-    }
-  fclose(fp);
-}
-
-static char *
-guess_filename_from_id(Pool *pool, const char *id)
-{
-  int l = strlen(id);
-  char *r = pool_tmpjoin(pool, id, ".metainfo.xml", 0);
-  if (l > 8 && !strcmp(".desktop", id + l - 8))
-    strcpy(r + l - 8, ".appdata.xml");
-  else if (l > 4 && !strcmp(".ttf", id + l - 4))
-    strcpy(r + l - 4, ".metainfo.xml");
-  else if (l > 4 && !strcmp(".otf", id + l - 4))
-    strcpy(r + l - 4, ".metainfo.xml");
-  else if (l > 4 && !strcmp(".xml", id + l - 4))
-    strcpy(r + l - 4, ".metainfo.xml");
-  else if (l > 3 && !strcmp(".db", id + l - 3))
-    strcpy(r + l - 3, ".metainfo.xml");
-  else
-    return 0;
-  return r;
-}
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  Id id;
-
-#if 0
-  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  if (pd->skip_depth && pd->depth + 1 >= pd->skip_depth)
-    {
-      if (pd->depth + 1 == pd->skip_depth)
-       pd->skip_depth = 0;
-      pd->state = pd->sbtab[pd->state];
-      pd->docontent = 0;
-      return;
-    }
-  pd->skip_depth = 0;
-
-  switch (pd->state)
-    {
-    case STATE_APPLICATION:
-      if (!s->arch)
-       s->arch = ARCH_NOARCH;
-      if (!s->evr)
-       s->evr = ID_EMPTY;
-      if ((!s->name || !pd->havesummary) && (pd->flags & APPDATA_CHECK_DESKTOP_FILE) != 0 && pd->desktop_file)
-       add_missing_tags_from_desktop_file(pd, s, pd->desktop_file);
-      if (!s->name && pd->desktop_file)
-       {
-          char *name = pool_tmpjoin(pool, "application:", pd->desktop_file, 0);
-         int l = strlen(name);
-         if (l > 8 && !strcmp(".desktop", name + l - 8))
-           l -= 8;
-         s->name = pool_strn2id(pool, name, l, 1);
-       }
-      if (!s->requires && pd->owners)
-       {
-         int i;
-         Id id;
-         for (i = 0; i < pd->owners->count; i++)
-           {
-             Solvable *os = pd->pool->solvables + pd->owners->elements[i];
-             s->requires = repo_addid_dep(pd->repo, s->requires, os->name, 0);
-             id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", pool_id2str(pd->pool, os->name), ")"), 1);
-             s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
-           }
-       }
-      if (!s->requires && (pd->desktop_file || pd->filename))
-       {
-         /* add appdata() link requires/provides */
-         const char *filename = pd->filename;
-         if (!filename)
-           filename = guess_filename_from_id(pool, pd->desktop_file);
-         if (filename)
-           {
-             filename = pool_tmpjoin(pool, "application-appdata(", filename, ")");
-             s->requires = repo_addid_dep(pd->repo, s->requires, pool_str2id(pd->pool, filename + 12, 1), 0);
-             s->provides = repo_addid_dep(pd->repo, s->provides, pool_str2id(pd->pool, filename, 1), 0);
-           }
-       }
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
-      pd->solvable = 0;
-      pd->desktop_file = solv_free(pd->desktop_file);
-      break;
-    case STATE_ID:
-      pd->desktop_file = solv_strdup(pd->content);
-      break;
-    case STATE_NAME:
-      s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", pd->content, 0), 1);
-      break;
-    case STATE_LICENCE:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, pd->content);
-      break;
-    case STATE_SUMMARY:
-      pd->havesummary = 1;
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
-      break;
-    case STATE_URL:
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, pd->content);
-      break;
-    case STATE_GROUP:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, pd->content);
-      break;
-    case STATE_EXTENDS:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, pd->content);
-      break;
-    case STATE_DESCRIPTION:
-      if (pd->description)
-       {
-         /* strip trailing newlines */
-         int l = strlen(pd->description);
-         while (l && pd->description[l - 1] == '\n')
-           pd->description[--l] = 0;
-          repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, pd->description);
-       }
-      break;
-    case STATE_P:
-      wsstrip(pd);
-      pd->description = solv_dupappend(pd->description, pd->content, "\n\n");
-      break;
-    case STATE_UL_LI:
-      wsstrip(pd);
-      indent(pd, 4);
-      pd->content[2] = '-';
-      pd->description = solv_dupappend(pd->description, pd->content, "\n");
-      break;
-    case STATE_OL_LI:
-      wsstrip(pd);
-      indent(pd, 4);
-      if (++pd->licnt >= 10)
-       pd->content[0] = '0' + (pd->licnt / 10) % 10;
-      pd->content[1] = '0' + pd->licnt  % 10;
-      pd->content[2] = '.';
-      pd->description = solv_dupappend(pd->description, pd->content, "\n");
-      break;
-    case STATE_UL:
-    case STATE_OL:
-      pd->description = solv_dupappend(pd->description, "\n", 0);
-      break;
-    case STATE_PKGNAME:
-      id = pool_str2id(pd->pool, pd->content, 1);
-      s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
-      id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", pd->content, ")"), 1);
-      s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
-      break;
-    case STATE_KEYWORD:
-      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, pd->content);
-      break;
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-  fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->acontent = l + 256;
-      pd->content = realloc(pd->content, pd->acontent);
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-static int
-repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue *owners)
-{
-  Pool *pool = repo->pool;
-  struct parsedata pd;
-  struct stateswitch *sw;
-  Repodata *data;
-  char buf[BUFF_SIZE];
-  int i, l;
-  int ret = 0;
-
-  data = repo_add_repodata(repo, flags);
-  memset(&pd, 0, sizeof(pd));
-  pd.repo = repo;
-  pd.pool = repo->pool;
-  pd.data = data;
-  pd.flags = flags;
-  pd.filename = filename;
-  pd.owners = owners;
-
-  pd.content = malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  XML_Parser parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_error(pool, -1, "repo_appdata: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         if (pd.solvable)
-           {
-             repo_free_solvable(repo, pd.solvable - pd.pool->solvables, 1);
-             pd.solvable = 0;
-           }
-         ret = -1;
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-
-  solv_free(pd.content);
-  solv_free(pd.desktop_file);
-  solv_free(pd.description);
-  return ret;
-}
-
-int
-repo_add_appdata(Repo *repo, FILE *fp, int flags)
-{
-  return repo_add_appdata_fn(repo, fp, flags, 0, 0);
-}
-
-static void
-search_uninternalized_filelist(Repo *repo, const char *dir, Queue *res)
-{
-  Pool *pool = repo->pool;
-  Id rdid, p;
-  Id iter, did, idid;
-
-  for (rdid = 1; rdid < repo->nrepodata; rdid++)
-    {
-      Repodata *data = repo_id2repodata(repo, rdid);
-      if (!data)
-       continue;
-      if (data->state == REPODATA_STUB)
-       continue;
-      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
-       continue;
-      did = repodata_str2dir(data, dir, 0);
-      if (!did)
-       continue;
-      for (p = data->start; p < data->end; p++)
-       {
-         if (p >= pool->nsolvables)
-           continue;
-         if (pool->solvables[p].repo != repo)
-           continue;
-         iter = 0;
-         for (;;)
-           {
-             const char *str;
-             int l;
-             Id id;
-             idid = did;
-             str = repodata_lookup_dirstrarray_uninternalized(data, p, SOLVABLE_FILELIST, &idid, &iter);
-             if (!iter)
-               break;
-             l = strlen(str);
-             if (l > 12 && strncmp(str + l - 12, ".appdata.xml", 12))
-               id = pool_str2id(pool, str, 1);
-             else if (l > 13 && strncmp(str + l - 13, ".metainfo.xml", 13))
-               id = pool_str2id(pool, str, 1);
-             else
-               continue;
-             queue_push2(res, p, id);
-           }
-       }
-    }
-}
-
-/* add all files ending in .appdata.xml */
-int
-repo_add_appdata_dir(Repo *repo, const char *appdatadir, int flags)
-{
-  DIR *dir;
-  char *dirpath;
-  Repodata *data;
-  Queue flq;
-  Queue oq;
-
-  queue_init(&flq);
-  queue_init(&oq);
-  if (flags & APPDATA_SEARCH_UNINTERNALIZED_FILELIST)
-    search_uninternalized_filelist(repo, appdatadir, &flq);
-  data = repo_add_repodata(repo, flags);
-  if (flags & REPO_USE_ROOTDIR)
-    dirpath = pool_prepend_rootdir(repo->pool, appdatadir);
-  else
-    dirpath = solv_strdup(appdatadir);
-  if ((dir = opendir(dirpath)) != 0)
-    {
-      struct dirent *entry;
-      while ((entry = readdir(dir)))
-       {
-         const char *n;
-         FILE *fp;
-         int len = strlen(entry->d_name);
-         if (entry->d_name[0] == '.')
-           continue;
-         if (!(len > 12 && !strcmp(entry->d_name + len - 12, ".appdata.xml")) &&
-             !(len > 13 && !strcmp(entry->d_name + len - 13, ".metainfo.xml")))
-           continue;
-          n = pool_tmpjoin(repo->pool, dirpath, "/", entry->d_name);
-         fp = fopen(n, "r");
-         if (!fp)
-           {
-             pool_error(repo->pool, 0, "%s: %s", n, strerror(errno));
-             continue;
-           }
-         if (flags & APPDATA_SEARCH_UNINTERNALIZED_FILELIST)
-           {
-             Id id = pool_str2id(repo->pool, entry->d_name, 0);
-             queue_empty(&oq);
-             if (id)
-               {
-                 int i;
-                 for (i = 0; i < flq.count; i += 2)
-                   if (flq.elements[i + 1] == id)
-                     queue_push(&oq, flq.elements[i]);
-               }
-           }
-         repo_add_appdata_fn(repo, fp, flags | REPO_NO_INTERNALIZE | REPO_REUSE_REPODATA | APPDATA_CHECK_DESKTOP_FILE, entry->d_name, oq.count ? &oq : 0);
-         fclose(fp);
-       }
-      closedir(dir);
-    }
-  solv_free(dirpath);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  queue_free(&oq);
-  queue_free(&flq);
-  return 0;
-}
diff --git a/libsolv-0.6.15/ext/repo_appdata.h b/libsolv-0.6.15/ext/repo_appdata.h
deleted file mode 100644 (file)
index db5f2cf..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (c) 2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-int repo_add_appdata(Repo *repo, FILE *fp, int flags);
-int repo_add_appdata_dir(Repo *repo, const char *appdatadir, int flags);
-
-#define APPDATA_SEARCH_UNINTERNALIZED_FILELIST         (1 << 8)
-#define APPDATA_CHECK_DESKTOP_FILE     (1 << 30)       /* internal */
diff --git a/libsolv-0.6.15/ext/repo_arch.c b/libsolv-0.6.15/ext/repo_arch.c
deleted file mode 100644 (file)
index a0c45ce..0000000
+++ /dev/null
@@ -1,859 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "chksum.h"
-#include "solv_xfopen.h"
-#include "repo_arch.h"
-
-static long long parsenum(unsigned char *p, int cnt)
-{
-  long long x = 0;
-  if (!cnt)
-    return -1;
-  if (*p & 0x80)
-    {
-      /* binary format */
-      x = *p & 0x40 ? (-1 << 8 | *p)  : (*p ^ 0x80);
-      while (--cnt > 0)
-       x = (x << 8) | *p++;
-      return x;
-    }
-  while (cnt > 0 && (*p == ' ' || *p == '\t'))
-    cnt--, p++;
-  if (*p == '-')
-    return -1;
-  for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
-    x = (x << 3) | (*p - '0');
-  return x;
-}
-
-static int readblock(FILE *fp, unsigned char *blk)
-{
-  int r, l = 0;
-  while (l < 512)
-    {
-      r = fread(blk + l, 1, 512 - l, fp);
-      if (r <= 0)
-       return -1;
-      l += r;
-    }
-  return 0;
-}
-
-struct tarhead {
-  FILE *fp;
-  unsigned char blk[512];
-  int type;
-  long long length;
-  char *path;
-  int eof;
-  int ispax;
-  int off;
-  int end;
-};
-
-static char *getsentry(struct tarhead *th, char *s, int size)
-{
-  char *os = s;
-  if (th->eof || size <= 1)
-    return 0;
-  size--;      /* terminating 0 */
-  for (;;)
-    {
-      int i;
-      for (i = th->off; i < th->end; i++)
-       {
-         *s++ = th->blk[i];
-         size--;
-         if (!size || th->blk[i] == '\n')
-           {
-             th->off = i + 1;
-             *s = 0;
-             return os;
-           }
-       }
-      th->off = i;
-      if (!th->path)
-       {
-         /* fake entry */
-         th->end = fread(th->blk, 1, 512, th->fp);
-         if (th->end <= 0)
-           {
-             th->eof = 1;
-             return 0;
-           }
-         th->off = 0;
-         continue;
-       }
-      if (th->length <= 0)
-       return 0;
-      if (readblock(th->fp, th->blk))
-       {
-         th->eof = 1;
-         return 0;
-       }
-      th->off = 0;
-      th->end = th->length > 512 ? 512 : th->length;
-      th->length -= th->end;
-    }
-}
-
-static void skipentry(struct tarhead *th)
-{
-  for (; th->length > 0; th->length -= 512)
-    {
-      if (readblock(th->fp, th->blk))
-       {
-         th->eof = 1;
-         th->length = 0;
-         return;
-       }
-    }
-  th->length = 0;
-  th->off = th->end = 0;
-}
-
-static void inittarhead(struct tarhead *th, FILE *fp)
-{
-  memset(th, 0, sizeof(*th));
-  th->fp = fp;
-}
-
-static void freetarhead(struct tarhead *th)
-{
-  solv_free(th->path);
-}
-
-static int gettarhead(struct tarhead *th)
-{
-  int l, type;
-  long long length;
-
-  th->path = solv_free(th->path);
-  th->ispax = 0;
-  th->type = 0;
-  th->length = 0;
-  th->off = 0;
-  th->end = 0;
-  if (th->eof)
-    return 0;
-  for (;;)
-    {
-      int r = readblock(th->fp, th->blk);
-      if (r)
-       {
-         if (feof(th->fp))
-           {
-             th->eof = 1;
-             return 0;
-           }
-         return -1;
-       }
-      if (th->blk[0] == 0)
-       {
-          th->eof = 1;
-         return 0;
-       }
-      length = parsenum(th->blk + 124, 12);
-      if (length < 0)
-       return -1;
-      type = 0;
-      switch (th->blk[156])
-       {
-       case 'S': case '0':
-         type = 1;     /* file */
-         break;
-       case '1':
-         /* hard link, special length magic... */
-         if (!th->ispax)
-           length = 0;
-         break;
-       case '5':
-         type = 2;     /* dir */
-         break;
-       case '2': case '3': case '4': case '6':
-         length = 0;
-         break;
-       case 'X': case 'x': case 'L':
-         {
-           char *data, *pp;
-           if (length < 1 || length >= 1024 * 1024)
-             return -1;
-           data = pp = solv_malloc(length + 512);
-           for (l = length; l > 0; l -= 512, pp += 512)
-             if (readblock(th->fp, (unsigned char *)pp))
-               {
-                 solv_free(data);
-                 return -1;
-               }
-           data[length] = 0;
-           type = 3;           /* extension */
-           if (th->blk[156] == 'L')
-             {
-               solv_free(th->path);
-               th->path = data;
-               length = 0;
-               break;
-             }
-           pp = data;
-           while (length > 0)
-             {
-               int ll = 0;
-               for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
-                 ll = ll * 10 + (pp[l] - '0');
-               if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
-                 {
-                   solv_free(data);
-                   return -1;
-                 }
-               length -= ll;
-               pp += l + 1;
-               ll -= l + 1;
-               pp[ll - 1] = 0;
-               if (!strncmp(pp, "path=", 5))
-                 {
-                   solv_free(th->path);
-                   th->path = solv_strdup(pp + 5);
-                 }
-               pp += ll;
-             }
-           solv_free(data);
-           th->ispax = 1;
-           length = 0;
-           break;
-         }
-       default:
-         type = 3;     /* extension */
-         break;
-       }
-      if ((type == 1 || type == 2) && !th->path)
-       {
-         char path[157];
-         memcpy(path, th->blk, 156);
-         path[156] = 0;
-         if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
-           {
-             /* POSIX ustar with prefix */
-             char prefix[156];
-             memcpy(prefix, th->blk + 345, 155);
-             prefix[155] = 0;
-             l = strlen(prefix);
-             if (l && prefix[l - 1] == '/')
-               prefix[l - 1] = 0;
-             th->path = solv_dupjoin(prefix, "/", path);
-           }
-         else
-           th->path = solv_dupjoin(path, 0, 0);
-       }
-      if (type == 1 || type == 2)
-       {
-         l = strlen(th->path);
-         if (l && th->path[l - 1] == '/')
-           {
-             if (l > 1)
-               th->path[l - 1] = 0;
-             type = 2;
-           }
-       }
-      if (type != 3)
-       break;
-      while (length > 0)
-       {
-         r = readblock(th->fp, th->blk);
-         if (r)
-           return r;
-         length -= 512;
-       }
-    }
-  th->type = type;
-  th->length = length;
-  return 1;
-}
-
-static Offset
-adddep(Repo *repo, Offset olddeps, char *line)
-{
-  Pool *pool = repo->pool;
-  char *p;
-  Id id;
-
-  while (*line == ' ' || *line == '\t')
-    line++;
-  p = line;
-  while (*p && *p != ' ' && *p != '\t' && *p != '<' && *p != '=' && *p != '>')
-    p++;
-  id = pool_strn2id(pool, line, p - line, 1);
-  while (*p == ' ' || *p == '\t')
-    p++;
-  if (*p == '<' || *p == '=' || *p == '>')
-    {
-      int flags = 0;
-      for (;; p++)
-       {
-         if (*p == '<')
-           flags |= REL_LT;
-         else if (*p == '=')
-           flags |= REL_EQ;
-         else if (*p == '>')
-           flags |= REL_GT;
-         else
-           break;
-       }
-      while (*p == ' ' || *p == '\t')
-        p++;
-      line = p;
-      while (*p && *p != ' ' && *p != '\t')
-       p++;
-      id = pool_rel2id(pool, id, pool_strn2id(pool, line, p - line, 1), flags, 1);
-    }
-  return repo_addid_dep(repo, olddeps, id, 0);
-}
-
-Id
-repo_add_arch_pkg(Repo *repo, const char *fn, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  FILE *fp;
-  struct tarhead th;
-  char line[4096];
-  int ignoreline;
-  Solvable *s;
-  int l, fd;
-  struct stat stb;
-  Chksum *pkgidchk = 0;
-
-  data = repo_add_repodata(repo, flags);
-  if ((fd = open(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, fn) : fn, O_RDONLY, 0)) < 0)
-    {
-      pool_error(pool, -1, "%s: %s", fn, strerror(errno));
-      return 0;
-    }
-  if (fstat(fd, &stb))
-    {
-      pool_error(pool, -1, "%s: fstat: %s", fn, strerror(errno));
-      close(fd);
-      return 0;
-    }
-  if (!(fp = solv_xfopen_fd(fn, fd, "r")))
-    {
-      pool_error(pool, -1, "%s: fdopen failed", fn);
-      close(fd);
-      return 0;
-    }
-  s = 0;
-  inittarhead(&th, fp);
-  while (gettarhead(&th) > 0)
-    {
-      if (th.type != 1 || strcmp(th.path, ".PKGINFO") != 0)
-       {
-          skipentry(&th);
-         continue;
-       }
-      ignoreline = 0;
-      s = pool_id2solvable(pool, repo_add_solvable(repo));
-      if (flags & ARCH_ADD_WITH_PKGID)
-       pkgidchk = solv_chksum_create(REPOKEY_TYPE_MD5);
-      while (getsentry(&th, line, sizeof(line)))
-       {
-         l = strlen(line);
-         if (l == 0)
-           continue;
-         if (pkgidchk)
-           solv_chksum_add(pkgidchk, line, l);
-         if (line[l - 1] != '\n')
-           {
-             ignoreline = 1;
-             continue;
-           }
-         if (ignoreline)
-           {
-             ignoreline = 0;
-             continue;
-           }
-         line[--l] = 0;
-         if (l == 0 || line[0] == '#')
-           continue;
-         if (!strncmp(line, "pkgname = ", 10))
-           s->name = pool_str2id(pool, line + 10, 1);
-         else if (!strncmp(line, "pkgver = ", 9))
-           s->evr = pool_str2id(pool, line + 9, 1);
-         else if (!strncmp(line, "pkgdesc = ", 10))
-           {
-             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 10);
-             repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line + 10);
-           }
-         else if (!strncmp(line, "url = ", 6))
-           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line + 6);
-         else if (!strncmp(line, "builddate = ", 12))
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line + 12, 0, 10));
-         else if (!strncmp(line, "packager = ", 11))
-           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line + 11);
-         else if (!strncmp(line, "size = ", 7))
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line + 7, 0, 10));
-         else if (!strncmp(line, "arch = ", 7))
-           s->arch = pool_str2id(pool, line + 7, 1);
-         else if (!strncmp(line, "license = ", 10))
-           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
-         else if (!strncmp(line, "replaces = ", 11))
-           s->obsoletes = adddep(repo, s->obsoletes, line + 11);
-         else if (!strncmp(line, "group = ", 8))
-           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line + 8);
-         else if (!strncmp(line, "depend = ", 9))
-           s->requires = adddep(repo, s->requires, line + 9);
-         else if (!strncmp(line, "optdepend = ", 12))
-           {
-             char *p = strchr(line, ':');
-             if (p)
-               *p = 0;
-             s->suggests = adddep(repo, s->suggests, line + 12);
-           }
-         else if (!strncmp(line, "conflict = ", 11))
-           s->conflicts = adddep(repo, s->conflicts, line + 11);
-         else if (!strncmp(line, "provides = ", 11))
-           s->provides = adddep(repo, s->provides, line + 11);
-       }
-      break;
-    }
-  freetarhead(&th);
-  fclose(fp);
-  if (!s)
-    {
-      pool_error(pool, -1, "%s: not an arch package", fn);
-      if (pkgidchk)
-       solv_chksum_free(pkgidchk, 0);
-      return 0;
-    }
-  if (s && !s->name)
-    {
-      pool_error(pool, -1, "%s: package has no name", fn);
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      s = 0;
-    }
-  if (s)
-    {
-      if (!s->arch)
-       s->arch = ARCH_ANY;
-      if (!s->evr)
-       s->evr = ID_EMPTY;
-      s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-      if (!(flags & REPO_NO_LOCATION))
-       repodata_set_location(data, s - pool->solvables, 0, 0, fn);
-      if (S_ISREG(stb.st_mode))
-        repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
-      if (pkgidchk)
-       {
-         unsigned char pkgid[16];
-         solv_chksum_free(pkgidchk, pkgid);
-         repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
-         pkgidchk = 0;
-       }
-    }
-  if (pkgidchk)
-    solv_chksum_free(pkgidchk, 0);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return s ? s - pool->solvables : 0;
-}
-
-static char *getsentrynl(struct tarhead *th, char *s, int size)
-{
-  int l;
-  if (!getsentry(th, s, size))
-    {
-      *s = 0;  /* eof */
-      return 0;
-    }
-  l = strlen(s);
-  if (!l)
-    return 0;
-  if (l && s[l - 1] == '\n')
-    {
-      s[l - 1] = 0;
-      return s;
-    }
-  while (getsentry(th, s, size))
-    {
-      l = strlen(s);
-      if (!l || s[l - 1] == '\n')
-       return 0;
-    }
-  *s = 0;      /* eof */
-  return 0;
-}
-
-static Hashtable
-joinhash_init(Repo *repo, Hashval *hmp)
-{
-  Hashval hm = mkmask(repo->nsolvables);
-  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
-  Hashval h, hh;
-  Solvable *s;
-  int i;
-
-  FOR_REPO_SOLVABLES(repo, i, s)
-    {
-      hh = HASHCHAIN_START;
-      h = s->name & hm;
-      while (ht[h])
-        h = HASHCHAIN_NEXT(h, hh, hm);
-      ht[h] = i;
-    }
-  *hmp = hm;
-  return ht;
-}
-
-static Solvable *
-joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn)
-{
-  const char *p;
-  Id name, evr;
-  Hashval h, hh;
-
-  if ((p = strrchr(fn, '/')) != 0)
-    fn = p + 1;
-  /* here we assume that the dirname is name-evr */
-  if (!*fn)
-    return 0;
-  for (p = fn + strlen(fn) - 1; p > fn; p--)
-    {
-      while (p > fn && *p != '-')
-       p--;
-      if (p == fn)
-       return 0;
-      name = pool_strn2id(repo->pool, fn, p - fn, 0);
-      if (!name)
-       continue;
-      evr = pool_str2id(repo->pool, p + 1, 0);
-      if (!evr)
-       continue;
-      /* found valid name/evr combination, check hash */
-      hh = HASHCHAIN_START;
-      h = name & hm;
-      while (ht[h])
-       {
-         Solvable *s = repo->pool->solvables + ht[h];
-         if (s->name == name && s->evr == evr)
-           return s;
-         h = HASHCHAIN_NEXT(h, hh, hm);
-       }
-    }
-  return 0;
-}
-
-static void
-adddata(Repodata *data, Solvable *s, struct tarhead *th)
-{
-  Repo *repo = data->repo;
-  Pool *pool = repo->pool;
-  char line[4096];
-  int l;
-  int havesha256 = 0;
-
-  while (getsentry(th, line, sizeof(line)))
-    {
-      l = strlen(line);
-      if (l == 0 || line[l - 1] != '\n')
-       continue;
-      line[--l] = 0;
-      if (l <= 2 || line[0] != '%' || line[l - 1] != '%')
-       continue;
-      if (!strcmp(line, "%FILENAME%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_set_location(data, s - pool->solvables, 0, 0, line);
-       }
-      else if (!strcmp(line, "%NAME%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           s->name = pool_str2id(pool, line, 1);
-       }
-      else if (!strcmp(line, "%VERSION%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           s->evr = pool_str2id(pool, line, 1);
-       }
-      else if (!strcmp(line, "%DESC%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           {
-             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line);
-             repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line);
-           }
-       }
-      else if (!strcmp(line, "%GROUPS%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line);
-       }
-      else if (!strcmp(line, "%CSIZE%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(line, 0, 10));
-       }
-      else if (!strcmp(line, "%ISIZE%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line, 0, 10));
-       }
-      else if (!strcmp(line, "%MD5SUM%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)) && !havesha256)
-           repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_MD5, line);
-       }
-      else if (!strcmp(line, "%SHA256SUM%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           {
-             repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, line);
-             havesha256 = 1;
-           }
-       }
-      else if (!strcmp(line, "%URL%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line);
-       }
-      else if (!strcmp(line, "%LICENSE%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line);
-       }
-      else if (!strcmp(line, "%ARCH%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           s->arch = pool_str2id(pool, line, 1);
-       }
-      else if (!strcmp(line, "%BUILDDATE%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line, 0, 10));
-       }
-      else if (!strcmp(line, "%PACKAGER%"))
-       {
-         if (getsentrynl(th, line, sizeof(line)))
-           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line);
-       }
-      else if (!strcmp(line, "%REPLACES%"))
-       {
-         while (getsentrynl(th, line, sizeof(line)) && *line)
-           s->obsoletes = adddep(repo, s->obsoletes, line);
-       }
-      else if (!strcmp(line, "%DEPENDS%"))
-       {
-         while (getsentrynl(th, line, sizeof(line)) && *line)
-           s->requires = adddep(repo, s->requires, line);
-       }
-      else if (!strcmp(line, "%CONFLICTS%"))
-       {
-         while (getsentrynl(th, line, sizeof(line)) && *line)
-           s->conflicts = adddep(repo, s->conflicts, line);
-       }
-      else if (!strcmp(line, "%PROVIDES%"))
-       {
-         while (getsentrynl(th, line, sizeof(line)) && *line)
-           s->provides = adddep(repo, s->provides, line);
-       }
-      else if (!strcmp(line, "%OPTDEPENDS%"))
-       {
-         while (getsentrynl(th, line, sizeof(line)) && *line)
-           {
-             char *p = strchr(line, ':');
-             if (p && p > line)
-               *p = 0;
-             s->suggests = adddep(repo, s->suggests, line);
-           }
-       }
-      else if (!strcmp(line, "%FILES%"))
-       {
-         while (getsentrynl(th, line, sizeof(line)) && *line)
-           {
-             char *p;
-             Id id;
-             l = strlen(line);
-             if (l > 1 && line[l - 1] == '/')
-               line[--l] = 0;  /* remove trailing slashes */
-             if ((p = strrchr(line , '/')) != 0)
-               {
-                 *p++ = 0;
-                 if (line[0] != '/')   /* anchor */
-                   {
-                     char tmp = *p;
-                     memmove(line + 1, line, p - 1 - line);
-                     *line = '/';
-                     *p = 0;
-                     id = repodata_str2dir(data, line, 1);
-                     *p = tmp;
-                   }
-                 else
-                   id = repodata_str2dir(data, line, 1);
-               }
-             else
-               {
-                 p = line;
-                 id = 0;
-               }
-             if (!id)
-               id = repodata_str2dir(data, "/", 1);
-             repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, id, p);
-           }
-       }
-      while (*line)
-       getsentrynl(th, line, sizeof(line));
-    }
-}
-
-static void
-finishsolvable(Repo *repo, Solvable *s)
-{
-  Pool *pool = repo->pool;
-  if (!s)
-    return;
-  if (!s->name)
-    {
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      return;
-    }
-  if (!s->arch)
-    s->arch = ARCH_ANY;
-  if (!s->evr)
-    s->evr = ID_EMPTY;
-  s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-}
-
-int
-repo_add_arch_repo(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  struct tarhead th;
-  char *lastdn = 0;
-  int lastdnlen = 0;
-  Solvable *s = 0;
-  Hashtable joinhash = 0;
-  Hashval joinhashmask = 0;
-
-  data = repo_add_repodata(repo, flags);
-
-  if (flags & REPO_EXTEND_SOLVABLES)
-    joinhash = joinhash_init(repo, &joinhashmask);
-
-  inittarhead(&th, fp);
-  while (gettarhead(&th) > 0)
-    {
-      char *bn;
-      if (th.type != 1)
-       {
-          skipentry(&th);
-         continue;
-       }
-      bn = strrchr(th.path, '/');
-      if (!bn || (strcmp(bn + 1, "desc") != 0 && strcmp(bn + 1, "depends") != 0 && strcmp(bn + 1, "files") != 0))
-       {
-          skipentry(&th);
-         continue;
-       }
-      if ((flags & REPO_EXTEND_SOLVABLES) != 0 && (!strcmp(bn + 1, "desc") || !strcmp(bn + 1, "depends")))
-       {
-          skipentry(&th);
-         continue;     /* skip those when we're extending */
-       }
-      if (!lastdn || (bn - th.path) != lastdnlen || strncmp(lastdn, th.path, lastdnlen) != 0)
-       {
-         finishsolvable(repo, s);
-         solv_free(lastdn);
-         lastdn = solv_strdup(th.path);
-         lastdnlen = bn - th.path;
-         lastdn[lastdnlen] = 0;
-         if (flags & REPO_EXTEND_SOLVABLES)
-           {
-             s = joinhash_lookup(repo, joinhash, joinhashmask, lastdn);
-             if (!s)
-               {
-                 skipentry(&th);
-                 continue;
-               }
-           }
-         else
-           s = pool_id2solvable(pool, repo_add_solvable(repo));
-       }
-      adddata(data, s, &th);
-    }
-  finishsolvable(repo, s);
-  solv_free(joinhash);
-  solv_free(lastdn);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-int
-repo_add_arch_local(Repo *repo, const char *dir, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  DIR *dp;
-  struct dirent *de;
-  char *entrydir, *file;
-  FILE *fp;
-  Solvable *s;
-
-  data = repo_add_repodata(repo, flags);
-
-  if (flags & REPO_USE_ROOTDIR)
-    dir = pool_prepend_rootdir(pool, dir);
-  dp = opendir(dir);
-  if (dp)
-    {
-      while ((de = readdir(dp)) != 0)
-       {
-         if (!de->d_name[0] || de->d_name[0] == '.')
-           continue;
-         entrydir = solv_dupjoin(dir, "/", de->d_name);
-         file = pool_tmpjoin(repo->pool, entrydir, "/desc", 0);
-         s = 0;
-         if ((fp = fopen(file, "r")) != 0)
-           {
-             struct tarhead th;
-             inittarhead(&th, fp);
-             s = pool_id2solvable(pool, repo_add_solvable(repo));
-             adddata(data, s, &th);
-             freetarhead(&th);
-             fclose(fp);
-             file = pool_tmpjoin(repo->pool, entrydir, "/files", 0);
-             if ((fp = fopen(file, "r")) != 0)
-               {
-                 inittarhead(&th, fp);
-                 adddata(data, s, &th);
-                 freetarhead(&th);
-                 fclose(fp);
-               }
-           }
-         solv_free(entrydir);
-       }
-      closedir(dp);
-    }
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  if (flags & REPO_USE_ROOTDIR)
-    solv_free((char *)dir);
-  return 0;
-}
-
diff --git a/libsolv-0.6.15/ext/repo_arch.h b/libsolv-0.6.15/ext/repo_arch.h
deleted file mode 100644 (file)
index 78a2f32..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define ARCH_ADD_WITH_PKGID  (1 << 8)
-
-extern Id repo_add_arch_pkg(Repo *repo, const char *fn, int flags);
-extern Id repo_add_arch_repo(Repo *repo, FILE *fp, int flags);
-extern Id repo_add_arch_local(Repo *repo, const char *dir, int flags);
-
diff --git a/libsolv-0.6.15/ext/repo_autopattern.c b/libsolv-0.6.15/ext/repo_autopattern.c
deleted file mode 100644 (file)
index 4c767e1..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (c) 2013, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-#define _XOPEN_SOURCE
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "repo_autopattern.h"
-
-static void
-unescape(char *p)
-{
-  char *q = p;
-  while (*p)
-    {
-      if (*p == '%' && p[1] && p[2])
-       {
-         int d1 = p[1], d2 = p[2];
-         if (d1 >= '0' && d1 <= '9')
-           d1 -= '0';
-         else if (d1 >= 'a' && d1 <= 'f')
-           d1 -= 'a' - 10;
-         else if (d1 >= 'A' && d1 <= 'F')
-           d1 -= 'A' - 10;
-         else
-           d1 = -1;
-         if (d2 >= '0' && d2 <= '9')
-           d2 -= '0';
-         else if (d2 >= 'a' && d2 <= 'f')
-           d2 -= 'a' - 10;
-         else if (d2 >= 'A' && d2 <= 'F')
-           d2 -= 'A' - 10;
-         else
-           d2 = -1;
-         if (d1 != -1 && d2 != -1)
-           {
-             *q++ = d1 << 4 | d2;
-             p += 3;
-             continue;
-           }
-       }
-      *q++ = *p++;
-    }
-  *q = 0;
-}
-
-static time_t
-datestr2timestamp(const char *date)
-{
-  const char *p; 
-  struct tm tm; 
-
-  if (!date || !*date)
-    return 0;
-  for (p = date; *p >= '0' && *p <= '9'; p++)
-    ;   
-  if (!*p)
-    return atoi(date);
-  memset(&tm, 0, sizeof(tm));
-  p = strptime(date, "%F%T", &tm);
-  if (!p)
-    {   
-      memset(&tm, 0, sizeof(tm));
-      p = strptime(date, "%F", &tm);
-      if (!p || *p) 
-        return 0;
-    }   
-  return timegm(&tm);
-}
-
-int
-repo_add_autopattern(Repo *repo, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data = 0;
-  Solvable *s, *s2;
-  Queue patq, patq2;
-  Queue prdq, prdq2;
-  Id p;
-  Id pattern_id, product_id;
-  Id autopattern_id = 0, autoproduct_id = 0;
-  int i, j;
-
-  queue_init(&patq);
-  queue_init(&patq2);
-  queue_init(&prdq);
-  queue_init(&prdq2);
-
-  if (repo == pool->installed)
-    flags |= ADD_NO_AUTOPRODUCTS;      /* no auto products for installed repos */
-
-  pattern_id = pool_str2id(pool, "pattern()", 9);
-  product_id = pool_str2id(pool, "product()", 9);
-  FOR_REPO_SOLVABLES(repo, p, s)
-    {
-      const char *n = pool_id2str(pool, s->name);
-      if (*n == 'p')
-       {
-         if (!strncmp("pattern:", n, 8))
-           {
-             queue_push(&patq, p);
-             continue;
-           }
-         else if (!strncmp("product:", n, 8))
-           {
-             queue_push(&prdq, p);
-             continue;
-           }
-       }
-      if (s->provides)
-       {
-         Id prv, *prvp = repo->idarraydata + s->provides;
-         while ((prv = *prvp++) != 0)            /* go through all provides */
-           if (ISRELDEP(prv))
-             {
-               Reldep *rd = GETRELDEP(pool, prv);
-               if (rd->flags != REL_EQ)
-                 continue;
-               if (rd->name == pattern_id)
-                 {
-                   const char *evrstr = pool_id2str(pool, rd->evr);
-                   if (evrstr[0] == '.')       /* hack to allow provides that do not create a pattern */
-                     continue;
-                   if (patq2.count && patq2.elements[patq2.count - 2] == p)
-                     {
-                       /* hmm, two provides. choose by evrstr */
-                       if (strcmp(evrstr, pool_id2str(pool, patq2.elements[patq2.count - 1])) >= 0)
-                         continue;
-                       patq2.count -= 2;
-                     }
-                   queue_push2(&patq2, p, rd->evr);
-                 }
-               if (rd->name == product_id)
-                 {
-                   const char *evrstr = pool_id2str(pool, rd->evr);
-                   if (prdq2.count && prdq2.elements[prdq2.count - 2] == p)
-                     {
-                       /* hmm, two provides. choose by evrstr */
-                       if (strcmp(evrstr, pool_id2str(pool, prdq2.elements[prdq2.count - 1])) >= 0)
-                         continue;
-                       prdq2.count -= 2;
-                     }
-                   queue_push2(&prdq2, p, rd->evr);
-                 }
-             }
-       }
-    }
-  for (i = 0; i < patq2.count; i += 2)
-    {
-      const char *pn = 0;
-      char *newname;
-      Id name, prv, *prvp;
-      const char *str;
-      unsigned long long num;
-
-      s = pool->solvables + patq2.elements[i];
-      /* construct new name */
-      newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, patq2.elements[i + 1]), 0);
-      unescape(newname);
-      name = pool_str2id(pool, newname, 0);
-      if (name)
-       {
-         /* check if we already have that pattern */
-         for (j = 0; j < patq.count; j++)
-           {
-             s2 = pool->solvables + patq.elements[j];
-             if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr)
-               break;
-           }
-         if (j < patq.count)
-           continue;   /* yes, do not add again */
-       }
-      /* new pattern */
-      if (!name)
-        name = pool_str2id(pool, newname, 1);
-      if (!data)
-       {
-         repo_internalize(repo);       /* to make that the lookups work */
-         data = repo_add_repodata(repo, flags);
-       }
-      s2 = pool_id2solvable(pool, repo_add_solvable(repo));
-      s = pool->solvables + patq2.elements[i]; /* re-calc pointer */
-      s2->name = name;
-      s2->arch = s->arch;
-      s2->evr = s->evr;
-      s2->vendor = s->vendor;
-      /* add link requires */
-      s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0);
-      /* add autopattern provides */
-      if (!autopattern_id)
-       autopattern_id = pool_str2id(pool, "autopattern()", 1);
-      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0);
-      /* add self provides */
-      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
-      if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
-       repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num);
-      if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
-       repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
-      if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
-       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
-      if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
-       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
-      /* fill in stuff from provides */
-      prvp = repo->idarraydata + s->provides;
-      while ((prv = *prvp++) != 0)            /* go through all provides */
-       {
-         Id evr = 0;
-         if (ISRELDEP(prv))
-           {
-             Reldep *rd = GETRELDEP(pool, prv);
-             if (rd->flags != REL_EQ)
-               continue;
-             prv = rd->name;
-             evr = rd->evr;
-           }
-         pn = pool_id2str(pool, prv);
-         if (strncmp("pattern-", pn, 8) != 0)
-           continue;
-         newname = 0;
-         if (evr)
-           {
-             newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
-             unescape(newname);
-           }
-         if (!strncmp(pn, "pattern-category(", 17) && evr)
-           {
-             char lang[9];
-             int l = strlen(pn);
-             Id langtag;
-             if (l > 17 + 9 || pn[l - 1] != ')')
-               continue;
-              strncpy(lang, pn + 17, l - 17 - 1);
-             lang[l - 17 - 1] = 0;
-             langtag = SOLVABLE_CATEGORY;
-             if (*lang && strcmp(lang, "en") != 0)
-               langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1);
-             if (newname[solv_validutf8(newname)] == 0)
-               repodata_set_str(data, s2 - pool->solvables, langtag, newname);
-             else
-               {
-                 char *ustr = solv_latin1toutf8(newname);
-                 repodata_set_str(data, s2 - pool->solvables, langtag, ustr);
-                 solv_free(ustr);
-               }
-           }
-         else if (!strcmp(pn, "pattern-includes()") && evr)
-           repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0));
-         else if (!strcmp(pn, "pattern-extends()") && evr)
-           repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0));
-         else if (!strcmp(pn, "pattern-icon()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname);
-         else if (!strcmp(pn, "pattern-order()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname);
-         else if (!strcmp(pn, "pattern-visible()"))
-           {
-             if (!evr)
-               repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE);
-             else
-               repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE, newname);
-           }
-       }
-    }
-  queue_free(&patq);
-  queue_free(&patq2);
-
-  if ((flags & ADD_NO_AUTOPRODUCTS) != 0)
-    queue_empty(&prdq2);
-
-  for (i = 0; i < prdq2.count; i += 2)
-    {
-      const char *pn = 0;
-      char *newname;
-      Id name, evr = 0, prv, *prvp;
-      const char *str;
-      unsigned long long num;
-
-      s = pool->solvables + prdq2.elements[i];
-      /* construct new name */
-      newname = pool_tmpjoin(pool, "product(", pool_id2str(pool, prdq2.elements[i + 1]), ")");
-      unescape(newname);
-      name = pool_str2id(pool, newname, 0);
-      if (!name)
-       continue;       /* must have it in provides! */
-      prvp = repo->idarraydata + s->provides;
-      while ((prv = *prvp++) != 0)            /* go through all provides */
-       {
-         if (ISRELDEP(prv))
-           {
-             Reldep *rd = GETRELDEP(pool, prv);
-             if (rd->name == name && rd->flags == REL_EQ)
-               {
-                 evr = rd->evr;
-                 break;
-               }
-           }
-       }
-      if (!prv)
-       continue;       /* not found in provides */
-      newname = pool_tmpjoin(pool, "product:", pool_id2str(pool, prdq2.elements[i + 1]), 0);
-      unescape(newname);
-      name = pool_str2id(pool, newname, 0);
-      if (name)
-       {
-         /* check if we already have that product */
-         for (j = 0; j < prdq.count; j++)
-           {
-             s2 = pool->solvables + prdq.elements[j];
-             if (s2->name == name && s2->arch == s->arch && s2->evr == evr)
-               break;
-           }
-         if (j < prdq.count)
-           continue;   /* yes, do not add again */
-       }
-      /* new product */
-      if (!name)
-        name = pool_str2id(pool, newname, 1);
-      if (!data)
-       {
-         repo_internalize(repo);       /* to make that the lookups work */
-         data = repo_add_repodata(repo, flags);
-       }
-      if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
-       continue;               /* eek, not for installed packages, please! */
-      s2 = pool_id2solvable(pool, repo_add_solvable(repo));
-      s = pool->solvables + prdq2.elements[i]; /* re-calc pointer */
-      s2->name = name;
-      s2->arch = s->arch;
-      s2->evr = evr;
-      s2->vendor = s->vendor;
-      /* add link requires */
-      s2->requires = repo_addid_dep(repo, s2->requires, prv, 0);
-      if (!autoproduct_id)
-       autoproduct_id = pool_str2id(pool, "autoproduct()", 1);
-      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autoproduct_id, s->name, REL_EQ, 1), 0);
-      /* add self provides */
-      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
-      if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
-       repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
-      if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
-       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
-      if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
-       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
-      if ((str = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION)) != 0)
-       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DISTRIBUTION, str);
-      /* fill in stuff from provides */
-      prvp = repo->idarraydata + s->provides;
-      while ((prv = *prvp++) != 0)            /* go through all provides */
-       {
-         Id evr = 0;
-         if (ISRELDEP(prv))
-           {
-             Reldep *rd = GETRELDEP(pool, prv);
-             if (rd->flags != REL_EQ)
-               continue;
-             prv = rd->name;
-             evr = rd->evr;
-           }
-         pn = pool_id2str(pool, prv);
-         if (strncmp("product-", pn, 8) != 0)
-           continue;
-         newname = 0;
-         if (evr)
-           {
-             newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
-             unescape(newname);
-           }
-         if (!strcmp(pn, "product-label()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, PRODUCT_SHORTLABEL, newname);
-         else if (!strcmp(pn, "product-register-target()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_TARGET, newname);
-         else if (!strcmp(pn, "product-register-flavor()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_FLAVOR, newname);
-         else if (!strcmp(pn, "product-type()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, PRODUCT_TYPE, newname);
-         else if (!strcmp(pn, "product-cpeid()") && evr)
-           repodata_set_str(data, s2 - pool->solvables, SOLVABLE_CPEID, newname);
-         else if (!strcmp(pn, "product-flags()") && evr)
-           repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_FLAGS, newname);
-         else if (!strcmp(pn, "product-updates-repoid()") && evr)
-           {
-             Id h = repodata_new_handle(data);
-             repodata_set_str(data, h, PRODUCT_UPDATES_REPOID, newname);
-             repodata_add_flexarray(data, s2 - pool->solvables, PRODUCT_UPDATES, h);
-           }
-         else if (!strcmp(pn, "product-endoflife()") && evr)
-           {
-             time_t t = datestr2timestamp(newname);
-             if (t)
-               repodata_set_num(data, s2 - pool->solvables, PRODUCT_ENDOFLIFE, t);
-           }
-         else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32)
-           {
-             char type[34];
-             strcpy(type, pn + 12);
-             type[strlen(type) - 1] = 0;       /* closing ) */
-             repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL_TYPE, type);
-             repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL, newname);
-           }
-       }
-    }
-  queue_free(&prdq);
-  queue_free(&prdq2);
-
-  if (data && !(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  else if (!data && !(flags & REPO_NO_INTERNALIZE))
-    repo_internalize(repo);
-  return 0;
-}
-
diff --git a/libsolv-0.6.15/ext/repo_autopattern.h b/libsolv-0.6.15/ext/repo_autopattern.h
deleted file mode 100644 (file)
index b9cbada..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (c) 2013, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define ADD_NO_AUTOPRODUCTS    (1 << 8)
-
-extern int repo_add_autopattern(Repo *repo, int flags);
diff --git a/libsolv-0.6.15/ext/repo_comps.c b/libsolv-0.6.15/ext/repo_comps.c
deleted file mode 100644 (file)
index 8f364dd..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * repo_comps.c
- *
- * Parses RedHat comps format
- *
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <dirent.h>
-#include <expat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#define DISABLE_SPLIT
-#include "tools_util.h"
-#include "repo_comps.h"
-
-/*
- * TODO:
- *
- * what's the difference between group/category?
- * handle "default" and "langonly".
- *
- * maybe handle REL_COND in solver recommends handling?
- */
-
-enum state {
-  STATE_START,
-  STATE_COMPS,
-  STATE_GROUP,
-  STATE_ID,
-  STATE_NAME,
-  STATE_DESCRIPTION,
-  STATE_DISPLAY_ORDER,
-  STATE_DEFAULT,
-  STATE_LANGONLY,
-  STATE_LANG_ONLY,
-  STATE_USERVISIBLE,
-  STATE_PACKAGELIST,
-  STATE_PACKAGEREQ,
-  STATE_CATEGORY,
-  STATE_CID,
-  STATE_CNAME,
-  STATE_CDESCRIPTION,
-  STATE_CDISPLAY_ORDER,
-  STATE_GROUPLIST,
-  STATE_GROUPID,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* must be sorted by first column */
-static struct stateswitch stateswitches[] = {
-  { STATE_START,       "comps",         STATE_COMPS,         0 },
-  { STATE_COMPS,       "group",         STATE_GROUP,         0 },
-  { STATE_COMPS,       "category",      STATE_CATEGORY,      0 },
-  { STATE_GROUP,       "id",            STATE_ID,            1 },
-  { STATE_GROUP,       "name",          STATE_NAME,          1 },
-  { STATE_GROUP,       "description",   STATE_DESCRIPTION,   1 },
-  { STATE_GROUP,       "uservisible",   STATE_USERVISIBLE,   1 },
-  { STATE_GROUP,       "display_order", STATE_DISPLAY_ORDER, 1 },
-  { STATE_GROUP,       "default",       STATE_DEFAULT,       1 },
-  { STATE_GROUP,       "langonly",      STATE_LANGONLY,      1 },
-  { STATE_GROUP,       "lang_only",     STATE_LANG_ONLY,     1 },
-  { STATE_GROUP,       "packagelist",   STATE_PACKAGELIST,   0 },
-  { STATE_PACKAGELIST, "packagereq",    STATE_PACKAGEREQ,    1 },
-  { STATE_CATEGORY,    "id",            STATE_CID,           1 },
-  { STATE_CATEGORY,    "name",          STATE_CNAME,         1 },
-  { STATE_CATEGORY,    "description",   STATE_CDESCRIPTION,  1 },
-  { STATE_CATEGORY ,   "grouplist",     STATE_GROUPLIST,     0 },
-  { STATE_CATEGORY ,   "display_order", STATE_CDISPLAY_ORDER, 1 },
-  { STATE_GROUPLIST,   "groupid",       STATE_GROUPID,       1 },
-  { NUMSTATES }
-};
-
-struct parsedata {
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-  const char *filename;
-  const char *basename;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  struct joindata jd;
-
-  const char *tmplang;
-  Id reqtype;
-  Id condreq;
-
-  Solvable *solvable;
-  Id handle;
-};
-
-
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-/*
- * XML callback: startElement
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-
-#if 0
-      fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_GROUP:
-    case STATE_CATEGORY:
-      s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-      pd->handle = s - pool->solvables;
-      break;
-
-    case STATE_NAME:
-    case STATE_CNAME:
-    case STATE_DESCRIPTION:
-    case STATE_CDESCRIPTION:
-      pd->tmplang = join_dup(&pd->jd, find_attr("xml:lang", atts));
-      break;
-
-    case STATE_PACKAGEREQ:
-      {
-       const char *type = find_attr("type", atts);
-       pd->condreq = 0;
-       pd->reqtype = SOLVABLE_RECOMMENDS;
-       if (type && !strcmp(type, "conditional"))
-         {
-           const char *requires = find_attr("requires", atts);
-           if (requires && *requires)
-             pd->condreq = pool_str2id(pool, requires, 1);
-         }
-       else if (type && !strcmp(type, "mandatory"))
-         pd->reqtype = SOLVABLE_REQUIRES;
-       else if (type && !strcmp(type, "optional"))
-         pd->reqtype = SOLVABLE_SUGGESTS;
-       break;
-      }
-
-    default:
-      break;
-    }
-}
-
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Solvable *s = pd->solvable;
-  Id id;
-
-#if 0
-      fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  switch (pd->state)
-    {
-    case STATE_GROUP:
-    case STATE_CATEGORY:
-      if (!s->arch)
-       s->arch = ARCH_NOARCH;
-      if (!s->evr)
-       s->evr = ID_EMPTY;
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
-      pd->solvable = 0;
-      break;
-
-    case STATE_ID:
-    case STATE_CID:
-      s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->state == STATE_ID ? "group" : "category", ":", pd->content), 1);
-      break;
-
-    case STATE_NAME:
-    case STATE_CNAME:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
-      break;
-
-    case STATE_DESCRIPTION:
-    case STATE_CDESCRIPTION:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content);
-      break;
-
-    case STATE_PACKAGEREQ:
-      id = pool_str2id(pd->pool, pd->content, 1);
-      if (pd->condreq)
-       id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1);
-      repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id);
-      break;
-
-    case STATE_GROUPID:
-      id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", pd->content), 1);
-      s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
-      break;
-
-    case STATE_USERVISIBLE:
-      repodata_set_void(pd->data, pd->handle, SOLVABLE_ISVISIBLE);
-      break;
-
-    case STATE_DISPLAY_ORDER:
-    case STATE_CDISPLAY_ORDER:
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, pd->content);
-      break;
-
-    case STATE_DEFAULT:
-      break;
-
-    case STATE_LANGONLY:
-    case STATE_LANG_ONLY:
-      break;
-
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-      fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-
-int
-repo_add_comps(Repo *repo, FILE *fp, int flags)
-{
-  Repodata *data;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  XML_Parser parser;
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  pd.repo = repo;
-  pd.pool = repo->pool;
-  pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-
-  solv_free(pd.content);
-  join_freemem(&pd.jd);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/ext/repo_comps.h b/libsolv-0.6.15/ext/repo_comps.h
deleted file mode 100644 (file)
index 8998b07..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_comps(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.6.15/ext/repo_content.c b/libsolv-0.6.15/ext/repo_content.c
deleted file mode 100644 (file)
index 0cd1293..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * repo_content.c
- *
- * Parses 'content' file into .solv
- * A 'content' file is the repomd.xml of the susetags format
- *
- * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata/content for a description
- * of the syntax
- *
- *
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "chksum.h"
-#include "repo_content.h"
-#define DISABLE_SPLIT
-#define DISABLE_JOIN2
-#include "tools_util.h"
-
-/* split off a word, return null terminated pointer to it.
- * return NULL if there is no word left. */
-static char *
-splitword(char **lp)
-{
-  char *w, *l = *lp;
-
-  while (*l == ' ' || *l == '\t')
-    l++;
-  w = *l ? l : 0;
-  while (*l && *l != ' ' && *l != '\t')
-    l++;
-  if (*l)
-    *l++ = 0;          /* terminate word */
-  while (*l == ' ' || *l == '\t')
-    l++;               /* convenience: advance to next word */
-  *lp = l;
-  return w;
-}
-
-struct parsedata {
-  Repo *repo;
-  char *tmp;
-  int tmpl;
-
-  const char *tmpvers;
-  const char *tmprel;
-};
-
-/*
- * dependency relations
- */
-
-static char *flagtab[] = {
-  ">",
-  "=",
-  ">=",
-  "<",
-  "!=",
-  "<="
-};
-
-
-/*
- * join up to three strings into one
- */
-
-static char *
-join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
-{
-  int l = 1;
-  char *p;
-
-  if (s1)
-    l += strlen(s1);
-  if (s2)
-    l += strlen(s2);
-  if (s3)
-    l += strlen(s3);
-  if (l > pd->tmpl)
-    {
-      pd->tmpl = l + 256;
-      pd->tmp = solv_realloc(pd->tmp, pd->tmpl);
-    }
-  p = pd->tmp;
-  if (s1)
-    {
-      strcpy(p, s1);
-      p += strlen(s1);
-    }
-  if (s2)
-    {
-      strcpy(p, s2);
-      p += strlen(s2);
-    }
-  if (s3)
-    {
-      strcpy(p, s3);
-      p += strlen(s3);
-    }
-  *p = 0;
-  return pd->tmp;
-}
-
-
-/*
- * add dependency to pool
- * OBSOLETES product:SUSE_LINUX product:openSUSE < 11.0 package:openSUSE < 11.0
- */
-
-static unsigned int
-adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
-{
-  char *name;
-  Id id;
-
-  while ((name = splitword(&line)) != 0)
-    {
-      /* Hack, as the content file adds 'package:' for package
-         dependencies sometimes.  */
-      if (!strncmp (name, "package:", 8))
-        name += 8;
-      id = pool_str2id(pool, name, 1);
-      if (*line == '<' || *line == '>' || *line == '=')        /* rel follows */
-       {
-         char *rel = splitword(&line);
-          char *evr = splitword(&line);
-         int flags;
-
-         if (!rel || !evr)
-           {
-             pool_debug(pool, SOLV_ERROR, "repo_content: bad relation '%s %s'\n", name, rel);
-             continue;
-           }
-         for (flags = 0; flags < 6; flags++)
-           if (!strcmp(rel, flagtab[flags]))
-             break;
-         if (flags == 6)
-           {
-             pool_debug(pool, SOLV_ERROR, "repo_content: unknown relation '%s'\n", rel);
-             continue;
-           }
-         id = pool_rel2id(pool, id, pool_str2id(pool, evr, 1), flags + 1, 1);
-       }
-      olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
-    }
-  return olddeps;
-}
-
-
-/*
- * split value and add to pool
- */
-
-static void
-add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
-{
-  char *str;
-
-  while ((str = splitword(&value)) != 0)
-    repodata_add_poolstr_array(data, handle, name, str);
-}
-
-/*
- * split value and add to pool
- */
-
-static void
-add_multiple_urls(Repodata *data, Id handle, char *value, Id type)
-{
-  char *url;
-
-  while ((url = splitword(&value)) != 0)
-    {
-      repodata_add_poolstr_array(data, handle, PRODUCT_URL, url);
-      repodata_add_idarray(data, handle, PRODUCT_URL_TYPE, type);
-    }
-}
-
-
-
-/*
- * add 'content' to repo
- *
- */
-
-int
-repo_add_content(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  char *line, *linep;
-  int aline;
-  Solvable *s;
-  struct parsedata pd;
-  Repodata *data;
-  Id handle = 0;
-  int contentstyle = 0;
-  char *descrdir = 0;
-  char *datadir = 0;
-  char *defvendor = 0;
-
-  int i = 0;
-  int res = 0;
-
-  /* architectures
-     we use the first architecture in BASEARCHS or noarch
-     for the product. At the end we create (clone) the product
-     for each one of the remaining architectures
-     we allow max 4 archs
-  */
-  unsigned int numotherarchs = 0;
-  Id *otherarchs = 0;
-
-  memset(&pd, 0, sizeof(pd));
-  line = solv_malloc(1024);
-  aline = 1024;
-
-  pd.repo = repo;
-  linep = line;
-  s = 0;
-
-  data = repo_add_repodata(repo, flags);
-
-  for (;;)
-    {
-      char *key, *value;
-
-      /* read line into big-enough buffer */
-      if (linep - line + 16 > aline)
-       {
-         aline = linep - line;
-         line = solv_realloc(line, aline + 512);
-         linep = line + aline;
-         aline += 512;
-       }
-      if (!fgets(linep, aline - (linep - line), fp))
-       break;
-      linep += strlen(linep);
-      if (linep == line || linep[-1] != '\n')
-        continue;
-      while ( --linep > line && ( linep[-1] == ' ' ||  linep[-1] == '\t' ) )
-        ; /* skip trailing ws */
-      *linep = 0;
-      linep = line;
-
-      /* expect "key value" lines */
-      value = line;
-      key = splitword(&value);
-
-      if (key)
-        {
-#if 0
-         fprintf (stderr, "key %s, value %s\n", key, value);
-#endif
-
-#define istag(x) (!strcmp (key, x))
-#define code10 (contentstyle == 10)
-#define code11 (contentstyle == 11)
-
-
-         if (istag ("CONTENTSTYLE"))
-           {
-             if (contentstyle)
-               pool_debug(pool, SOLV_ERROR, "repo_content: 'CONTENTSTYLE' must be first line of 'content'\n");
-             contentstyle = atoi(value);
-             continue;
-           }
-         if (!contentstyle)
-           contentstyle = 10;
-
-         /* repository tags */
-          /* we also replicate some of them into the product solvables
-           * to be backward compatible */
-
-         if (istag ("REPOID"))
-           {
-             repodata_add_poolstr_array(data, SOLVID_META, REPOSITORY_REPOID, value);
-             continue;
-           }
-         if (istag ("REPOKEYWORDS"))
-           {
-             add_multiple_strings(data, SOLVID_META, REPOSITORY_KEYWORDS, value);
-             continue;
-           }
-         if (istag ("DISTRO"))
-           {
-             Id dh = repodata_new_handle(data);
-             char *p;
-             /* like with createrepo --distro */
-             if ((p = strchr(value, ',')) != 0)
-               {
-                 *p++ = 0;
-                 if (*value)
-                   repodata_set_poolstr(data, dh, REPOSITORY_PRODUCT_CPEID, value);
-               }
-             else
-               p = value;
-             if (*p)
-               repodata_set_str(data, dh, REPOSITORY_PRODUCT_LABEL, p);
-             repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DISTROS, dh);
-             continue;
-           }
-
-         if (istag ("DESCRDIR"))
-           {
-             if (descrdir)
-               free(descrdir);
-             else
-               repodata_set_str(data, SOLVID_META, SUSETAGS_DESCRDIR, value);
-             if (s)
-               repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, value);
-             descrdir = solv_strdup(value);
-             continue;
-           }
-         if (istag ("DATADIR"))
-           {
-             if (datadir)
-               free(datadir);
-             else
-               repodata_set_str(data, SOLVID_META, SUSETAGS_DATADIR, value);
-             if (s)
-               repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, value);
-             datadir = solv_strdup(value);
-             continue;
-           }
-         if (istag ("VENDOR"))
-           {
-             if (defvendor)
-               free(defvendor);
-             else
-               repodata_set_poolstr(data, SOLVID_META, SUSETAGS_DEFAULTVENDOR, value);
-             if (s)
-               s->vendor = pool_str2id(pool, value, 1);
-             defvendor = solv_strdup(value);
-             continue;
-           }
-
-         if (istag ("META") || istag ("HASH") || istag ("KEY"))
-           {
-             char *checksumtype, *checksum;
-             Id fh, type;
-             int l;
-
-             if ((checksumtype = splitword(&value)) == 0)
-               continue;
-             if ((checksum = splitword(&value)) == 0)
-               continue;
-             if (!*value)
-               continue;
-             type = solv_chksum_str2type(checksumtype);
-             if (!type)
-               {
-                 pool_error(pool, -1, "%s: unknown checksum type '%s'", value, checksumtype);
-                 res = 1;
-                 continue;
-               }
-              l = solv_chksum_len(type);
-             if (strlen(checksum) != 2 * l)
-               {
-                 pool_error(pool, -1, "%s: invalid checksum length for %s", value, checksumtype);
-                 res = 1;
-                 continue;
-               }
-             fh = repodata_new_handle(data);
-             repodata_set_poolstr(data, fh, SUSETAGS_FILE_TYPE, key);
-             repodata_set_str(data, fh, SUSETAGS_FILE_NAME, value);
-             repodata_set_checksum(data, fh, SUSETAGS_FILE_CHECKSUM, type, checksum);
-             repodata_add_flexarray(data, SOLVID_META, SUSETAGS_FILE, fh);
-             continue;
-           }
-
-         /* product tags */
-
-         if ((code10 && istag ("PRODUCT"))
-             || (code11 && istag ("NAME")))
-           {
-             if (s && !s->name)
-               {
-                 /* this solvable was created without seeing a
-                    PRODUCT entry, just set the name and continue */
-                 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
-                 continue;
-               }
-             if (s)
-               {
-                 /* finish old solvable */
-                 if (!s->arch)
-                   s->arch = ARCH_NOARCH;
-                 if (!s->evr)
-                   s->evr = ID_EMPTY;
-                 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-                   s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-                 if (code10)
-                   s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
-               }
-             /* create new solvable */
-             s = pool_id2solvable(pool, repo_add_solvable(repo));
-             handle = s - pool->solvables;
-             s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
-             if (datadir)
-               repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, datadir);
-             if (descrdir)
-               repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, descrdir);
-             if (defvendor)
-               s->vendor = pool_str2id(pool, defvendor, 1);
-             continue;
-           }
-
-         /* Sometimes PRODUCT/NAME is not the first entry, but we need a solvable
-            from here on.  */
-         if (!s)
-           {
-             s = pool_id2solvable(pool, repo_add_solvable(repo));
-             handle = s - pool->solvables;
-           }
-
-         if (istag ("VERSION"))
-            pd.tmpvers = solv_strdup(value);
-          else if (istag ("RELEASE"))
-            pd.tmprel = solv_strdup(value);
-         else if (code11 && istag ("DISTRIBUTION"))
-           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
-         else if (istag ("UPDATEURLS"))
-           add_multiple_urls(data, handle, value, pool_str2id(pool, "update", 1));
-         else if (istag ("EXTRAURLS"))
-           add_multiple_urls(data, handle, value, pool_str2id(pool, "extra", 1));
-         else if (istag ("OPTIONALURLS"))
-           add_multiple_urls(data, handle, value, pool_str2id(pool, "optional", 1));
-         else if (istag ("RELNOTESURL"))
-           add_multiple_urls(data, handle, value, pool_str2id(pool, "releasenotes", 1));
-         else if (istag ("SHORTLABEL"))
-           repodata_set_str(data, s - pool->solvables, PRODUCT_SHORTLABEL, value);
-         else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
-           repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, value);
-         else if (!strncmp (key, "LABEL.", 6))
-           repodata_set_str(data, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
-         else if (istag ("FLAGS"))
-           add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
-         else if (istag ("VENDOR"))    /* actually already handled above */
-           s->vendor = pool_str2id(pool, value, 1);
-          else if (istag ("BASEARCHS"))
-            {
-              char *arch;
-
-             if ((arch = splitword(&value)) != 0)
-               {
-                 s->arch = pool_str2id(pool, arch, 1);
-                 while ((arch = splitword(&value)) != 0)
-                   {
-                      otherarchs = solv_extend(otherarchs, numotherarchs, 1, sizeof(Id), 7);
-                      otherarchs[numotherarchs++] = pool_str2id(pool, arch, 1);
-                   }
-               }
-            }
-         if (!code10)
-           continue;
-
-         /*
-          * Every tag below is Code10 only
-          *
-          */
-
-         if (istag ("ARCH"))
-           /* Theoretically we want to have the best arch of the given
-              modifiers which still is compatible with the system
-              arch.  We don't know the latter here, though.  */
-           s->arch = ARCH_NOARCH;
-         else if (istag ("PREREQUIRES"))
-           s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
-         else if (istag ("REQUIRES"))
-           s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
-         else if (istag ("PROVIDES"))
-           s->provides = adddep(pool, &pd, s->provides, value, 0);
-         else if (istag ("CONFLICTS"))
-           s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
-         else if (istag ("OBSOLETES"))
-           s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
-         else if (istag ("RECOMMENDS"))
-           s->recommends = adddep(pool, &pd, s->recommends, value, 0);
-         else if (istag ("SUGGESTS"))
-           s->suggests = adddep(pool, &pd, s->suggests, value, 0);
-         else if (istag ("SUPPLEMENTS"))
-           s->supplements = adddep(pool, &pd, s->supplements, value, 0);
-         else if (istag ("ENHANCES"))
-           s->enhances = adddep(pool, &pd, s->enhances, value, 0);
-         /* FRESHENS doesn't seem to exist.  */
-         else if (istag ("TYPE"))
-           repodata_set_str(data, s - pool->solvables, PRODUCT_TYPE, value);
-
-         /* XXX do something about LINGUAS and ARCH?
-          * <ma>: Don't think so. zypp does not use or propagate them.
-          */
-#undef istag
-       }
-      else
-       pool_debug(pool, SOLV_ERROR, "repo_content: malformed line: %s\n", line);
-    }
-
-  if (datadir)
-    free(datadir);
-  if (descrdir)
-    free(descrdir);
-  if (defvendor)
-    free(defvendor);
-
-  if (s && !s->name)
-    {
-      pool_debug(pool, SOLV_ERROR, "repo_content: 'content' incomplete, no product solvable created!\n");
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      s = 0;
-    }
-  if (s)
-    {
-      if (pd.tmprel)
-       s->evr = makeevr(pool, join(&pd, pd.tmpvers, "-", pd.tmprel));
-      else
-       s->evr = makeevr(pool, pd.tmpvers);
-      pd.tmpvers = solv_free((void *)pd.tmpvers);
-      pd.tmprel = solv_free((void *)pd.tmprel);
-
-      if (!s->arch)
-       s->arch = ARCH_NOARCH;
-      if (!s->evr)
-       s->evr = ID_EMPTY;
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-        s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-      if (code10)
-       s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
-
-      /* now for every other arch, clone the product except the architecture */
-      for (i = 0; i < numotherarchs; ++i)
-       {
-         Solvable *p = pool_id2solvable(pool, repo_add_solvable(repo));
-         p->name = s->name;
-         p->evr = s->evr;
-         p->vendor = s->vendor;
-         p->arch = otherarchs[i];
-
-         /* self provides */
-         if (s->name && p->arch != ARCH_SRC && p->arch != ARCH_NOSRC)
-             p->provides = repo_addid_dep(repo, p->provides, pool_rel2id(pool, p->name, p->evr, REL_EQ, 1), 0);
-
-         /* now merge the attributes */
-         repodata_merge_attrs(data, p - pool->solvables, s - pool->solvables);
-       }
-    }
-
-  if (pd.tmp)
-    solv_free(pd.tmp);
-  solv_free(line);
-  solv_free(otherarchs);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return res;
-}
diff --git a/libsolv-0.6.15/ext/repo_content.h b/libsolv-0.6.15/ext/repo_content.h
deleted file mode 100644 (file)
index 2a70ce4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_content(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.6.15/ext/repo_cudf.c b/libsolv-0.6.15/ext/repo_cudf.c
deleted file mode 100644 (file)
index 00a4f87..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <zlib.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "chksum.h"
-#include "solver.h"
-#include "repo_cudf.h"
-
-static Id
-parseonedep(Pool *pool, char *p)
-{
-  char *n, *ne, *e, *ee;
-  Id name, evr;
-  int flags;
-
-  while (*p == ' ' || *p == '\t' || *p == '\n')
-    p++;
-  if (!*p)
-    return 0;
-  if (!strcmp(p, "!true"))
-    return 0;
-  if (!strcmp(p, "!false"))
-    return pool_str2id(pool, p, 1);
-  n = p;
-  /* find end of name */
-  while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
-    p++;
-  ne = p;
-  while (*p == ' ' || *p == '\t' || *p == '\n')
-    p++;
-  evr = 0;
-  flags = 0;
-  e = ee = 0;
-  if (*p == '>' || *p == '<' || *p == '=' || *p == '!')
-    {
-      if (*p == '>')
-       flags |= REL_GT;
-      else if (*p == '=')
-       flags |= REL_EQ;
-      else if (*p == '<')
-       flags |= REL_LT;
-      else if (*p == '!')
-       flags |= REL_LT | REL_GT | REL_EQ;
-      p++;
-      if (flags && *p == '=')
-       {
-         if (p[-1] != '=')
-           flags ^= REL_EQ;
-         p++;
-       }
-      while (*p == ' ' || *p == '\t' || *p == '\n')
-       p++;
-      e = p;
-      while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
-       p++;
-      ee = p;
-      while (*p == ' ' || *p == '\t' || *p == '\n')
-       p++;
-    }
-  name = pool_strn2id(pool, n, ne - n, 1);
-  if (e)
-    {
-      evr = pool_strn2id(pool, e, ee - e, 1);
-      name = pool_rel2id(pool, name, evr, flags, 1);
-    }
-  if (*p == '|')
-    {
-      Id id = parseonedep(pool, p + 1);
-      if (id)
-       name = pool_rel2id(pool, name, id, REL_OR, 1);
-    }
-  return name;
-}
-static unsigned int
-makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
-{
-  Pool *pool = repo->pool;
-  char *p;
-  Id id;
-
-  while ((p = strchr(deps, ',')) != 0)
-    {
-      *p = 0;
-      olddeps = makedeps(repo, deps, olddeps, marker);
-      *p = ',';
-      deps = p + 1;
-    }
-  id = parseonedep(pool, deps);
-  if (!id)
-    return olddeps;
-  return repo_addid_dep(repo, olddeps, id, marker);
-}
-
-static Offset
-copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
-{
-  Id *ida, *from;
-  int cc;
-  Offset off;
-
-  if (!fromoff)
-    return 0;
-  from = fromrepo->idarraydata + fromoff;
-  for (ida = from, cc = 0; *ida; ida++, cc++)
-    ;
-  if (cc == 0)
-    return 0;
-  off = repo_reserve_ids(repo, 0, cc);
-  memcpy(repo->idarraydata + off, from, (cc + 1) * sizeof(Id));
-  repo->idarraysize += cc + 1;
-  return off;
-}
-
-static void
-copysolvabledata(Pool *pool, Solvable *s, Repo *repo)
-{
-  Repo *srepo = s->repo;
-  if (srepo == repo)
-    return;
-  s->provides = copydeps(pool, repo, s->provides, srepo);
-  s->requires = copydeps(pool, repo, s->requires, srepo);
-  s->conflicts = copydeps(pool, repo, s->conflicts, srepo);
-  s->obsoletes = copydeps(pool, repo, s->obsoletes, srepo);
-  s->recommends = copydeps(pool, repo, s->recommends, srepo);
-  s->suggests = copydeps(pool, repo, s->suggests, srepo);
-  s->supplements = copydeps(pool, repo, s->supplements, srepo);
-  s->enhances  = copydeps(pool, repo, s->enhances, srepo);
-}
-
-#define KEEP_VERSION 1
-#define KEEP_PACKAGE 2
-#define KEEP_FEATURE 3
-
-static void
-finishpackage(Pool *pool, Solvable *s, int keep, Queue *job)
-{
-  Id *idp, id, sid;
-  if (!s)
-    return;
-  if (!s->arch)
-    s->arch = ARCH_ANY;
-  if (!s->evr)
-    s->evr = ID_EMPTY;
-  sid = pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
-  s->provides = repo_addid_dep(s->repo, s->provides, sid, 0);
-  if (!job || !pool->installed || s->repo != pool->installed)
-    return;
-  if (keep == KEEP_VERSION)
-    queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, sid);
-  else if (keep == KEEP_PACKAGE)
-    queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, s->name);
-  else if (keep == KEEP_FEATURE)
-    {
-      for (idp = s->repo->idarraydata + s->provides; (id = *idp) != 0; idp++)
-       {
-         if (id != sid)        /* skip self-provides */
-           queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
-       }
-    }
-}
-
-int
-repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
-{
-  Pool *pool;
-  char *buf, *p;
-  int bufa, bufl, c;
-  Solvable *s;
-  int instanza = 0;
-  int inrequest = 0;
-  int isinstalled = 0;
-  int keep = 0;
-  Repo *xrepo;
-
-  xrepo = repo ? repo : installedrepo;
-  if (!xrepo)
-    return -1;
-  pool = xrepo->pool;
-
-  buf = solv_malloc(4096);
-  bufa = 4096;
-  bufl = 0;
-  s = 0;
-
-  while (fgets(buf + bufl, bufa - bufl, fp) > 0)
-    {
-      bufl += strlen(buf + bufl);
-      if (bufl && buf[bufl - 1] != '\n')
-       {
-         if (bufa - bufl < 256)
-           {
-             bufa += 4096;
-             buf = solv_realloc(buf, bufa);
-           }
-         continue;
-       }
-      buf[--bufl] = 0;
-      c = getc(fp);
-      if (c == ' ' || c == '\t')
-       {
-         /* continuation line */
-         buf[bufl++] = ' ';
-         continue;
-       }
-      if (c != EOF)
-       ungetc(c, fp);
-      bufl = 0;
-      if (*buf == '#')
-       continue;
-      if (!*buf)
-       {
-         if (s && !repo && !isinstalled)
-           {
-             repo_free_solvable(repo, s - pool->solvables, 1);
-             s = 0;
-           }
-         if (s)
-           finishpackage(pool, s, keep, job);
-         s = 0;
-         keep = 0;
-         instanza = 0;
-         inrequest = 0;
-         continue;
-       }
-      p = strchr(buf, ':');
-      if (!p)
-       continue;       /* hmm */
-      *p++ = 0;
-      while (*p == ' ' || *p == '\t')
-       p++;
-      if (!instanza)
-       {
-         instanza = 1;
-         inrequest = 0;
-         if (!strcmp(buf, "request"))
-           {
-             inrequest = 1;
-             continue;
-           }
-         if (!strcmp(buf, "package"))
-           {
-             s = pool_id2solvable(pool, repo_add_solvable(xrepo));
-             isinstalled = 0;
-             keep = 0;
-           }
-       }
-      if (inrequest)
-       {
-         if (!job)
-           continue;
-         if (!strcmp(buf, "install"))
-           {
-             Id id, *idp;
-             Offset off = makedeps(xrepo, p, 0, 0);
-             for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
-               queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
-           }
-         else if (!strcmp(buf, "remove"))
-           {
-             Id id, *idp;
-             Offset off = makedeps(xrepo, p, 0, 0);
-             for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
-               queue_push2(job, SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES, id);
-           }
-         else if (!strcmp(buf, "upgrade"))
-           {
-             Id id, *idp;
-             Offset off = makedeps(xrepo, p, 0, 0);
-             for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
-               queue_push2(job, SOLVER_INSTALL|SOLVER_ORUPDATE|SOLVER_SOLVABLE_PROVIDES, id);
-           }
-         continue;
-       }
-      if (!s)
-       continue;       /* we ignore the preamble for now */
-      switch (buf[0])
-       {
-       case 'c':
-         if (!strcmp(buf, "conflicts"))
-           {
-             s->conflicts = makedeps(s->repo, p, s->conflicts, 0);
-             continue;
-           }
-       case 'd':
-         if (!strcmp(buf, "depends"))
-           {
-             s->requires = makedeps(s->repo, p, s->requires, 0);
-             continue;
-           }
-         break;
-       case 'k':
-         if (!strcmp(buf, "keep"))
-           {
-             if (!job)
-               continue;
-             if (!strcmp(p, "version"))
-               keep = KEEP_VERSION;
-             else if (!strcmp(p, "package"))
-               keep = KEEP_PACKAGE;
-             else if (!strcmp(p, "feature"))
-               keep = KEEP_FEATURE;
-             continue;
-           }
-         break;
-       case 'i':
-         if (!strcmp(buf, "installed"))
-           {
-             if (!strcmp(p, "true"))
-               {
-                 isinstalled = 1;
-                 if (!installedrepo)
-                   {
-                     repo_free_solvable(repo, s - pool->solvables, 1);
-                     s = 0;
-                   }
-                 else if (s->repo != installedrepo)
-                   {
-                     copysolvabledata(pool, s, installedrepo);
-                     s->repo->nsolvables--;
-                     s->repo = installedrepo;
-                     if (s - pool->solvables < s->repo->start)
-                       s->repo->start = s - pool->solvables;
-                     if (s - pool->solvables >= s->repo->end)
-                       s->repo->end = s - pool->solvables + 1;
-                     s->repo->nsolvables++;
-                   }
-               }
-             continue;
-           }
-         break;
-       case 'p':
-         if (!strcmp(buf, "package"))
-           {
-             s->name = pool_str2id(pool, p, 1);
-             continue;
-           }
-         if (!strcmp(buf, "provides"))
-           {
-             s->provides = makedeps(s->repo, p, s->provides, 0);
-             continue;
-           }
-         break;
-       case 'r':
-         if (!strcmp(buf, "depends"))
-           {
-             s->recommends = makedeps(s->repo, p, s->recommends, 0);
-             continue;
-           }
-         break;
-       case 'v':
-         if (!strcmp(buf, "version"))
-           {
-             s->evr = pool_str2id(pool, p, 1);
-             continue;
-           }
-         break;
-       }
-    }
-  if (s && !repo && !isinstalled)
-    {
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      s = 0;
-    }
-  if (s)
-    finishpackage(pool, s, keep, job);
-  solv_free(buf);
-  return 0;
-}
-
diff --git a/libsolv-0.6.15/ext/repo_cudf.h b/libsolv-0.6.15/ext/repo_cudf.h
deleted file mode 100644 (file)
index fc9a0d6..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags);
-
diff --git a/libsolv-0.6.15/ext/repo_deb.c b/libsolv-0.6.15/ext/repo_deb.c
deleted file mode 100755 (executable)
index 6af7f10..0000000
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright (c) 2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <zlib.h>
-#include <lzma.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "solver.h"    /* for GET_USERINSTALLED_ flags */
-#include "chksum.h"
-#include "repo_deb.h"
-
-static unsigned char *
-decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
-{
-  z_stream strm;
-  int outl, ret;
-  unsigned char *bp, *out;
-
-  /* first skip the gz header */
-  if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b)
-    return 0;
-  if (in[2] != 8 || (in[3] & 0xe0) != 0)
-    return 0;
-  bp = in + 4;
-  bp += 6;     /* skip time, xflags and OS code */
-  if (in[3] & 0x04)
-    {
-      /* skip extra field */
-      int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8);
-      bp += l + 2;
-    }
-  if (in[3] & 0x08)    /* orig filename */
-    while (bp < in + inl && *bp++)
-      ;
-  if (in[3] & 0x10)    /* file comment */
-    while (bp < in + inl && *bp++)
-      ;
-  if (in[3] & 0x02)    /* header crc */
-    bp += 2;
-  if (bp >= in + inl)
-    return 0;
-  inl -= bp - in;
-  in = bp;
-
-  memset(&strm, 0, sizeof(strm));
-  strm.next_in = in;
-  strm.avail_in = inl;
-  out = solv_malloc(4096);
-  strm.next_out = out;
-  strm.avail_out = 4096;
-  outl = 0;
-  ret = inflateInit2(&strm, -MAX_WBITS);
-  if (ret != Z_OK)
-    {
-      free(out);
-      return 0;
-    }
-  for (;;)
-    {
-      if (strm.avail_out == 0)
-       {
-         outl += 4096;
-         if (outl >= maxoutl)
-           {
-             inflateEnd(&strm);
-             free(out);
-             return 0;
-           }
-         out = solv_realloc(out, outl + 4096);
-         strm.next_out = out + outl;
-         strm.avail_out = 4096;
-       }
-      ret = inflate(&strm, Z_NO_FLUSH);
-      if (ret == Z_STREAM_END)
-       break;
-      if (ret != Z_OK)
-       {
-         inflateEnd(&strm);
-         free(out);
-         return 0;
-       }
-    }
-  outl += 4096 - strm.avail_out;
-  inflateEnd(&strm);
-  *outlp = outl;
-  return out;
-}
-
-static unsigned char *
-decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
-{
-  static lzma_stream stream_init = LZMA_STREAM_INIT;
-  lzma_stream strm;
-  int outl, ret;
-  unsigned char *out;
-
-  strm = stream_init;
-  strm.next_in = in;
-  strm.avail_in = inl;
-  out = solv_malloc(4096);
-  strm.next_out = out;
-  strm.avail_out = 4096;
-  outl = 0;
-  ret = lzma_auto_decoder(&strm, 100 << 20, 0);
-  if (ret != LZMA_OK)
-    {
-      free(out);
-      return 0;
-    }
-  for (;;)
-    {
-      if (strm.avail_out == 0)
-       {
-         outl += 4096;
-         if (outl >= maxoutl)
-           {
-             lzma_end(&strm);
-             free(out);
-             return 0;
-           }
-         out = solv_realloc(out, outl + 4096);
-         strm.next_out = out + outl;
-         strm.avail_out = 4096;
-       }
-      ret = lzma_code(&strm, LZMA_RUN);
-      if (ret == LZMA_STREAM_END)
-       break;
-      if (ret != LZMA_OK)
-       {
-         lzma_end(&strm);
-         free(out);
-         return 0;
-       }
-    }
-  outl += 4096 - strm.avail_out;
-  lzma_end(&strm);
-  *outlp = outl;
-  return out;
-}
-
-static Id
-parseonedep(Pool *pool, char *p)
-{
-  char *n, *ne, *e, *ee;
-  Id name, evr;
-  int flags;
-
-  while (*p == ' ' || *p == '\t' || *p == '\n')
-    p++;
-  if (!*p || *p == '(')
-    return 0;
-  n = p;
-  /* find end of name */
-  while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
-    p++;
-  ne = p;
-  while (*p == ' ' || *p == '\t' || *p == '\n')
-    p++;
-  evr = 0;
-  flags = 0;
-  e = ee = 0;
-  if (*p == '(')
-    {
-      p++;
-      while (*p == ' ' || *p == '\t' || *p == '\n')
-       p++;
-      if (*p == '>')
-       flags |= REL_GT;
-      else if (*p == '=')
-       flags |= REL_EQ;
-      else if (*p == '<')
-       flags |= REL_LT;
-      if (flags)
-       {
-         p++;
-         if (*p == '>')
-           flags |= REL_GT;
-         else if (*p == '=')
-           flags |= REL_EQ;
-         else if (*p == '<')
-           flags |= REL_LT;
-         else
-           p--;
-         p++;
-       }
-      while (*p == ' ' || *p == '\t' || *p == '\n')
-       p++;
-      e = p;
-      while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
-       p++;
-      ee = p;
-      while (*p && *p != ')')
-       p++;
-      if (*p)
-       p++;
-      while (*p == ' ' || *p == '\t' || *p == '\n')
-       p++;
-    }
-  if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4))
-    {
-      /* multiarch annotation */
-      name = pool_strn2id(pool, n, ne - n - 4, 1);
-      name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1);
-    }
-  else
-    name = pool_strn2id(pool, n, ne - n, 1);
-  if (e)
-    {
-      evr = pool_strn2id(pool, e, ee - e, 1);
-      name = pool_rel2id(pool, name, evr, flags, 1);
-    }
-  if (*p == '|')
-    {
-      Id id = parseonedep(pool, p + 1);
-      if (id)
-       name = pool_rel2id(pool, name, id, REL_OR, 1);
-    }
-  return name;
-}
-
-static unsigned int
-makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
-{
-  Pool *pool = repo->pool;
-  char *p;
-  Id id;
-
-  while ((p = strchr(deps, ',')) != 0)
-    {
-      *p = 0;
-      olddeps = makedeps(repo, deps, olddeps, marker);
-      *p = ',';
-      deps = p + 1;
-    }
-  id = parseonedep(pool, deps);
-  if (!id)
-    return olddeps;
-  return repo_addid_dep(repo, olddeps, id, marker);
-}
-
-
-/* put data from control file into the solvable */
-/* warning: does inplace changes */
-static void
-control2solvable(Solvable *s, Repodata *data, char *control)
-{
-  Repo *repo = s->repo;
-  Pool *pool = repo->pool;
-  char *p, *q, *end, *tag;
-  int x, l;
-  int havesource = 0;
-  char checksum[32 * 2 + 1];
-  Id checksumtype = 0;
-  Id newtype;
-
-  p = control;
-  while (*p)
-    {
-      p = strchr(p, '\n');
-      if (!p)
-       break;
-      if (p[1] == ' ' || p[1] == '\t')
-       {
-         char *q;
-         /* continuation line */
-         q = p - 1;
-         while (q >= control && *q == ' ' && *q == '\t')
-           q--;
-         l = q + 1 - control;
-         if (l)
-           memmove(p + 1 - l, control, l);
-         control = p + 1 - l;
-         p[1] = '\n';
-         p += 2;
-         continue;
-       }
-      end = p - 1;
-      if (*p)
-        *p++ = 0;
-      /* strip trailing space */
-      while (end >= control && (*end == ' ' || *end == '\t'))
-       *end-- = 0;
-      tag = control;
-      control = p;
-      q = strchr(tag, ':');
-      if (!q || q - tag < 4)
-       continue;
-      *q++ = 0;
-      while (*q == ' ' || *q == '\t')
-       q++;
-      x = '@' + (tag[0] & 0x1f);
-      x = (x << 8) + '@' + (tag[1] & 0x1f);
-      switch(x)
-       {
-       case 'A' << 8 | 'R':
-         if (!strcasecmp(tag, "architecture"))
-           s->arch = pool_str2id(pool, q, 1);
-         break;
-       case 'B' << 8 | 'R':
-         if (!strcasecmp(tag, "breaks"))
-           s->conflicts = makedeps(repo, q, s->conflicts, 0);
-         break;
-       case 'C' << 8 | 'O':
-         if (!strcasecmp(tag, "conflicts"))
-           s->conflicts = makedeps(repo, q, s->conflicts, 0);
-         break;
-       case 'D' << 8 | 'E':
-         if (!strcasecmp(tag, "depends"))
-           s->requires = makedeps(repo, q, s->requires, -SOLVABLE_PREREQMARKER);
-         else if (!strcasecmp(tag, "description"))
-           {
-             char *ld = strchr(q, '\n');
-             if (ld)
-               {
-                 *ld++ = 0;
-                 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, ld);
-               }
-             else
-               repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, q);
-             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, q);
-           }
-         break;
-       case 'E' << 8 | 'N':
-         if (!strcasecmp(tag, "enhances"))
-           s->enhances = makedeps(repo, q, s->enhances, 0);
-         break;
-       case 'F' << 8 | 'I':
-         if (!strcasecmp(tag, "filename"))
-           repodata_set_location(data, s - pool->solvables, 0, 0, q);
-         break;
-       case 'H' << 8 | 'O':
-         if (!strcasecmp(tag, "homepage"))
-           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
-         break;
-       case 'I' << 8 | 'N':
-         if (!strcasecmp(tag, "installed-size"))
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10);
-         break;
-       case 'M' << 8 | 'D':
-         if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
-           {
-             strcpy(checksum, q);
-             checksumtype = REPOKEY_TYPE_MD5;
-           }
-         break;
-       case 'P' << 8 | 'A':
-         if (!strcasecmp(tag, "package"))
-           s->name = pool_str2id(pool, q, 1);
-         break;
-       case 'P' << 8 | 'R':
-         if (!strcasecmp(tag, "pre-depends"))
-           s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER);
-         else if (!strcasecmp(tag, "provides"))
-           s->provides = makedeps(repo, q, s->provides, 0);
-         break;
-       case 'R' << 8 | 'E':
-         if (!strcasecmp(tag, "replaces"))
-           s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
-         else if (!strcasecmp(tag, "recommends"))
-           s->recommends = makedeps(repo, q, s->recommends, 0);
-         break;
-       case 'S' << 8 | 'H':
-         newtype = solv_chksum_str2type(tag);
-         if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
-           break;
-         if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
-           {
-             strcpy(checksum, q);
-             checksumtype = newtype;
-           }
-         break;
-       case 'S' << 8 | 'O':
-         if (!strcasecmp(tag, "source"))
-           {
-             char *q2;
-             /* ignore version for now */
-             for (q2 = q; *q2; q2++)
-               if (*q2 == ' ' || *q2 == '\t')
-                 {
-                   *q2 = 0;
-                   break;
-                 }
-             if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
-               repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
-             else
-               repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
-             havesource = 1;
-           }
-         break;
-       case 'S' << 8 | 'T':
-         if (!strcasecmp(tag, "status"))
-           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
-         break;
-       case 'S' << 8 | 'U':
-         if (!strcasecmp(tag, "suggests"))
-           s->suggests = makedeps(repo, q, s->suggests, 0);
-         break;
-       case 'V' << 8 | 'E':
-         if (!strcasecmp(tag, "version"))
-           s->evr = pool_str2id(pool, q, 1);
-         break;
-       }
-    }
-  if (checksumtype)
-    repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
-  if (!s->arch)
-    s->arch = ARCH_ALL;
-  if (!s->evr)
-    s->evr = ID_EMPTY;
-  if (s->name)
-    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-  if (s->name && !havesource)
-    repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
-  if (s->obsoletes)
-    {
-      /* obsoletes only count when the packages also conflict */
-      /* XXX: should not transcode here */
-      int i, j, k;
-      Id d, cid;
-      for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
-       {
-         if (!s->conflicts)
-           continue;
-         for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
-           {
-             if (repo->idarraydata[k] == cid)
-               break;
-             if (ISRELDEP(cid))
-               {
-                 Reldep *rd = GETRELDEP(pool, cid);
-                 if (rd->flags < 8 && rd->name == d)
-                   break;      /* specialize obsoletes */
-               }
-           }
-         if (cid)
-           repo->idarraydata[j++] = cid;
-       }
-      repo->idarraydata[j] = 0;
-      if (j == s->obsoletes)
-       s->obsoletes = 0;
-    }
-}
-
-int
-repo_add_debpackages(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  char *buf, *p;
-  int bufl, l, ll;
-  Solvable *s;
-
-  data = repo_add_repodata(repo, flags);
-  buf = solv_malloc(4096);
-  bufl = 4096;
-  l = 0;
-  buf[l] = 0;
-  p = buf;
-  for (;;)
-    {
-      if (!(p = strchr(p, '\n')))
-       {
-         int l3;
-         while (l + 1024 >= bufl)
-           {
-             buf = solv_realloc(buf, bufl + 4096);
-             bufl += 4096;
-           }
-         p = buf + l;
-         ll = fread(p, 1, bufl - l - 1, fp);
-         if (ll <= 0)
-           break;
-         p[ll] = 0;
-         while ((l3 = strlen(p)) < ll)
-           p[l3] = '\n';
-         l += ll;
-         if (p != buf)
-           p--;
-         continue;
-       }
-      p++;
-      if (*p != '\n')
-       continue;
-      *p = 0;
-      ll = p - buf + 1;
-      s = pool_id2solvable(pool, repo_add_solvable(repo));
-      control2solvable(s, data, buf);
-      if (!s->name)
-       repo_free_solvable(repo, s - pool->solvables, 1);
-      if (l > ll)
-        memmove(buf, p + 1, l - ll);
-      l -= ll;
-      p = buf;
-      buf[l] = 0;
-    }
-  if (l)
-    {
-      s = pool_id2solvable(pool, repo_add_solvable(repo));
-      control2solvable(s, data, buf);
-      if (!s->name)
-       repo_free_solvable(repo, s - pool->solvables, 1);
-    }
-  solv_free(buf);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-int
-repo_add_debdb(Repo *repo, int flags)
-{
-  FILE *fp;
-  const char *path = "/var/lib/dpkg/status";
-  if (flags & REPO_USE_ROOTDIR)
-    path = pool_prepend_rootdir_tmp(repo->pool, path);
-  if ((fp = fopen(path, "r")) == 0)
-    return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
-  repo_add_debpackages(repo, fp, flags);
-  fclose(fp);
-  return 0;
-}
-
-#define CONTROL_COMP_NONE      0
-#define CONTROL_COMP_GZIP      1
-#define CONTROL_COMP_XZ                2
-
-Id
-repo_add_deb(Repo *repo, const char *deb, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  unsigned char buf[4096], *bp;
-  int l, l2, vlen, clen, ctarlen;
-  int control_comp;
-  unsigned char *ctgz;
-  unsigned char pkgid[16];
-  unsigned char *ctar;
-  int gotpkgid;
-  FILE *fp;
-  Solvable *s;
-  struct stat stb;
-
-  data = repo_add_repodata(repo, flags);
-  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
-    {
-      pool_error(pool, -1, "%s: %s", deb, strerror(errno));
-      return 0;
-    }
-  if (fstat(fileno(fp), &stb))
-    {
-      pool_error(pool, -1, "fstat: %s", strerror(errno));
-      fclose(fp);
-      return 0;
-    }
-  l = fread(buf, 1, sizeof(buf), fp);
-  if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/  ", 8 + 16) != 0))
-    {
-      pool_error(pool, -1, "%s: not a deb package", deb);
-      fclose(fp);
-      return 0;
-    }
-  vlen = atoi((char *)buf + 8 + 48);
-  if (vlen < 0 || vlen > l)
-    {
-      pool_error(pool, -1, "%s: not a deb package", deb);
-      fclose(fp);
-      return 0;
-    }
-  vlen += vlen & 1;
-  if (l < 8 + 60 + vlen + 60)
-    {
-      pool_error(pool, -1, "%s: unhandled deb package", deb);
-      fclose(fp);
-      return 0;
-    }
-  control_comp = 0;
-  if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
-    control_comp = CONTROL_COMP_GZIP;
-  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
-    control_comp = CONTROL_COMP_XZ;
-  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
-    control_comp = CONTROL_COMP_NONE;
-  else
-    {
-      pool_error(pool, -1, "%s: control.tar is not second entry", deb);
-      fclose(fp);
-      return 0;
-    }
-  /* dpkg has no actual maximum size for the control.tar member, so this
-   * just keeps from allocating arbitrarily large amounts of memory.
-   */
-  clen = atoi((char *)buf + 8 + 60 + vlen + 48);
-  if (clen <= 0 || clen >= 0x1000000)
-    {
-      pool_error(pool, -1, "%s: control.tar has illegal size", deb);
-      fclose(fp);
-      return 0;
-    }
-  ctgz = solv_calloc(1, clen + 4);
-  bp = buf + 8 + 60 + vlen + 60;
-  l -= 8 + 60 + vlen + 60;
-  if (l > clen)
-    l = clen;
-  if (l)
-    memcpy(ctgz, bp, l);
-  if (l < clen)
-    {
-      if (fread(ctgz + l, clen - l, 1, fp) != 1)
-       {
-         pool_error(pool, -1, "%s: unexpected EOF", deb);
-         solv_free(ctgz);
-         fclose(fp);
-         return 0;
-       }
-    }
-  fclose(fp);
-  gotpkgid = 0;
-  if (flags & DEBS_ADD_WITH_PKGID)
-    {
-      Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
-      solv_chksum_add(chk, ctgz, clen);
-      solv_chksum_free(chk, pkgid);
-      gotpkgid = 1;
-    }
-  ctar = 0;
-  if (control_comp == CONTROL_COMP_GZIP)
-    ctar = decompress_gz(ctgz, clen, &ctarlen, 0x1000000);
-  else if (control_comp == CONTROL_COMP_XZ)
-    ctar = decompress_xz(ctgz, clen, &ctarlen, 0x1000000);
-  else
-    {
-      ctarlen = clen;
-      ctar = solv_memdup(ctgz, clen);
-    }
-  solv_free(ctgz);
-  if (!ctar)
-    {
-      pool_error(pool, -1, "%s: control.tar is corrupt", deb);
-      return 0;
-    }
-  bp = ctar;
-  l = ctarlen;
-  l2 = 0;
-  while (l > 512)
-    {
-      int j;
-      l2 = 0;
-      for (j = 124; j < 124 + 12; j++)
-       if (bp[j] >= '0' && bp[j] <= '7')
-         l2 = l2 * 8 + (bp[j] - '0');
-      if (l2 < 0 || l2 > l)
-       {
-         l2 = 0;
-         break;
-       }
-      bp[124] = 0;
-      if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
-       break;
-      l2 = 512 + ((l2 + 511) & ~511);
-      l -= l2;
-      bp += l2;
-    }
-  if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
-    {
-      pool_error(pool, -1, "%s: control.tar contains no control file", deb);
-      free(ctar);
-      return 0;
-    }
-  memmove(ctar, bp + 512, l2);
-  ctar = solv_realloc(ctar, l2 + 1);
-  ctar[l2] = 0;
-  s = pool_id2solvable(pool, repo_add_solvable(repo));
-  control2solvable(s, data, (char *)ctar);
-  if (!(flags & REPO_NO_LOCATION))
-    repodata_set_location(data, s - pool->solvables, 0, 0, deb);
-  if (S_ISREG(stb.st_mode))
-    repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
-  if (gotpkgid)
-    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
-  solv_free(ctar);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return s - pool->solvables;
-}
-
-void
-pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
-{
-  Id name = 0, arch = 0;
-  int autoinstalled = -1;
-  char *buf, *bp;
-  int x, l, bufl, eof = 0;
-  Id p, pp;
-
-  queue_empty(q);
-  buf = solv_malloc(4096);
-  bufl = 4096;
-  l = 0;
-  while (!eof)
-    {
-      while (bufl - l < 1024)
-       {
-         bufl += 4096;
-         if (bufl > 1024 * 64)
-           break;      /* hmm? */
-         buf = solv_realloc(buf, bufl);
-       }
-      if (!fgets(buf + l, bufl - l, fp))
-       {
-         eof = 1;
-         buf[l] = '\n';
-         buf[l + 1] = 0;
-       }
-      l = strlen(buf);
-      if (l && buf[l - 1] == '\n')
-       buf[--l] = 0;
-      if (!*buf || eof)
-       {
-         l = 0;
-         if (name && autoinstalled > 0)
-           {
-             if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-               queue_push2(q, name, arch);
-             else if ((flags & GET_USERINSTALLED_NAMES) != 0)
-               queue_push(q, name);
-             else
-               {
-                 FOR_PROVIDES(p, pp, name)
-                   {
-                     Solvable *s = pool->solvables + p;
-                     if (s->name != name)
-                       continue;
-                     if (arch && s->arch != arch)
-                       continue;
-                     queue_push(q, p);
-                   }
-               }
-           }
-         name = arch = 0;
-         autoinstalled = -1;
-         continue;
-       }
-      /* strip trailing space */
-      while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
-       buf[--l] = 0;
-      l = 0;
-
-      bp = strchr(buf, ':');
-      if (!bp || bp - buf < 4)
-       continue;
-      *bp++ = 0;
-      while (*bp == ' ' || *bp == '\t')
-       bp++;
-      x = '@' + (buf[0] & 0x1f);
-      x = (x << 8) + '@' + (buf[1] & 0x1f);
-      switch(x)
-       {
-       case 'P' << 8 | 'A':
-         if (!strcasecmp(buf, "package"))
-           name = pool_str2id(pool, bp, 1);
-         break;
-       case 'A' << 8 | 'R':
-         if (!strcasecmp(buf, "architecture"))
-           arch = pool_str2id(pool, bp, 1);
-         break;
-       case 'A' << 8 | 'U':
-         if (!strcasecmp(buf, "auto-installed"))
-           autoinstalled = atoi(bp);
-         break;
-       default:
-         break;
-       }
-    }
-}
-
diff --git a/libsolv-0.6.15/ext/repo_deb.h b/libsolv-0.6.15/ext/repo_deb.h
deleted file mode 100644 (file)
index 5993991..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (c) 2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_debpackages(Repo *repo, FILE *fp, int flags);
-extern int repo_add_debdb(Repo *repo, int flags);
-extern Id repo_add_deb(Repo *repo, const char *deb, int flags);
-extern void pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags);
-
-#define DEBS_ADD_WITH_PKGID    (1 << 8)
diff --git a/libsolv-0.6.15/ext/repo_deltainfoxml.c b/libsolv-0.6.15/ext/repo_deltainfoxml.c
deleted file mode 100644 (file)
index 06df1a3..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define DO_ARRAY 1
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <expat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_deltainfoxml.h"
-
-/*
- * <deltainfo>
- *   <newpackage name="libtool" epoch="0" version="1.5.24" release="6.fc9" arch="i386">
- *     <delta oldepoch="0" oldversion="1.5.24" oldrelease="3.fc8">
- *       <filename>DRPMS/libtool-1.5.24-3.fc8_1.5.24-6.fc9.i386.drpm</filename>
- *       <sequence>libtool-1.5.24-3.fc8-d3571f98b048b1a870e40241bb46c67ab4</sequence>
- *       <size>22452</size>
- *       <checksum type="sha">8f05394695dee9399c204614e21e5f6848990ab7</checksum>
- *     </delta>
- *     <delta oldepoch="0" oldversion="1.5.22" oldrelease="11.fc7">
- *       <filename>DRPMS/libtool-1.5.22-11.fc7_1.5.24-6.fc9.i386.drpm</filename>
- *        <sequence>libtool-1.5.22-11.fc7-e82691677eee1e83b4812572c5c9ce8eb</sequence>
- *        <size>110362</size>
- *        <checksum type="sha">326658fee45c0baec1e70231046dbaf560f941ce</checksum>
- *      </delta>
- *    </newpackage>
- *  </deltainfo>
- */
-
-enum state {
-  STATE_START,
-  STATE_NEWPACKAGE,     /* 1 */
-  STATE_DELTA,          /* 2 */
-  STATE_FILENAME,       /* 3 */
-  STATE_SEQUENCE,       /* 4 */
-  STATE_SIZE,           /* 5 */
-  STATE_CHECKSUM,       /* 6 */
-  STATE_LOCATION,       /* 7 */
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
-  /* compatibility with old yum-presto */
-  { STATE_START,       "prestodelta",     STATE_START, 0 },
-  { STATE_START,       "deltainfo",       STATE_START, 0 },
-  { STATE_START,       "newpackage",      STATE_NEWPACKAGE,  0 },
-  { STATE_NEWPACKAGE,  "delta",           STATE_DELTA,       0 },
-  /* compatibility with yum-presto */
-  { STATE_DELTA,       "filename",        STATE_FILENAME,    1 },
-  { STATE_DELTA,       "location",        STATE_LOCATION,    0 },
-  { STATE_DELTA,       "sequence",        STATE_SEQUENCE,    1 },
-  { STATE_DELTA,       "size",            STATE_SIZE,        1 },
-  { STATE_DELTA,       "checksum",        STATE_CHECKSUM,    1 },
-  { NUMSTATES }
-};
-
-/* Cumulated info about the current deltarpm or patchrpm */
-struct deltarpm {
-  char *location;
-  char *locbase;
-  unsigned int buildtime;
-  unsigned long long downloadsize;
-  char *filechecksum;
-  int filechecksumtype;
-  /* Baseversion.  deltarpm only has one. */
-  Id *bevr;
-  unsigned nbevr;
-  Id seqname;
-  Id seqevr;
-  char *seqnum;
-};
-
-struct parsedata {
-  int ret;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  struct deltarpm delta;
-  Id newpkgevr;
-  Id newpkgname;
-  Id newpkgarch;
-
-  Id *handles;
-  int nhandles;
-};
-
-/*
- * find attribute
- */
-
-static const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-/*
- * create evr (as Id) from 'epoch', 'version' and 'release' attributes
- */
-
-static Id
-makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
-{
-  const char *e, *v, *r, *v2;
-  char *c;
-  int l;
-
-  e = v = r = 0;
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, "oldepoch"))
-        e = atts[1];
-      else if (!strcmp(*atts, "epoch"))
-       e = atts[1];
-      else if (!strcmp(*atts, "version"))
-       v = atts[1];
-      else if (!strcmp(*atts, "oldversion"))
-       v = atts[1];
-      else if (!strcmp(*atts, "release"))
-       r = atts[1];
-      else if (!strcmp(*atts, "oldrelease"))
-       r = atts[1];
-    }
-  if (e && (!*e || !strcmp(e, "0")))
-    e = 0;
-  if (v && !e)
-    {
-      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
-        ;
-      if (v2 > v && *v2 == ':')
-       e = "0";
-    }
-  l = 1;
-  if (e)
-    l += strlen(e) + 1;
-  if (v)
-    l += strlen(v);
-  if (r)
-    l += strlen(r) + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content;
-  if (e)
-    {
-      strcpy(c, e);
-      c += strlen(c);
-      *c++ = ':';
-    }
-  if (v)
-    {
-      strcpy(c, v);
-      c += strlen(c);
-    }
-  if (r)
-    {
-      *c++ = '-';
-      strcpy(c, r);
-      c += strlen(c);
-    }
-  *c = 0;
-  if (!*pd->content)
-    return 0;
-#if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
-#endif
-  return pool_str2id(pool, pd->content, 1);
-}
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  struct stateswitch *sw;
-  const char *str;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: [%d]%s (from: %d)\n", sw->to, name, sw->from);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_START:
-      break;
-    case STATE_NEWPACKAGE:
-      if ((str = find_attr("name", atts)) != 0)
-       pd->newpkgname = pool_str2id(pool, str, 1);
-      pd->newpkgevr = makeevr_atts(pool, pd, atts);
-      if ((str = find_attr("arch", atts)) != 0)
-       pd->newpkgarch = pool_str2id(pool, str, 1);
-      break;
-
-    case STATE_DELTA:
-      memset(&pd->delta, 0, sizeof(pd->delta));
-      pd->delta.bevr = solv_extend(pd->delta.bevr, pd->delta.nbevr, 1, sizeof(Id), 7);
-      pd->delta.bevr[pd->delta.nbevr++] = makeevr_atts(pool, pd, atts);
-      break;
-    case STATE_FILENAME:
-      if ((str = find_attr("xml:base", atts)))
-        pd->delta.locbase = solv_strdup(str);
-      break;
-    case STATE_LOCATION:
-      pd->delta.location = solv_strdup(find_attr("href", atts));
-      if ((str = find_attr("xml:base", atts)))
-        pd->delta.locbase = solv_strdup(str);
-      break;
-    case STATE_SIZE:
-      break;
-    case STATE_CHECKSUM:
-      pd->delta.filechecksum = 0;
-      pd->delta.filechecksumtype = REPOKEY_TYPE_SHA1;
-      if ((str = find_attr("type", atts)) != 0)
-       {
-         pd->delta.filechecksumtype = solv_chksum_str2type(str);
-         if (!pd->delta.filechecksumtype)
-           pool_debug(pool, SOLV_ERROR, "unknown checksum type: '%s'\n", str);
-       }
-      break;
-    case STATE_SEQUENCE:
-      break;
-    default:
-      break;
-    }
-}
-
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  const char *str;
-
-#if 0
-  fprintf(stderr, "end: %s\n", name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
-    {
-    case STATE_START:
-      break;
-    case STATE_NEWPACKAGE:
-      break;
-    case STATE_DELTA:
-      {
-       /* read all data for a deltarpm. commit into attributes */
-       Id handle;
-       struct deltarpm *d = &pd->delta;
-
-       handle = repodata_new_handle(pd->data);
-       /* we commit all handles later on in one go so that the
-         * repodata code doesn't need to realloc every time */
-       pd->handles = solv_extend(pd->handles, pd->nhandles, 1, sizeof(Id), 63);
-        pd->handles[pd->nhandles++] = handle;
-       repodata_set_id(pd->data, handle, DELTA_PACKAGE_NAME, pd->newpkgname);
-       repodata_set_id(pd->data, handle, DELTA_PACKAGE_EVR, pd->newpkgevr);
-       repodata_set_id(pd->data, handle, DELTA_PACKAGE_ARCH, pd->newpkgarch);
-       if (d->location)
-         {
-           repodata_set_deltalocation(pd->data, handle, 0, 0, d->location);
-           if (d->locbase)
-             repodata_set_poolstr(pd->data, handle, DELTA_LOCATION_BASE, d->locbase);
-         }
-       if (d->downloadsize)
-         repodata_set_num(pd->data, handle, DELTA_DOWNLOADSIZE, d->downloadsize);
-       if (d->filechecksum)
-         repodata_set_checksum(pd->data, handle, DELTA_CHECKSUM, d->filechecksumtype, d->filechecksum);
-       if (d->seqnum)
-         {
-           repodata_set_id(pd->data, handle, DELTA_BASE_EVR, d->bevr[0]);
-           repodata_set_id(pd->data, handle, DELTA_SEQ_NAME, d->seqname);
-           repodata_set_id(pd->data, handle, DELTA_SEQ_EVR, d->seqevr);
-           /* should store as binary blob! */
-           repodata_set_str(pd->data, handle, DELTA_SEQ_NUM, d->seqnum);
-         }
-      }
-      pd->delta.filechecksum = solv_free(pd->delta.filechecksum);
-      pd->delta.bevr = solv_free(pd->delta.bevr);
-      pd->delta.nbevr = 0;
-      pd->delta.seqnum = solv_free(pd->delta.seqnum);
-      pd->delta.location = solv_free(pd->delta.location);
-      pd->delta.locbase = solv_free(pd->delta.locbase);
-      break;
-    case STATE_FILENAME:
-      pd->delta.location = solv_strdup(pd->content);
-      break;
-    case STATE_CHECKSUM:
-      pd->delta.filechecksum = solv_strdup(pd->content);
-      break;
-    case STATE_SIZE:
-      pd->delta.downloadsize = strtoull(pd->content, 0, 10);
-      break;
-    case STATE_SEQUENCE:
-      if ((str = pd->content))
-       {
-         const char *s1, *s2;
-         s1 = strrchr(str, '-');
-         if (s1)
-           {
-             for (s2 = s1 - 1; s2 > str; s2--)
-               if (*s2 == '-')
-                 break;
-             if (*s2 == '-')
-               {
-                 for (s2 = s2 - 1; s2 > str; s2--)
-                   if (*s2 == '-')
-                     break;
-                 if (*s2 == '-')
-                   {
-                     pd->delta.seqevr = pool_strn2id(pool, s2 + 1, s1 - s2 - 1, 1);
-                     pd->delta.seqname = pool_strn2id(pool, str, s2 - str, 1);
-                     str = s1 + 1;
-                   }
-               }
-           }
-         pd->delta.seqnum = solv_strdup(str);
-      }
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-int
-repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  Repodata *data;
-  XML_Parser parser;
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-  pd.pool = pool;
-  pd.repo = repo;
-  pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  solv_free(pd.content);
-
-  /* now commit all handles */
-  if (!pd.ret)
-    for (i = 0; i < pd.nhandles; i++)
-      repodata_add_flexarray(pd.data, SOLVID_META, REPOSITORY_DELTAINFO, pd.handles[i]);
-  solv_free(pd.handles);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return pd.ret;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/ext/repo_deltainfoxml.h b/libsolv-0.6.15/ext/repo_deltainfoxml.h
deleted file mode 100644 (file)
index 6647b15..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.6.15/ext/repo_haiku.cpp b/libsolv-0.6.15/ext/repo_haiku.cpp
deleted file mode 100644 (file)
index a624df1..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2011-2013, Ingo Weinhold <ingo_weinhold@gmx.de>
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <package/PackageInfo.h>
-#include <package/PackageInfoSet.h>
-#include <package/PackageRoster.h>
-#include <package/PackageVersion.h>
-#include <package/RepositoryCache.h>
-#include <package/RepositoryConfig.h>
-
-#include "repo_haiku.h"
-
-using namespace BPackageKit;
-using namespace BPackageKit::BHPKG;
-
-static void add_dependency(Repo *repo, Offset &dependencies, const char *name,
-  const char *version, int flags, const char* compatVersion = NULL)
-{
-  Pool *pool = repo->pool;
-
-  Id dependency = pool_str2id(pool, name, 1);
-
-  if (version && version[0] != '\0')
-  {
-    Id versionId = pool_str2id(pool, version, 1);
-
-    if (compatVersion && compatVersion[0] != '\0')
-      {
-        versionId = pool_rel2id(pool, versionId, pool_str2id(pool, compatVersion, 1),
-          REL_COMPAT, 1);
-      }
-
-    dependency = pool_rel2id(pool, dependency, versionId, flags, 1);
-  }
-
-  dependencies = repo_addid_dep(repo, dependencies, dependency, 0);
-}
-
-static void add_dependency(Repo *repo, Offset &dependencies, const char *name,
-  const BPackageVersion &version, int flags)
-{
-  add_dependency(repo, dependencies, name, version.ToString(),
-    flags);
-}
-
-static void add_resolvables(Repo *repo, Offset &dependencies,
-  const BObjectList<BPackageResolvable> &resolvables)
-{
-  for (int32 i = 0; BPackageResolvable *resolvable = resolvables.ItemAt(i); i++)
-    {
-      add_dependency(repo, dependencies, resolvable->Name(),
-        resolvable->Version().ToString(), REL_EQ,
-        resolvable->CompatibleVersion().ToString());
-    }
-}
-
-static void add_resolvable_expressions(Repo *repo, Offset &dependencies,
-  const BObjectList<BPackageResolvableExpression> &expressions)
-{
-  for (int32 i = 0;
-    BPackageResolvableExpression *expression = expressions.ItemAt(i); i++)
-    {
-      // It is possible that no version is specified. In that case any version
-      // is acceptable.
-      if (expression->Version().InitCheck() != B_OK)
-        {
-          BPackageVersion version;
-          add_dependency(repo, dependencies, expression->Name(), NULL, 0);
-          continue;
-        }
-
-      int flags = 0;
-      switch (expression->Operator())
-        {
-          case B_PACKAGE_RESOLVABLE_OP_LESS:
-            flags |= REL_LT;
-            break;
-          case B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL:
-            flags |= REL_LT | REL_EQ;
-            break;
-          case B_PACKAGE_RESOLVABLE_OP_EQUAL:
-            flags |= REL_EQ;
-            break;
-          case B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL:
-            break;
-          case B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL:
-            flags |= REL_GT | REL_EQ;
-            break;
-          case B_PACKAGE_RESOLVABLE_OP_GREATER:
-              flags |= REL_GT;
-            break;
-        }
-
-      add_dependency(repo, dependencies, expression->Name(),
-        expression->Version(), flags);
-    }
-}
-
-static void add_replaces_list(Repo *repo, Offset &dependencies,
-  const BStringList &packageNames)
-{
-  int32 count = packageNames.CountStrings();
-  for (int32 i = 0; i < count; i++)
-    {
-      const BString &packageName = packageNames.StringAt(i);
-      add_dependency(repo, dependencies, packageName, BPackageVersion(), 0);
-    }
-}
-
-static Id add_package_info_to_repo(Repo *repo, Repodata *repoData,
-  const BPackageInfo &packageInfo)
-{
-  Pool *pool = repo->pool;
-
-  Id solvableId = repo_add_solvable(repo);
-  Solvable *solvable = pool_id2solvable(pool, solvableId);
-  // Prepend "pkg:" to package name, so "provides" don't match unless explicitly
-  // specified this way.
-  BString name("pkg:");
-  name << packageInfo.Name();
-  solvable->name = pool_str2id(pool, name, 1);
-  if (packageInfo.Architecture() == B_PACKAGE_ARCHITECTURE_ANY)
-    solvable->arch = ARCH_ANY;
-  else if (packageInfo.Architecture() == B_PACKAGE_ARCHITECTURE_SOURCE)
-    solvable->arch = ARCH_SRC;
-  else
-    solvable->arch = pool_str2id(pool,
-      BPackageInfo::kArchitectureNames[packageInfo.Architecture()], 1);
-  solvable->evr = pool_str2id(pool, packageInfo.Version().ToString(), 1);
-  solvable->vendor = pool_str2id(pool, packageInfo.Vendor(), 1);
-  repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_SUMMARY,
-    packageInfo.Summary());
-  repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_DESCRIPTION,
-    packageInfo.Description());
-  repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_PACKAGER,
-    packageInfo.Packager());
-
-  if (!packageInfo.Checksum().IsEmpty())
-    repodata_set_checksum(repoData, solvable - pool->solvables,
-      SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, packageInfo.Checksum());
-
-  solvable->provides = repo_addid_dep(repo, solvable->provides,
-    pool_rel2id(pool, solvable->name, solvable->evr, REL_EQ, 1), 0);
-
-  add_resolvables(repo, solvable->provides, packageInfo.ProvidesList());
-  add_resolvable_expressions(repo, solvable->requires,
-    packageInfo.RequiresList());
-  add_resolvable_expressions(repo, solvable->supplements,
-    packageInfo.SupplementsList());
-  add_resolvable_expressions(repo, solvable->conflicts,
-    packageInfo.ConflictsList());
-  add_resolvable_expressions(repo, solvable->enhances,
-    packageInfo.FreshensList());
-  add_replaces_list(repo, solvable->obsoletes, packageInfo.ReplacesList());
-  // TODO: Check whether freshens and replaces does indeed work as intended
-  // here.
-
-  // TODO: copyrights, licenses, URLs, source URLs
-
-  return solvableId;
-}
-
-static void add_installed_packages(Repo *repo, Repodata *repoData,
-  BPackageInstallationLocation location)
-{
-  BPackageRoster roster;
-  BPackageInfoSet packageInfos;
-  if (roster.GetActivePackages(location, packageInfos) == B_OK)
-    {
-      BRepositoryCache::Iterator it = packageInfos.GetIterator();
-      while (const BPackageInfo *packageInfo = it.Next())
-        add_package_info_to_repo(repo, repoData, *packageInfo);
-    }
-}
-
-int repo_add_haiku_installed_packages(Repo *repo, const char *rootdir,
-  int flags)
-{
-  Repodata *repoData = repo_add_repodata(repo, flags);
-
-  add_installed_packages(repo, repoData,
-    B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
-  add_installed_packages(repo, repoData, B_PACKAGE_INSTALLATION_LOCATION_HOME);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(repoData);
-
-  return 0;
-}
-
-Id repo_add_haiku_package(Repo *repo, const char *hpkgPath, int flags)
-{
-  BPackageInfo packageInfo;
-  if (packageInfo.ReadFromPackageFile(hpkgPath) != B_OK)
-    return 0;
-
-  return repo_add_haiku_package_info(repo, packageInfo, flags);
-}
-
-int repo_add_haiku_packages(Repo *repo, const char *repoName, int flags)
-{
-  BPackageRoster roster;
-  BRepositoryCache cache;
-  if (roster.GetRepositoryCache(repoName, &cache) != B_OK)
-    return 0;
-
-  Repodata *repoData = repo_add_repodata(repo, flags);
-
-  BRepositoryCache::Iterator it = cache.GetIterator();
-  while (const BPackageInfo *packageInfo = it.Next())
-    add_package_info_to_repo(repo, repoData, *packageInfo);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(repoData);
-
-  return 0;
-}
-
-Id repo_add_haiku_package_info(Repo *repo,
-  const BPackageKit::BPackageInfo &packageInfo, int flags)
-{
-  if (packageInfo.InitCheck() != B_OK)
-    return 0;
-  
-  Repodata *repoData = repo_add_repodata(repo, flags);
-
-  Id id = add_package_info_to_repo(repo, repoData, packageInfo);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(repoData);
-
-  return id;
-}
diff --git a/libsolv-0.6.15/ext/repo_haiku.h b/libsolv-0.6.15/ext/repo_haiku.h
deleted file mode 100644 (file)
index 6770666..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2011-2013, Ingo Weinhold <ingo_weinhold@gmx.de>
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-#ifndef REPO_HAIKU_H
-#define REPO_HAIKU_H
-
-#include "repo.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int repo_add_haiku_installed_packages(Repo *repo, const char *rootdir,
-  int flags);
-Id repo_add_haiku_package(Repo *repo, const char *hpkgPath, int flags);
-int repo_add_haiku_packages(Repo *repo, const char *repoName, int flags);
-
-#ifdef __cplusplus
-
-namespace BPackageKit {
-  class BPackageInfo;
-}
-
-Id repo_add_haiku_package_info(Repo *repo,
-  const BPackageKit::BPackageInfo &packageInfo, int flags);
-
-} /* extern "C" */
-
-#endif /*__cplusplus*/
-
-#endif /* REPO_HAIKU_H */
diff --git a/libsolv-0.6.15/ext/repo_helix.c b/libsolv-0.6.15/ext/repo_helix.c
deleted file mode 100644 (file)
index f495be7..0000000
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_helix.c
- *
- * Parse 'helix' XML representation
- * and create 'repo'
- *
- * A bit of history: "Helix Code" was the name of the company that
- * wrote Red Carpet. The company was later renamed to Ximian.
- * The Red Carpet solver was merged into the ZYPP project, the
- * library used both by ZENworks and YaST for package management.
- * Red Carpet came with solver testcases in its own repository
- * format, the 'helix' format.
- *
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <expat.h>
-
-#include "repo_helix.h"
-#include "evr.h"
-
-
-/* XML parser states */
-
-enum state {
-  STATE_START,
-  STATE_CHANNEL,
-  STATE_SUBCHANNEL,
-  STATE_PACKAGE,
-  STATE_NAME,
-  STATE_VENDOR,
-  STATE_BUILDTIME,
-  STATE_HISTORY,
-  STATE_UPDATE,
-  STATE_EPOCH,
-  STATE_VERSION,
-  STATE_RELEASE,
-  STATE_ARCH,
-  STATE_PROVIDES,
-  STATE_PROVIDESENTRY,
-  STATE_REQUIRES,
-  STATE_REQUIRESENTRY,
-  STATE_PREREQUIRES,
-  STATE_PREREQUIRESENTRY,
-  STATE_OBSOLETES,
-  STATE_OBSOLETESENTRY,
-  STATE_CONFLICTS,
-  STATE_CONFLICTSENTRY,
-  STATE_RECOMMENDS,
-  STATE_RECOMMENDSENTRY,
-  STATE_SUPPLEMENTS,
-  STATE_SUPPLEMENTSENTRY,
-  STATE_SUGGESTS,
-  STATE_SUGGESTSENTRY,
-  STATE_ENHANCES,
-  STATE_ENHANCESENTRY,
-  STATE_FRESHENS,
-  STATE_FRESHENSENTRY,
-
-  STATE_SELECTTION,
-  STATE_PATTERN,
-  STATE_ATOM,
-  STATE_PATCH,
-  STATE_PRODUCT,
-
-  STATE_PEPOCH,
-  STATE_PVERSION,
-  STATE_PRELEASE,
-  STATE_PARCH,
-
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-static struct stateswitch stateswitches[] = {
-  { STATE_START,       "channel",         STATE_CHANNEL, 0 },
-  { STATE_CHANNEL,     "subchannel",      STATE_SUBCHANNEL, 0 },
-  { STATE_SUBCHANNEL,  "package",         STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "srcpackage",      STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "selection",       STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "pattern",         STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "atom",            STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "patch",           STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "product",         STATE_PACKAGE, 0 },
-  { STATE_SUBCHANNEL,  "application",     STATE_PACKAGE, 0 },
-  { STATE_PACKAGE,     "name",            STATE_NAME, 1 },
-  { STATE_PACKAGE,     "vendor",          STATE_VENDOR, 1 },
-  { STATE_PACKAGE,     "buildtime",       STATE_BUILDTIME, 1 },
-  { STATE_PACKAGE,     "epoch",           STATE_PEPOCH, 1 },
-  { STATE_PACKAGE,     "version",         STATE_PVERSION, 1 },
-  { STATE_PACKAGE,     "release",         STATE_PRELEASE, 1 },
-  { STATE_PACKAGE,     "arch",            STATE_PARCH, 1 },
-  { STATE_PACKAGE,     "history",         STATE_HISTORY, 0 },
-  { STATE_PACKAGE,     "provides",        STATE_PROVIDES, 0 },
-  { STATE_PACKAGE,     "requires",        STATE_REQUIRES, 0 },
-  { STATE_PACKAGE,     "prerequires",     STATE_PREREQUIRES, 0 },
-  { STATE_PACKAGE,     "obsoletes",       STATE_OBSOLETES , 0 },
-  { STATE_PACKAGE,     "conflicts",       STATE_CONFLICTS , 0 },
-  { STATE_PACKAGE,     "recommends" ,     STATE_RECOMMENDS , 0 },
-  { STATE_PACKAGE,     "supplements",     STATE_SUPPLEMENTS, 0 },
-  { STATE_PACKAGE,     "suggests",        STATE_SUGGESTS, 0 },
-  { STATE_PACKAGE,     "enhances",        STATE_ENHANCES, 0 },
-  { STATE_PACKAGE,     "freshens",        STATE_FRESHENS, 0 },
-
-  { STATE_HISTORY,     "update",          STATE_UPDATE, 0 },
-  { STATE_UPDATE,      "epoch",           STATE_EPOCH, 1 },
-  { STATE_UPDATE,      "version",         STATE_VERSION, 1 },
-  { STATE_UPDATE,      "release",         STATE_RELEASE, 1 },
-  { STATE_UPDATE,      "arch",            STATE_ARCH, 1 },
-
-  { STATE_PROVIDES,    "dep",             STATE_PROVIDESENTRY, 0 },
-  { STATE_REQUIRES,    "dep",             STATE_REQUIRESENTRY, 0 },
-  { STATE_PREREQUIRES, "dep",             STATE_PREREQUIRESENTRY, 0 },
-  { STATE_OBSOLETES,   "dep",             STATE_OBSOLETESENTRY, 0 },
-  { STATE_CONFLICTS,   "dep",             STATE_CONFLICTSENTRY, 0 },
-  { STATE_RECOMMENDS,  "dep",             STATE_RECOMMENDSENTRY, 0 },
-  { STATE_SUPPLEMENTS, "dep",             STATE_SUPPLEMENTSENTRY, 0 },
-  { STATE_SUGGESTS,    "dep",             STATE_SUGGESTSENTRY, 0 },
-  { STATE_ENHANCES,    "dep",             STATE_ENHANCESENTRY, 0 },
-  { STATE_FRESHENS,    "dep",             STATE_FRESHENSENTRY, 0 },
-  { NUMSTATES }
-
-};
-
-/*
- * parser data
- */
-
-typedef struct _parsedata {
-  int ret;
-  /* XML parser data */
-  int depth;
-  enum state state;    /* current state */
-  int statedepth;
-  char *content;       /* buffer for content of node */
-  int lcontent;                /* actual length of current content */
-  int acontent;                /* actual buffer size */
-  int docontent;       /* handle content */
-
-  /* repo data */
-  Pool *pool;          /* current pool */
-  Repo *repo;          /* current repo */
-  Repodata *data;       /* current repo data */
-  Solvable *solvable;  /* current solvable */
-  Offset freshens;     /* current freshens vector */
-
-  /* package data */
-  int  epoch;          /* epoch (as offset into evrspace) */
-  int  version;                /* version (as offset into evrspace) */
-  int  release;                /* release (as offset into evrspace) */
-  char *evrspace;      /* buffer for evr */
-  int  aevrspace;      /* actual buffer space */
-  int  levrspace;      /* actual evr length */
-  char *kind;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-} Parsedata;
-
-
-/*------------------------------------------------------------------*/
-/* E:V-R handling */
-
-/* create Id from epoch:version-release */
-
-static Id
-evr2id(Pool *pool, Parsedata *pd, const char *e, const char *v, const char *r)
-{
-  char *c;
-  int l;
-
-  /* treat explitcit 0 as NULL */
-  if (e && (!*e || !strcmp(e, "0")))
-    e = 0;
-
-  if (v && !e)
-    {
-      const char *v2;
-      /* scan version for ":" */
-      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)     /* skip leading digits */
-        ;
-      /* if version contains ":", set epoch to "0" */
-      if (v2 > v && *v2 == ':')
-       e = "0";
-    }
-
-  /* compute length of Id string */
-  l = 1;  /* for the \0 */
-  if (e)
-    l += strlen(e) + 1;  /* e: */
-  if (v)
-    l += strlen(v);      /* v */
-  if (r)
-    l += strlen(r) + 1;  /* -r */
-
-  /* extend content if not sufficient */
-  if (l > pd->acontent)
-    {
-      pd->content = (char *)realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-
-  /* copy e-v-r to content */
-  c = pd->content;
-  if (e)
-    {
-      strcpy(c, e);
-      c += strlen(c);
-      *c++ = ':';
-    }
-  if (v)
-    {
-      strcpy(c, v);
-      c += strlen(c);
-    }
-  if (r)
-    {
-      *c++ = '-';
-      strcpy(c, r);
-      c += strlen(c);
-    }
-  *c = 0;
-  /* if nothing inserted, return Id 0 */
-  if (!*pd->content)
-    return ID_NULL;
-#if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
-#endif
-  /* intern and create */
-  return pool_str2id(pool, pd->content, 1);
-}
-
-
-/* create e:v-r from attributes
- * atts is array of name,value pairs, NULL at end
- *   even index into atts is name
- *   odd index is value
- */
-static Id
-evr_atts2id(Pool *pool, Parsedata *pd, const char **atts)
-{
-  const char *e, *v, *r;
-  e = v = r = 0;
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, "epoch"))
-       e = atts[1];
-      else if (!strcmp(*atts, "version"))
-       v = atts[1];
-      else if (!strcmp(*atts, "release"))
-       r = atts[1];
-    }
-  return evr2id(pool, pd, e, v, r);
-}
-
-/*------------------------------------------------------------------*/
-/* rel operator handling */
-
-struct flagtab {
-  char *from;
-  int to;
-};
-
-static struct flagtab flagtab[] = {
-  { ">",  REL_GT },
-  { "=",  REL_EQ },
-  { ">=", REL_GT|REL_EQ },
-  { "<",  REL_LT },
-  { "!=", REL_GT|REL_LT },
-  { "<=", REL_LT|REL_EQ },
-  { "(any)", REL_LT|REL_EQ|REL_GT },
-  { "==", REL_EQ },
-  { "gt", REL_GT },
-  { "eq", REL_EQ },
-  { "ge", REL_GT|REL_EQ },
-  { "lt", REL_LT },
-  { "ne", REL_GT|REL_LT },
-  { "le", REL_LT|REL_EQ },
-  { "gte", REL_GT|REL_EQ },
-  { "lte", REL_LT|REL_EQ },
-  { "GT", REL_GT },
-  { "EQ", REL_EQ },
-  { "GE", REL_GT|REL_EQ },
-  { "LT", REL_LT },
-  { "NE", REL_GT|REL_LT },
-  { "LE", REL_LT|REL_EQ }
-};
-
-/*
- * process new dependency from parser
- *  olddeps = already collected deps, this defines the 'kind' of dep
- *  atts = array of name,value attributes of dep
- *  isreq == 1 if its a requires
- */
-
-static unsigned int
-adddep(Pool *pool, Parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
-{
-  Id id, name;
-  const char *n, *f, *k;
-  const char **a;
-
-  n = f = k = NULL;
-
-  /* loop over name,value pairs */
-  for (a = atts; *a; a += 2)
-    {
-      if (!strcmp(*a, "name"))
-       n = a[1];
-      if (!strcmp(*a, "kind"))
-       k = a[1];
-      else if (!strcmp(*a, "op"))
-       f = a[1];
-      else if (marker && !strcmp(*a, "pre") && a[1][0] == '1')
-        marker = SOLVABLE_PREREQMARKER;
-    }
-  if (!n)                             /* quit if no name found */
-    return olddeps;
-
-  /* kind, name */
-  if (k && !strcmp(k, "package"))
-    k = NULL;                         /* package is default */
-
-  if (k)                              /* if kind!=package, intern <kind>:<name> */
-    {
-      int l = strlen(k) + 1 + strlen(n) + 1;
-      if (l > pd->acontent)           /* extend buffer if needed */
-       {
-         pd->content = (char *)realloc(pd->content, l + 256);
-         pd->acontent = l + 256;
-       }
-      sprintf(pd->content, "%s:%s", k, n);
-      name = pool_str2id(pool, pd->content, 1);
-    }
-  else
-    {
-      name = pool_str2id(pool, n, 1);       /* package: just intern <name> */
-    }
-
-  if (f)                              /* operator ? */
-    {
-      /* intern e:v-r */
-      Id evr = evr_atts2id(pool, pd, atts);
-      /* parser operator to flags */
-      int flags;
-      for (flags = 0; flags < sizeof(flagtab)/sizeof(*flagtab); flags++)
-       if (!strcmp(f, flagtab[flags].from))
-         {
-           flags = flagtab[flags].to;
-           break;
-         }
-      if (flags > 7)
-       flags = 0;
-      /* intern rel */
-      id = pool_rel2id(pool, name, evr, flags, 1);
-    }
-  else
-    id = name;                        /* no operator */
-
-  /* add new dependency to repo */
-  return repo_addid_dep(pd->repo, olddeps, id, marker);
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * XML callback
- * <name>
- *
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  Parsedata *pd = (Parsedata *)userData;
-  struct stateswitch *sw;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  /* ignore deps element */
-  if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
-    return;
-
-  pd->depth++;
-
-  /* find node name in stateswitch */
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
-  {
-    if (!strcmp(sw->ename, name))
-      break;
-  }
-
-  /* check if we're at the right level */
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s\n", name);
-#endif
-      return;
-    }
-
-  /* set new state */
-  pd->state = sw->to;
-
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-
-  /* start with empty content */
-  /* (will collect data until end element) */
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch (pd->state)
-    {
-
-    case STATE_NAME:
-      if (pd->kind)                   /* if kind is set (non package) */
-        {
-          strcpy(pd->content, pd->kind);
-          pd->lcontent = strlen(pd->content);
-         pd->content[pd->lcontent++] = ':';   /* prefix name with '<kind>:' */
-         pd->content[pd->lcontent] = 0;
-       }
-      break;
-
-    case STATE_PACKAGE:                       /* solvable name */
-      pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-      if (!strcmp(name, "selection"))
-        pd->kind = "selection";
-      else if (!strcmp(name, "pattern"))
-        pd->kind = "pattern";
-      else if (!strcmp(name, "atom"))
-        pd->kind = "atom";
-      else if (!strcmp(name, "product"))
-        pd->kind = "product";
-      else if (!strcmp(name, "patch"))
-        pd->kind = "patch";
-      else if (!strcmp(name, "application"))
-        pd->kind = "application";
-      else
-        pd->kind = NULL;              /* default is package */
-      pd->levrspace = 1;
-      pd->epoch = 0;
-      pd->version = 0;
-      pd->release = 0;
-      pd->freshens = 0;
-#if 0
-      fprintf(stderr, "package #%d\n", s - pool->solvables);
-#endif
-      break;
-
-    case STATE_UPDATE:
-      pd->levrspace = 1;
-      pd->epoch = 0;
-      pd->version = 0;
-      pd->release = 0;
-      break;
-
-    case STATE_PROVIDES:              /* start of provides */
-      s->provides = 0;
-      break;
-    case STATE_PROVIDESENTRY:         /* entry within provides */
-      s->provides = adddep(pool, pd, s->provides, atts, 0);
-      break;
-    case STATE_REQUIRESENTRY:
-      s->requires = adddep(pool, pd, s->requires, atts, -SOLVABLE_PREREQMARKER);
-      break;
-    case STATE_PREREQUIRESENTRY:
-      s->requires = adddep(pool, pd, s->requires, atts, SOLVABLE_PREREQMARKER);
-      break;
-    case STATE_OBSOLETES:
-      s->obsoletes = 0;
-      break;
-    case STATE_OBSOLETESENTRY:
-      s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
-      break;
-    case STATE_CONFLICTS:
-      s->conflicts = 0;
-      break;
-    case STATE_CONFLICTSENTRY:
-      s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
-      break;
-    case STATE_RECOMMENDS:
-      s->recommends = 0;
-      break;
-    case STATE_RECOMMENDSENTRY:
-      s->recommends = adddep(pool, pd, s->recommends, atts, 0);
-      break;
-    case STATE_SUPPLEMENTS:
-      s->supplements= 0;
-      break;
-    case STATE_SUPPLEMENTSENTRY:
-      s->supplements = adddep(pool, pd, s->supplements, atts, 0);
-      break;
-    case STATE_SUGGESTS:
-      s->suggests = 0;
-      break;
-    case STATE_SUGGESTSENTRY:
-      s->suggests = adddep(pool, pd, s->suggests, atts, 0);
-      break;
-    case STATE_ENHANCES:
-      s->enhances = 0;
-      break;
-    case STATE_ENHANCESENTRY:
-      s->enhances = adddep(pool, pd, s->enhances, atts, 0);
-      break;
-    case STATE_FRESHENS:
-      pd->freshens = 0;
-      break;
-    case STATE_FRESHENSENTRY:
-      pd->freshens = adddep(pool, pd, pd->freshens, atts, 0);
-      break;
-    default:
-      break;
-    }
-}
-
-static const char *findKernelFlavor(Parsedata *pd, Solvable *s)
-{
-  Pool *pool = pd->pool;
-  Id pid, *pidp;
-
-  if (s->provides)
-    {
-      pidp = pd->repo->idarraydata + s->provides;
-      while ((pid = *pidp++) != 0)
-       {
-         Reldep *prd;
-         const char *depname;
-
-         if (!ISRELDEP(pid))
-           continue;               /* wrong provides name */
-         prd = GETRELDEP(pool, pid);
-         depname = pool_id2str(pool, prd->name);
-         if (!strncmp(depname, "kernel-", 7))
-           return depname + 7;
-       }
-    }
-
-  if (s->requires)
-    {
-      pidp = pd->repo->idarraydata + s->requires;
-      while ((pid = *pidp++) != 0)
-       {
-         const char *depname;
-
-         if (!ISRELDEP(pid))
-           {
-             depname = pool_id2str(pool, pid);
-           }
-         else
-           {
-             Reldep *prd = GETRELDEP(pool, pid);
-             depname = pool_id2str(pool, prd->name);
-           }
-         if (!strncmp(depname, "kernel-", 7))
-           return depname + 7;
-       }
-    }
-
-  return 0;
-}
-
-
-/*
- * XML callback
- * </name>
- *
- * create Solvable from collected data
- */
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  Parsedata *pd = (Parsedata *)userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  Id evr;
-  unsigned int t = 0;
-  const char *flavor;
-
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-      /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
-      return;
-    }
-
-  /* ignore deps element */
-  if (pd->state == STATE_PACKAGE && !strcmp(name, "deps"))
-    return;
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
-    {
-
-    case STATE_PACKAGE:                       /* package complete */
-      if (name[0] == 's' && name[1] == 'r' && name[2] == 'c' && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-       s->arch = ARCH_SRC;
-      if (!s->arch)                    /* default to "noarch" */
-       s->arch = ARCH_NOARCH;
-
-      if (!s->evr && pd->version)      /* set solvable evr */
-        s->evr = evr2id(pool, pd,
-                        pd->epoch   ? pd->evrspace + pd->epoch   : 0,
-                        pd->version ? pd->evrspace + pd->version : 0,
-                        pd->release ? pd->evrspace + pd->release : 0);
-      /* ensure self-provides */
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-        s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-      s->supplements = repo_fix_supplements(pd->repo, s->provides, s->supplements, pd->freshens);
-      s->conflicts = repo_fix_conflicts(pd->repo, s->conflicts);
-      pd->freshens = 0;
-
-      /* see bugzilla bnc#190163 */
-      flavor = findKernelFlavor(pd, s);
-      if (flavor)
-       {
-         char *cflavor = solv_strdup(flavor);  /* make pointer safe */
-
-         Id npr;
-         Id pid;
-
-         /* this is either a kernel package or a kmp */
-         if (s->provides)
-           {
-             Offset prov = s->provides;
-             npr = 0;
-             while ((pid = pd->repo->idarraydata[prov++]) != 0)
-               {
-                 const char *depname = 0;
-                 Reldep *prd = 0;
-
-                 if (ISRELDEP(pid))
-                   {
-                     prd = GETRELDEP(pool, pid);
-                     depname = pool_id2str(pool, prd->name);
-                   }
-                 else
-                   {
-                     depname = pool_id2str(pool, pid);
-                   }
-
-
-                 if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
-                   {
-                     char newdep[100];
-                     snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
-                     pid = pool_str2id(pool, newdep, 1);
-                     if (prd)
-                       pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
-                   }
-
-                 npr = repo_addid_dep(pd->repo, npr, pid, 0);
-               }
-             s->provides = npr;
-           }
-#if 1
-
-         if (s->requires)
-           {
-             Offset reqs = s->requires;
-             npr = 0;
-             while ((pid = pd->repo->idarraydata[reqs++]) != 0)
-               {
-                 const char *depname = 0;
-                 Reldep *prd = 0;
-
-                 if (ISRELDEP(pid))
-                   {
-                     prd = GETRELDEP(pool, pid);
-                     depname = pool_id2str(pool, prd->name);
-                   }
-                 else
-                   {
-                     depname = pool_id2str(pool, pid);
-                   }
-
-                 if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
-                   {
-                     char newdep[100];
-                     snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
-                     pid = pool_str2id(pool, newdep, 1);
-                     if (prd)
-                       pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
-                   }
-                 npr = repo_addid_dep(pd->repo, npr, pid, 0);
-               }
-             s->requires = npr;
-           }
-#endif
-         free(cflavor);
-       }
-      break;
-    case STATE_NAME:
-      s->name = pool_str2id(pool, pd->content, 1);
-      break;
-    case STATE_VENDOR:
-      s->vendor = pool_str2id(pool, pd->content, 1);
-      break;
-    case STATE_BUILDTIME:
-      t = atoi (pd->content);
-      if (t)
-       repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
-      break;   
-    case STATE_UPDATE:                /* new version, keeping all other metadata */
-      evr = evr2id(pool, pd,
-                   pd->epoch   ? pd->evrspace + pd->epoch   : 0,
-                   pd->version ? pd->evrspace + pd->version : 0,
-                   pd->release ? pd->evrspace + pd->release : 0);
-      pd->levrspace = 1;
-      pd->epoch = 0;
-      pd->version = 0;
-      pd->release = 0;
-      /* use highest evr */
-      if (!s->evr || pool_evrcmp(pool, s->evr, evr, EVRCMP_COMPARE) <= 0)
-       s->evr = evr;
-      break;
-    case STATE_EPOCH:
-    case STATE_VERSION:
-    case STATE_RELEASE:
-    case STATE_PEPOCH:
-    case STATE_PVERSION:
-    case STATE_PRELEASE:
-      /* ensure buffer space */
-      if (pd->lcontent + 1 + pd->levrspace > pd->aevrspace)
-       {
-         pd->evrspace = (char *)realloc(pd->evrspace, pd->lcontent + 1 + pd->levrspace + 256);
-         pd->aevrspace = pd->lcontent + 1 + pd->levrspace + 256;
-       }
-      memcpy(pd->evrspace + pd->levrspace, pd->content, pd->lcontent + 1);
-      if (pd->state == STATE_EPOCH || pd->state == STATE_PEPOCH)
-       pd->epoch = pd->levrspace;
-      else if (pd->state == STATE_VERSION || pd->state == STATE_PVERSION)
-       pd->version = pd->levrspace;
-      else
-       pd->release = pd->levrspace;
-      pd->levrspace += pd->lcontent + 1;
-      break;
-    case STATE_ARCH:
-    case STATE_PARCH:
-      s->arch = pool_str2id(pool, pd->content, 1);
-      break;
-    default:
-      break;
-    }
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-  /* printf("back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
-}
-
-
-/*
- * XML callback
- * character data
- *
- */
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  Parsedata *pd = (Parsedata *)userData;
-  int l;
-  char *c;
-
-  /* check if current nodes content is interesting */
-  if (!pd->docontent)
-    return;
-
-  /* adapt content buffer */
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = (char *)realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  /* append new content to buffer */
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-/*-------------------------------------------------------------------*/
-
-#define BUFF_SIZE 8192
-
-/*
- * read 'helix' type xml from fp
- * add packages to pool/repo
- *
- */
-
-int
-repo_add_helix(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  Parsedata pd;
-  Repodata *data;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  unsigned int now;
-  XML_Parser parser;
-
-  now = solv_timems(0);
-  data = repo_add_repodata(repo, flags);
-
-  /* prepare parsedata */
-  memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  pd.pool = pool;
-  pd.repo = repo;
-
-  pd.content = (char *)malloc(256);    /* must hold all solvable kinds! */
-  pd.acontent = 256;
-  pd.lcontent = 0;
-
-  pd.evrspace = (char *)malloc(256);
-  pd.aevrspace= 256;
-  pd.levrspace = 1;
-  pd.data = data;
-
-  /* set up XML parser */
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);       /* make parserdata available to XML callbacks */
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-
-  /* read/parse XML file */
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "%s at line %u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  free(pd.content);
-  free(pd.evrspace);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_helix took %d ms\n", solv_timems(now));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
-  return pd.ret;
-}
diff --git a/libsolv-0.6.15/ext/repo_helix.h b/libsolv-0.6.15/ext/repo_helix.h
deleted file mode 100644 (file)
index d883dd9..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_helix.h
- * 
- */
-
-#ifndef LIBSOLV_REPO_HELIX_H
-#define LIBSOLV_REPO_HELIX_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-#include "pool.h"
-#include "repo.h"
-
-extern int repo_add_helix(Repo *repo, FILE *fp, int flags);
-
-#ifdef __cplusplus
-}
-#endif
-    
-
-#endif /* LIBSOLV_REPO_HELIX_H */
diff --git a/libsolv-0.6.15/ext/repo_mdk.c b/libsolv-0.6.15/ext/repo_mdk.c
deleted file mode 100644 (file)
index 345d416..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <expat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "chksum.h"
-#include "repo_mdk.h"
-
-static Offset
-parse_deps(Solvable *s, char *bp, Id marker)
-{
-  Pool *pool = s->repo->pool;
-  Offset deps = 0;
-  char *nbp, *ebp;
-  for (; bp; bp = nbp)
-    {
-      int ispre = 0;
-      Id id, evr = 0;
-      int flags = 0;
-
-      nbp = strchr(bp, '@');
-      if (!nbp)
-       ebp = bp + strlen(bp);
-      else
-       {
-         ebp = nbp;
-         *nbp++ = 0;
-       }
-      if (ebp[-1] == ']')
-       {
-         char *sbp = ebp - 1;
-         while (sbp >= bp && *sbp != '[')
-           sbp--;
-         if (sbp >= bp && sbp[1] != '*')
-           {
-             char *fbp;
-             for (fbp = sbp + 1;; fbp++)
-               {
-                 if (*fbp == '>')
-                   flags |= REL_GT;
-                 else if (*fbp == '=')
-                   flags |= REL_EQ;
-                 else if (*fbp == '<')
-                   flags |= REL_LT;
-                 else
-                   break;
-               }
-             if (*fbp == ' ')
-               fbp++;
-             evr = pool_strn2id(pool, fbp, ebp - 1 - fbp, 1);
-             ebp = sbp;
-           }
-       }
-      if (ebp[-1] == ']' && ebp >= bp + 3 && !strncmp(ebp - 3, "[*]", 3))
-       {
-         ispre = 1;
-         ebp -= 3;
-       }
-      id = pool_strn2id(pool, bp, ebp - bp, 1);
-      if (evr)
-       id = pool_rel2id(pool, id, evr, flags, 1);
-      deps = repo_addid_dep(s->repo, deps, id, ispre ? marker : 0);
-      bp = nbp;
-    }
-  return deps;
-}
-
-int
-repo_add_mdk(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  Solvable *s;
-  char *buf;
-  int bufa, bufl;
-
-  data = repo_add_repodata(repo, flags);
-  bufa = 4096;
-  buf = solv_malloc(bufa);
-  bufl = 0;
-  s = 0;
-  while (fgets(buf + bufl, bufa - bufl, fp) > 0)
-    {
-      bufl += strlen(buf + bufl);
-      if (!bufl)
-       continue;
-      if (buf[bufl - 1] != '\n')
-       {
-         if (bufa - bufl < 256)
-           {
-             bufa += 4096;
-             buf = solv_realloc(buf, bufa);
-           }
-         continue;
-       }
-      buf[bufl - 1] = 0;
-      bufl = 0;
-      if (buf[0] != '@')
-       {
-         pool_debug(pool, SOLV_ERROR, "bad line <%s>\n", buf);
-         continue;
-       }
-      if (!s)
-       s = pool_id2solvable(pool, repo_add_solvable(repo));
-      if (!strncmp(buf + 1, "filesize@", 9))
-       repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(buf + 10, 0, 10));
-      else if (!strncmp(buf + 1, "summary@", 8))
-       repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, buf + 9);
-      else if (!strncmp(buf + 1, "provides@", 9))
-       s->provides = parse_deps(s, buf + 10, 0);
-      else if (!strncmp(buf + 1, "requires@", 9))
-       s->requires = parse_deps(s, buf + 10, SOLVABLE_PREREQMARKER);
-      else if (!strncmp(buf + 1, "recommends@", 11))
-       s->recommends = parse_deps(s, buf + 10, 0);
-      else if (!strncmp(buf + 1, "suggests@", 9))
-       s->suggests = parse_deps(s, buf + 10, 0);
-      else if (!strncmp(buf + 1, "obsoletes@", 10))
-       s->obsoletes = parse_deps(s, buf + 11, 0);
-      else if (!strncmp(buf + 1, "conflicts@", 10))
-       s->conflicts = parse_deps(s, buf + 11, 0);
-      else if (!strncmp(buf + 1, "info@", 5))
-       {
-         char *nvra = buf + 6;
-         char *epochstr;
-         char *arch;
-         char *version;
-         char *filename;
-         char *disttag = 0;
-         char *distepoch = 0;
-         if ((epochstr = strchr(nvra, '@')) != 0)
-           {
-             char *sizestr;
-             *epochstr++ = 0;
-             if ((sizestr = strchr(epochstr, '@')) != 0)
-               {
-                 char *groupstr;
-                 *sizestr++ = 0;
-                 if ((groupstr = strchr(sizestr, '@')) != 0)
-                   {
-                     *groupstr++ = 0;
-                     if ((disttag = strchr(groupstr, '@')) != 0)
-                       {
-                         *disttag++ = 0;
-                         if ((distepoch = strchr(disttag, '@')) != 0)
-                           {
-                             char *n;
-                             *distepoch++ = 0;
-                             if ((n = strchr(distepoch, '@')) != 0)
-                               *n = 0;
-                           }
-                       }
-                     if (*groupstr)
-                       repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, groupstr);
-                   }
-                 if (*sizestr)
-                   repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(sizestr, 0, 10));
-               }
-           }
-          filename = pool_tmpjoin(pool, nvra, ".rpm", 0);
-         arch = strrchr(nvra, '.');
-         if (arch)
-           {
-             *arch++ = 0;
-             s->arch = pool_str2id(pool, arch, 1);
-           }
-         if (disttag && *disttag)
-           {
-             /* strip disttag from release */
-             char *n = strrchr(nvra, '-');
-             if (n && !strncmp(n + 1, disttag, strlen(disttag)))
-               *n = 0;
-           }
-         if (distepoch && *distepoch)
-           {
-             /* add distepoch */
-             int le = strlen(distepoch);
-             int ln = strlen(nvra);
-             nvra[ln++] = ':';
-             memmove(nvra + ln, distepoch, le);        /* may overlap */
-             nvra[le + ln] = 0;
-           }
-         version = strrchr(nvra, '-');
-         if (version)
-           {
-             char *release = version;
-             *release = 0;
-             version = strrchr(nvra, '-');
-             *release = '-';
-             if (!version)
-               version = release;
-             *version++ = 0;
-           }
-         else
-           version = "";
-         s->name = pool_str2id(pool, nvra, 1);
-         if (epochstr && *epochstr && strcmp(epochstr, "0") != 0)
-           {
-             char *evr = pool_tmpjoin(pool, epochstr, ":", version);
-             s->evr = pool_str2id(pool, evr, 1);
-           }
-         else
-           s->evr = pool_str2id(pool, version, 1);
-         repodata_set_location(data, s - pool->solvables, 0, 0, filename);
-         if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-           s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-          s = 0;
-       }
-      else
-       {
-         char *tagend = strchr(buf + 1, '@');
-         if (tagend)
-           *tagend = 0;
-         pool_debug(pool, SOLV_ERROR, "unknown tag <%s>\n", buf + 1);
-         continue;
-       }
-    }
-  if (s)
-    {
-      pool_debug(pool, SOLV_ERROR, "unclosed package at EOF\n");
-      repo_free_solvable(s->repo, s - pool->solvables, 1);
-    }
-  solv_free(buf);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-enum state {
-  STATE_START,
-  STATE_MEDIA_INFO,
-  STATE_INFO,
-  STATE_FILES,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* must be sorted by first column */
-static struct stateswitch stateswitches[] = {
-  { STATE_START, "media_info", STATE_MEDIA_INFO, 0 },
-  { STATE_MEDIA_INFO, "info", STATE_INFO, 1 },
-  { STATE_MEDIA_INFO, "files", STATE_FILES, 1 },
-  { NUMSTATES }
-};
-
-struct parsedata {
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  Solvable *solvable;
-  Hashtable joinhash;
-  Hashval joinhashmask;
-};
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-static Hashtable
-joinhash_init(Repo *repo, Hashval *hmp)
-{
-  Hashval hm = mkmask(repo->nsolvables);
-  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
-  Hashval h, hh;
-  Solvable *s;
-  int i;
-
-  FOR_REPO_SOLVABLES(repo, i, s)
-    {
-      hh = HASHCHAIN_START;
-      h = s->name & hm;
-      while (ht[h])
-        h = HASHCHAIN_NEXT(h, hh, hm);
-      ht[h] = i;
-    }
-  *hmp = hm;
-  return ht;
-}
-
-static Solvable *
-joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn, const char *distepoch)
-{
-  Hashval h, hh;
-  const char *p, *vrstart, *vrend;
-  Id name, arch;
-
-  if (!fn || !*fn)
-    return 0;
-  if (distepoch && !*distepoch)
-    distepoch = 0;
-  p = fn + strlen(fn);
-  while (--p > fn)
-    if (*p == '.')
-      break;
-  if (p == fn)
-    return 0;
-  arch = pool_str2id(repo->pool, p + 1, 0);
-  if (!arch)
-    return 0;
-  if (distepoch)
-    {
-      while (--p > fn)
-        if (*p == '-')
-          break;
-      if (p == fn)
-       return 0;
-    }
-  vrend = p;
-  while (--p > fn)
-    if (*p == '-')
-      break;
-  if (p == fn)
-    return 0;
-  while (--p > fn)
-    if (*p == '-')
-      break;
-  if (p == fn)
-    return 0;
-  vrstart = p + 1;
-  name = pool_strn2id(repo->pool, fn, p - fn, 0);
-  if (!name)
-    return 0;
-  hh = HASHCHAIN_START;
-  h = name & hm;
-  while (ht[h])
-    {
-      Solvable *s = repo->pool->solvables + ht[h];
-      if (s->name == name && s->arch == arch)
-       {
-         /* too bad we don't know the epoch... */
-         const char *evr = pool_id2str(repo->pool, s->evr);
-         for (p = evr; *p >= '0' && *p <= '9'; p++)
-           ;
-         if (p > evr && *p == ':')
-           evr = p + 1;
-         if (distepoch)
-           {
-              if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == ':' && !strcmp(distepoch, evr + (vrend - vrstart + 1)))
-               return s;
-           }
-          else if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == 0)
-           return s;
-       }
-      h = HASHCHAIN_NEXT(h, hh, hm);
-    }
-  return 0;
-}
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  struct stateswitch *sw;
-
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
-    if (!strcmp(sw->ename, name))
-      break;
-  if (sw->from != pd->state)
-    return;
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-  switch (pd->state)
-    {
-    case STATE_INFO:
-      {
-       const char *fn = find_attr("fn", atts);
-       const char *distepoch = find_attr("distepoch", atts);
-       const char *str;
-       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
-       if (!pd->solvable)
-         break;
-       str = find_attr("url", atts);
-       if (str && *str)
-         repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str);
-       str = find_attr("license", atts);
-       if (str && *str)
-         repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str);
-       str = find_attr("sourcerpm", atts);
-       if (str && *str)
-         repodata_set_sourcepkg(pd->data, pd->solvable - pool->solvables, str);
-        break;
-      }
-    case STATE_FILES:
-      {
-       const char *fn = find_attr("fn", atts);
-       const char *distepoch = find_attr("distepoch", atts);
-       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
-        break;
-      }
-    default:
-      break;
-    }
-}
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Solvable *s = pd->solvable;
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-      return;
-    }
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
-    {
-    case STATE_INFO:
-      if (s && *pd->content)
-        repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, pd->content);
-      break;
-    case STATE_FILES:
-      if (s && *pd->content)
-       {
-         char *np, *p, *sl;
-         for (p = pd->content; p && *p; p = np)
-           {
-             Id id;
-             np = strchr(p, '\n');
-             if (np)
-               *np++ = 0;
-             if (!*p)
-               continue;
-             sl = strrchr(p, '/');
-             if (sl)
-               {
-                 *sl++ = 0;
-                 id = repodata_str2dir(pd->data, p, 1);
-               }
-             else
-               {
-                 sl = p;
-                 id = 0;
-               }
-             if (!id)
-               id = repodata_str2dir(pd->data, "/", 1);
-             repodata_add_dirstr(pd->data, s - pd->pool->solvables, SOLVABLE_FILELIST, id, sl);
-           }
-       }
-      break;
-    default:
-      break;
-    }
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-}
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-int
-repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
-{
-  Repodata *data;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  XML_Parser parser;
-
-  if (!(flags & REPO_EXTEND_SOLVABLES))
-    {
-      pool_debug(repo->pool, SOLV_ERROR, "repo_add_mdk_info: can only extend existing solvables\n");
-      return -1;
-    }
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  pd.repo = repo;
-  pd.pool = repo->pool;
-  pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-
-  pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-        {
-          pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-          break;
-        }
-      if (l == 0)
-        break;
-    }
-  XML_ParserFree(parser);
-  solv_free(pd.content);
-  solv_free(pd.joinhash);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
diff --git a/libsolv-0.6.15/ext/repo_mdk.h b/libsolv-0.6.15/ext/repo_mdk.h
deleted file mode 100644 (file)
index 270c42e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_mdk(Repo *repo, FILE *fp, int flags);
-extern int repo_add_mdk_info(Repo *repo, FILE *fp, int flags);
-
diff --git a/libsolv-0.6.15/ext/repo_products.c b/libsolv-0.6.15/ext/repo_products.c
deleted file mode 100644 (file)
index cb69c49..0000000
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * repo_products.c
- *
- * Parses all files below 'proddir'
- * See http://en.opensuse.org/Product_Management/Code11
- *
- *
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-#define _XOPEN_SOURCE
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <dirent.h>
-#include <expat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#define DISABLE_SPLIT
-#include "tools_util.h"
-#include "repo_content.h"
-#include "repo_zyppdb.h"
-#include "repo_products.h"
-#include "repo_releasefile_products.h"
-
-
-enum state {
-  STATE_START,
-  STATE_PRODUCT,
-  STATE_VENDOR,
-  STATE_NAME,
-  STATE_VERSION,
-  STATE_RELEASE,
-  STATE_ARCH,
-  STATE_SUMMARY,
-  STATE_SHORTSUMMARY,
-  STATE_DESCRIPTION,
-  STATE_UPDATEREPOKEY,
-  STATE_CPEID,
-  STATE_URLS,
-  STATE_URL,
-  STATE_RUNTIMECONFIG,
-  STATE_LINGUAS,
-  STATE_LANG,
-  STATE_REGISTER,
-  STATE_TARGET,
-  STATE_REGRELEASE,
-  STATE_REGFLAVOR,
-  STATE_PRODUCTLINE,
-  STATE_REGUPDATES,
-  STATE_REGUPDREPO,
-  STATE_ENDOFLIFE,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
-  { STATE_START,     "product",       STATE_PRODUCT,       0 },
-  { STATE_PRODUCT,   "vendor",        STATE_VENDOR,        1 },
-  { STATE_PRODUCT,   "name",          STATE_NAME,          1 },
-  { STATE_PRODUCT,   "version",       STATE_VERSION,       1 },
-  { STATE_PRODUCT,   "release",       STATE_RELEASE,       1 },
-  { STATE_PRODUCT,   "arch",          STATE_ARCH,          1 },
-  { STATE_PRODUCT,   "productline",   STATE_PRODUCTLINE,   1 },
-  { STATE_PRODUCT,   "summary",       STATE_SUMMARY,       1 },
-  { STATE_PRODUCT,   "shortsummary",  STATE_SHORTSUMMARY,  1 },
-  { STATE_PRODUCT,   "description",   STATE_DESCRIPTION,   1 },
-  { STATE_PRODUCT,   "register",      STATE_REGISTER,      0 },
-  { STATE_PRODUCT,   "urls",          STATE_URLS,          0 },
-  { STATE_PRODUCT,   "runtimeconfig", STATE_RUNTIMECONFIG, 0 },
-  { STATE_PRODUCT,   "linguas",       STATE_LINGUAS,       0 },
-  { STATE_PRODUCT,   "updaterepokey", STATE_UPDATEREPOKEY, 1 },
-  { STATE_PRODUCT,   "cpeid",         STATE_CPEID,         1 },
-  { STATE_PRODUCT,   "endoflife",     STATE_ENDOFLIFE,     1 },
-  { STATE_URLS,      "url",           STATE_URL,           1 },
-  { STATE_LINGUAS,   "lang",          STATE_LANG,          0 },
-  { STATE_REGISTER,  "target",        STATE_TARGET,        1 },
-  { STATE_REGISTER,  "release",       STATE_REGRELEASE,    1 },
-  { STATE_REGISTER,  "flavor",        STATE_REGFLAVOR,     1 },
-  { STATE_REGISTER,  "updates",       STATE_REGUPDATES,    0 },
-  { STATE_REGUPDATES, "repository",   STATE_REGUPDREPO,    0 },
-  { NUMSTATES }
-};
-
-struct parsedata {
-  const char *filename;
-  const char *basename;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  struct joindata jd;
-
-  const char *tmplang;
-
-  const char *tmpvers;
-  const char *tmprel;
-  Id urltype;
-
-  unsigned int ctime;
-
-  Solvable *solvable;
-  Id handle;
-
-  ino_t baseproduct;
-  ino_t currentproduct;
-  int productscheme;
-};
-
-
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-static time_t
-datestr2timestamp(const char *date)
-{
-  const char *p; 
-  struct tm tm; 
-
-  if (!date || !*date)
-    return 0;
-  for (p = date; *p >= '0' && *p <= '9'; p++)
-    ;   
-  if (!*p)
-    return atoi(date);
-  memset(&tm, 0, sizeof(tm));
-  p = strptime(date, "%F%T", &tm);
-  if (!p)
-    {
-      memset(&tm, 0, sizeof(tm));
-      p = strptime(date, "%F", &tm);
-      if (!p || *p)
-       return 0;
-    }
-  return timegm(&tm);
-}
-
-/*
- * XML callback: startElement
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_PRODUCT:
-      /* parse 'schemeversion' and store in global variable */
-      {
-        const char * scheme = find_attr("schemeversion", atts);
-        pd->productscheme = (scheme && *scheme) ? atoi(scheme) : -1;
-      }
-      if (!s)
-       {
-         s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-         pd->handle = s - pool->solvables;
-       }
-      break;
-
-      /* <summary lang="xy">... */
-    case STATE_SUMMARY:
-    case STATE_DESCRIPTION:
-      pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
-      break;
-    case STATE_URL:
-      pd->urltype = pool_str2id(pd->pool, find_attr("name", atts), 1);
-      break;
-    case STATE_REGUPDREPO:
-      {
-        const char *repoid = find_attr("repoid", atts);
-       if (repoid && *repoid)
-         {
-           Id h = repodata_new_handle(pd->data);
-           repodata_set_str(pd->data, h, PRODUCT_UPDATES_REPOID, repoid);
-           repodata_add_flexarray(pd->data, pd->handle, PRODUCT_UPDATES, h);
-         }
-       break;
-      }
-    default:
-      break;
-    }
-}
-
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Solvable *s = pd->solvable;
-
-#if 0
-  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  switch (pd->state)
-    {
-    case STATE_PRODUCT:
-      /* product done, finish solvable */
-      if (pd->ctime)
-        repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, pd->ctime);
-
-      if (pd->basename)
-        repodata_set_str(pd->data, pd->handle, PRODUCT_REFERENCEFILE, pd->basename);
-
-      /* this is where <productsdir>/baseproduct points to */
-      if (pd->currentproduct == pd->baseproduct)
-       repodata_set_str(pd->data, pd->handle, PRODUCT_TYPE, "base");
-
-      if (pd->tmprel)
-       {
-         if (pd->tmpvers)
-           s->evr = makeevr(pd->pool, join2(&pd->jd, pd->tmpvers, "-", pd->tmprel));
-         else
-           {
-             fprintf(stderr, "Seen <release> but no <version>\n");
-           }
-       }
-      else if (pd->tmpvers)
-       s->evr = makeevr(pd->pool, pd->tmpvers); /* just version, no release */
-      pd->tmpvers = solv_free((void *)pd->tmpvers);
-      pd->tmprel = solv_free((void *)pd->tmprel);
-      if (!s->arch)
-       s->arch = ARCH_NOARCH;
-      if (!s->evr)
-       s->evr = ID_EMPTY;
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
-      pd->solvable = 0;
-      break;
-    case STATE_VENDOR:
-      s->vendor = pool_str2id(pd->pool, pd->content, 1);
-      break;
-    case STATE_NAME:
-      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1);
-      break;
-    case STATE_VERSION:
-      pd->tmpvers = solv_strdup(pd->content);
-      break;
-    case STATE_RELEASE:
-      pd->tmprel = solv_strdup(pd->content);
-      break;
-    case STATE_ARCH:
-      s->arch = pool_str2id(pd->pool, pd->content, 1);
-      break;
-    case STATE_PRODUCTLINE:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, pd->content);
-    break;
-    case STATE_UPDATEREPOKEY:
-      /** obsolete **/
-      break;
-    case STATE_SUMMARY:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
-      break;
-    case STATE_SHORTSUMMARY:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, pd->content);
-      break;
-    case STATE_DESCRIPTION:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), pd->content);
-      break;
-    case STATE_URL:
-      if (pd->urltype)
-        {
-          repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, pd->content);
-          repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, pd->urltype);
-        }
-      break;
-    case STATE_TARGET:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, pd->content);
-      break;
-    case STATE_REGRELEASE:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, pd->content);
-      break;
-    case STATE_REGFLAVOR:
-      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, pd->content);
-      break;
-    case STATE_CPEID:
-      if (*pd->content)
-        repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, pd->content);
-      break;
-    case STATE_ENDOFLIFE:
-      if (*pd->content)
-       {
-         time_t t = datestr2timestamp(pd->content);
-         if (t)
-           repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (unsigned long long)t);
-       }
-      break;
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-      fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-
-/*
- * add single product to repo
- *
- */
-
-static void
-add_code11_product(struct parsedata *pd, FILE *fp)
-{
-  char buf[BUFF_SIZE];
-  int l;
-  struct stat st;
-  XML_Parser parser;
-
-  if (!fstat(fileno(fp), &st))
-    {
-      pd->currentproduct = st.st_ino;
-      pd->ctime = (unsigned int)st.st_ctime;
-    }
-  else
-    {
-      pd->currentproduct = pd->baseproduct + 1; /* make it != baseproduct if stat fails */
-      pool_error(pd->pool, 0, "fstat: %s", strerror(errno));
-      pd->ctime = 0;
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         XML_ParserFree(parser);
-         if (pd->solvable)
-           {
-             repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
-             pd->solvable = 0;
-           }
-         return;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-}
-
-
-int
-repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
-{
-  Repodata *data;
-  struct parsedata pd;
-  struct stateswitch *sw;
-  DIR *dir;
-  int i;
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  pd.repo = repo;
-  pd.pool = repo->pool;
-  pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  if (flags & REPO_USE_ROOTDIR)
-    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
-  dir = opendir(dirpath);
-  if (dir)
-    {
-      struct dirent *entry;
-      struct stat st;
-      char *fullpath;
-
-      /* check for <productsdir>/baseproduct on code11 and remember its target inode */
-      if (stat(join2(&pd.jd, dirpath, "/", "baseproduct"), &st) == 0) /* follow symlink */
-       pd.baseproduct = st.st_ino;
-      else
-       pd.baseproduct = 0;
-
-      while ((entry = readdir(dir)))
-       {
-         int len = strlen(entry->d_name);
-         FILE *fp;
-         if (len <= 5 || strcmp(entry->d_name + len - 5, ".prod") != 0)
-           continue;
-         fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
-         fp = fopen(fullpath, "r");
-         if (!fp)
-           {
-             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
-             continue;
-           }
-         pd.filename = fullpath;
-         pd.basename = entry->d_name;
-         add_code11_product(&pd, fp);
-         fclose(fp);
-       }
-      closedir(dir);
-    }
-  solv_free(pd.content);
-  join_freemem(&pd.jd);
-  if (flags & REPO_USE_ROOTDIR)
-    solv_free((char *)dirpath);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-
-/******************************************************************************************/
-
-
-/*
- * read all installed products
- *
- * try proddir (reading all .xml files from this directory) first
- * if not available, assume non-code11 layout and parse /etc/xyz-release
- *
- * parse each one as a product
- */
-
-/* Oh joy! Three parsers for the price of one! */
-
-int
-repo_add_products(Repo *repo, const char *proddir, int flags)
-{
-  const char *fullpath;
-  DIR *dir;
-
-  if (proddir)
-    {
-      dir = opendir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(repo->pool, proddir) : proddir);
-      if (dir)
-       {
-         /* assume code11 stype products */
-         closedir(dir);
-         return repo_add_code11_products(repo, proddir, flags);
-       }
-    }
-
-  /* code11 didn't work, try old code10 zyppdb */
-  fullpath = "/var/lib/zypp/db/products";
-  if (flags & REPO_USE_ROOTDIR)
-    fullpath = pool_prepend_rootdir_tmp(repo->pool, fullpath);
-  dir = opendir(fullpath);
-  if (dir)
-    {
-      closedir(dir);
-      /* assume code10 style products */
-      return repo_add_zyppdb_products(repo, "/var/lib/zypp/db/products", flags);
-    }
-
-  /* code10/11 didn't work, try -release files parsing */
-  fullpath = "/etc";
-  if (flags & REPO_USE_ROOTDIR)
-    fullpath = pool_prepend_rootdir_tmp(repo->pool, fullpath);
-  dir = opendir(fullpath);
-  if (dir)
-    {
-      closedir(dir);
-      return repo_add_releasefile_products(repo, "/etc", flags);
-    }
-
-  /* no luck. check if the rootdir exists */
-  fullpath = pool_get_rootdir(repo->pool);
-  if (fullpath && *fullpath)
-    {
-      dir = opendir(fullpath);
-      if (!dir)
-       return pool_error(repo->pool, -1, "%s: %s", fullpath, strerror(errno));
-      closedir(dir);
-    }
-
-  /* the least we can do... */
-  if (!(flags & REPO_NO_INTERNALIZE) && (flags & REPO_REUSE_REPODATA) != 0)
-    repodata_internalize(repo_last_repodata(repo));
-  return 0;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/ext/repo_products.h b/libsolv-0.6.15/ext/repo_products.h
deleted file mode 100644 (file)
index f7e3b0a..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_code11_products(Repo *repo, const char *dirpath, int flags);
-extern int repo_add_products(Repo *repo, const char *proddir, int flags);
diff --git a/libsolv-0.6.15/ext/repo_pubkey.c b/libsolv-0.6.15/ext/repo_pubkey.c
deleted file mode 100644 (file)
index d8496dc..0000000
+++ /dev/null
@@ -1,1250 +0,0 @@
-/*
- * Copyright (c) 2007-2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_pubkey
- *
- * support for pubkey reading
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <stdint.h>
-#include <errno.h>
-#include <dirent.h>
-
-#include <rpm/rpmio.h>
-#include <rpm/rpmpgp.h>
-#ifndef RPM5
-#include <rpm/header.h>
-#endif
-#include <rpm/rpmdb.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "hash.h"
-#include "util.h"
-#include "queue.h"
-#include "chksum.h"
-#include "repo_rpmdb.h"
-#include "repo_pubkey.h"
-#ifdef ENABLE_PGPVRFY
-#include "solv_pgpvrfy.h"
-#endif
-
-static void
-setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
-{
-  if (str[solv_validutf8(str)])
-    {
-      char *ustr = solv_latin1toutf8(str);     /* not utf8, assume latin1 */
-      repodata_set_str(repodata, handle, tag, ustr);
-      solv_free(ustr);
-    }
-  else
-    repodata_set_str(repodata, handle, tag, str);
-}
-
-static char *
-r64dec1(char *p, unsigned int *vp, int *eofp)
-{
-  int i, x;
-  unsigned int v = 0;
-
-  for (i = 0; i < 4; )
-    {
-      x = *p++;
-      if (!x)
-       return 0;
-      if (x >= 'A' && x <= 'Z')
-       x -= 'A';
-      else if (x >= 'a' && x <= 'z')
-       x -= 'a' - 26;
-      else if (x >= '0' && x <= '9')
-       x -= '0' - 52;
-      else if (x == '+')
-       x = 62;
-      else if (x == '/')
-       x = 63;
-      else if (x == '=')
-       {
-         x = 0;
-         if (i == 0)
-           {
-             *eofp = 3;
-             *vp = 0;
-             return p - 1;
-           }
-         *eofp += 1;
-       }
-      else
-       continue;
-      v = v << 6 | x;
-      i++;
-    }
-  *vp = v;
-  return p;
-}
-
-static unsigned int
-crc24(unsigned char *p, int len)
-{
-  unsigned int crc = 0xb704ce;
-  int i;
-
-  while (len--)
-    {
-      crc ^= (*p++) << 16;
-      for (i = 0; i < 8; i++)
-        if ((crc <<= 1) & 0x1000000)
-         crc ^= 0x1864cfb;
-    }
-  return crc & 0xffffff;
-}
-
-static int
-unarmor(char *pubkey, unsigned char **pktp, int *pktlp, const char *startstr, const char *endstr)
-{
-  char *p, *pubkeystart = pubkey;
-  int l, eof;
-  unsigned char *buf, *bp;
-  unsigned int v;
-
-  *pktp = 0;
-  *pktlp = 0;
-  if (!pubkey)
-    return 0;
-  l = strlen(startstr);
-  while (strncmp(pubkey, startstr, l) != 0)
-    {
-      pubkey = strchr(pubkey, '\n');
-      if (!pubkey)
-       return 0;
-      pubkey++;
-    }
-  pubkey = strchr(pubkey, '\n');
-  if (!pubkey++)
-    return 0;
-  /* skip header lines */
-  for (;;)
-    {
-      while (*pubkey == ' ' || *pubkey == '\t')
-       pubkey++;
-      if (*pubkey == '\n')
-       break;
-      pubkey = strchr(pubkey, '\n');
-      if (!pubkey++)
-       return 0;
-    }
-  pubkey++;
-  p = strchr(pubkey, '=');
-  if (!p)
-    return 0;
-  l = p - pubkey;
-  bp = buf = solv_malloc(l * 3 / 4 + 4);
-  eof = 0;
-  while (!eof)
-    {
-      pubkey = r64dec1(pubkey, &v, &eof);
-      if (!pubkey)
-       {
-         solv_free(buf);
-         return 0;
-       }
-      *bp++ = v >> 16;
-      *bp++ = v >> 8;
-      *bp++ = v;
-    }
-  while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
-    pubkey++;
-  bp -= eof;
-  if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0)
-    {
-      solv_free(buf);
-      return 0;
-    }
-  if (v != crc24(buf, bp - buf))
-    {
-      solv_free(buf);
-      return 0;
-    }
-  while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
-    pubkey++;
-  if (strncmp(pubkey, endstr, strlen(endstr)) != 0)
-    {
-      solv_free(buf);
-      return 0;
-    }
-  p = strchr(pubkey, '\n');
-  if (!p)
-    p = pubkey + strlen(pubkey);
-  *pktp = buf;
-  *pktlp = bp - buf;
-  return (p ? p + 1 : pubkey + strlen(pubkey)) - pubkeystart;
-}
-
-#define ARMOR_NLAFTER  16
-
-static char *
-armor(unsigned char *pkt, int pktl, const char *startstr, const char *endstr, const char *version)
-{
-  static const char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-  char *str = solv_malloc(strlen(startstr) + strlen(endstr) + strlen(version) + (pktl / 3) * 4 + (pktl / (ARMOR_NLAFTER * 3)) + 30);
-  char *p = str;
-  int a, b, c, i;
-  unsigned int v;
-
-  v = crc24(pkt, pktl);
-  sprintf(p, "%s\nVersion: %s\n\n", startstr, version);
-  p += strlen(p);
-  for (i = -1; pktl > 0; pktl -= 3)
-    {
-      if (++i == ARMOR_NLAFTER)
-       {
-         i = 0;
-         *p++ = '\n';
-       }
-      a = *pkt++;
-      b = pktl > 1 ? *pkt++ : 0;
-      c = pktl > 2 ? *pkt++ : 0;
-      *p++ = bintoasc[a >> 2];
-      *p++ = bintoasc[(a & 3) << 4 | b >> 4];
-      *p++ = pktl > 1 ? bintoasc[(b & 15) << 2 | c >> 6] : '=';
-      *p++ = pktl > 2 ? bintoasc[c & 63] : '=';
-    }
-  *p++ = '\n';
-  *p++ = '=';
-  *p++ = bintoasc[v >> 18 & 0x3f];
-  *p++ = bintoasc[v >> 12 & 0x3f];
-  *p++ = bintoasc[v >>  6 & 0x3f];
-  *p++ = bintoasc[v       & 0x3f];
-  sprintf(p, "\n%s\n", endstr);
-  return str;
-}
-
-/* internal representation of a signature */
-struct pgpsig {
-  int type;
-  Id hashalgo;
-  unsigned char issuer[8];
-  int haveissuer;
-  unsigned int created;
-  unsigned int expires;
-  unsigned int keyexpires;
-  unsigned char *sigdata;
-  int sigdatal;
-  int mpioff;
-};
-
-static Id
-pgphashalgo2type(int algo)
-{
-  if (algo == 1)
-    return REPOKEY_TYPE_MD5;
-  if (algo == 2)
-    return REPOKEY_TYPE_SHA1;
-  if (algo == 8)
-    return REPOKEY_TYPE_SHA256;
-  if (algo == 9)
-    return REPOKEY_TYPE_SHA384;
-  if (algo == 10)
-    return REPOKEY_TYPE_SHA512;
-  if (algo == 11)
-    return REPOKEY_TYPE_SHA224;
-  return 0;
-}
-
-/* hash the pubkey/userid data for self-sig verification
- * hash the final trailer
- * create a "sigdata" block suitable for a call to solv_pgpverify */
-static void
-pgpsig_makesigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl, Chksum *h)
-{
-  int type = sig->type;
-  unsigned char b[6];
-  const unsigned char *cs;
-  int csl;
-
-  if (!h || sig->mpioff < 2 || l <= sig->mpioff)
-    return;
-  if ((type >= 0x10 && type <= 0x13) || type == 0x1f || type == 0x18 || type == 0x20 || type == 0x28)
-    {
-      b[0] = 0x99;
-      b[1] = pubkeyl >> 8;
-      b[2] = pubkeyl;
-      solv_chksum_add(h, b, 3);
-      solv_chksum_add(h, pubkey, pubkeyl);
-    }
-  if ((type >= 0x10 && type <= 0x13))
-    {
-      if (p[0] != 3)
-       {
-         b[0] = 0xb4;
-         b[1] = useridl >> 24;
-         b[2] = useridl >> 16;
-         b[3] = useridl >> 8;
-         b[4] = useridl;
-         solv_chksum_add(h, b, 5);
-       }
-      solv_chksum_add(h, userid, useridl);
-    }
-  /* add trailer */
-  if (p[0] == 3)
-    solv_chksum_add(h, p + 2, 5);
-  else
-    {
-      int hl = 6 + (p[4] << 8 | p[5]);
-      solv_chksum_add(h, p, hl);
-      b[0] = 4;
-      b[1] = 0xff;
-      b[2] = hl >> 24;
-      b[3] = hl >> 16;
-      b[4] = hl >> 8;
-      b[5] = hl;
-      solv_chksum_add(h, b, 6);
-    }
-  cs = solv_chksum_get(h, &csl);
-  if (cs[0] == p[sig->mpioff - 2] && cs[1] == p[sig->mpioff - 1])
-    {
-      int ml = l - sig->mpioff;
-      sig->sigdata = solv_malloc(2 + csl + ml);
-      sig->sigdatal = 2 + csl + ml;
-      sig->sigdata[0] = p[0] == 3 ? p[15] : p[2];
-      sig->sigdata[1] = p[0] == 3 ? p[16] : p[3];
-      memcpy(sig->sigdata + 2, cs, csl);
-      memcpy(sig->sigdata + 2 + csl, p + sig->mpioff, ml);
-    }
-}
-
-/* parse the header of a subpacket contained in a signature packet
- * returns: length of the packet header, 0 if there was an error
- * *pktlp is set to the packet length, the tag is the first byte.
- */
-static inline int
-parsesubpkglength(unsigned char *q, int ql, int *pktlp)
-{
-  int x, sl, hl;
-  /* decode sub-packet length, ql must be > 0 */
-  x = *q++;
-  if (x < 192)
-    {
-      sl = x;
-      hl = 1;
-    }
-  else if (x == 255)
-    {
-      if (ql < 5 || q[0] != 0)
-       return 0;
-      sl = q[1] << 16 | q[2] << 8 | q[3];
-      hl = 5;
-    }
-  else
-    {
-      if (ql < 2)
-       return 0;
-      sl = ((x - 192) << 8) + q[0] + 192;
-      hl = 2;
-    }
-  if (!sl || ql < sl + hl)     /* sub pkg tag is included in length, i.e. sl must not be zero */
-    return 0;
-  *pktlp = sl;
-  return hl;
-}
-
-/* parse a signature packet, initializing the pgpsig struct */
-static void
-pgpsig_init(struct pgpsig *sig, unsigned char *p, int l)
-{
-  memset(sig, 0, sizeof(*sig));
-  sig->type = -1;
-  if (p[0] == 3)
-    {
-      /* printf("V3 signature packet\n"); */
-      if (l <= 19 || p[1] != 5)
-       return;
-      sig->type = p[2];
-      sig->haveissuer = 1;
-      memcpy(sig->issuer, p + 7, 8);
-      sig->created = p[3] << 24 | p[4] << 16 | p[5] << 8 | p[6];
-      sig->hashalgo = p[16];
-      sig->mpioff = 19;
-    }
-  else if (p[0] == 4)
-    {
-      int j, ql, x;
-      unsigned char *q;
-
-      /* printf("V4 signature packet\n"); */
-      if (l < 6)
-       return;
-      sig->type = p[1];
-      sig->hashalgo = p[3];
-      q = p + 4;
-      sig->keyexpires = -1;
-      for (j = 0; q && j < 2; j++)
-       {
-         if (q + 2 > p + l)
-           {
-             q = 0;
-             break;
-           }
-         ql = q[0] << 8 | q[1];
-         q += 2;
-         if (q + ql > p + l)
-           {
-             q = 0;
-             break;
-           }
-         while (ql > 0)
-           {
-             int sl, hl;
-             hl = parsesubpkglength(q, ql, &sl);
-             if (!hl)
-               {
-                 q = 0;
-                 break;
-               }
-             q += hl;
-             ql -= hl;
-             x = q[0] & 127;   /* strip critical bit */
-             /* printf("%d SIGSUB %d %d\n", j, x, sl); */
-             if (x == 16 && sl == 9 && !sig->haveissuer)
-               {
-                 sig->haveissuer = 1;
-                 memcpy(sig->issuer, q + 1, 8);
-               }
-             if (x == 2 && j == 0)
-               sig->created = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
-             if (x == 3 && j == 0)
-               sig->expires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
-             if (x == 9 && j == 0)
-               sig->keyexpires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
-             q += sl;
-             ql -= sl;
-           }
-       }
-      if (q && q - p + 2 < l)
-       sig->mpioff = q - p + 2;
-    }
-}
-
-/* parse a pgp packet header
- * returns: length of the packet header, 0 if there was an error
- * *tagp and *pktlp is set to the packet tag and the packet length
- */
-static int
-parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp)
-{
-  unsigned char *op = p;
-  int x, l;
-
-  if (!pl)
-    return 0;
-  x = *p++;
-  pl--;
-  if (!(x & 128) || pl <= 0)
-    return 0;
-  if ((x & 64) == 0)
-    {
-      *tagp = (x & 0x3c) >> 2;         /* old format */
-      x = 1 << (x & 3);
-      if (x > 4 || pl < x || (x == 4 && p[0]))
-       return 0;
-      pl -= x;
-      for (l = 0; x--;)
-       l = l << 8 | *p++;
-    }
-  else
-    {
-      *tagp = (x & 0x3f);              /* new format */
-      x = *p++;
-      pl--;
-      if (x < 192)
-       l = x;
-      else if (x >= 192 && x < 224)
-       {
-         if (pl <= 0)
-           return 0;
-         l = ((x - 192) << 8) + *p++ + 192;
-         pl--;
-       }
-      else if (x == 255)
-       {
-         if (pl <= 4 || p[0] != 0)     /* sanity: p[0] must be zero */
-           return 0;
-         l = p[1] << 16 | p[2] << 8 | p[3];
-         p += 4;
-         pl -= 4;
-       }
-      else
-       return 0;
-    }
-  if (l > pl)
-    return 0;
-  *pktlp = l;
-  return p - op;
-}
-
-/* parse the first pubkey (possible creating new packages for the subkeys)
- * returns the number of parsed bytes.
- * if flags contains ADD_WITH_SUBKEYS, all subkeys will be added as new
- * solvables as well */
-static int
-parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags)
-{
-  Repo *repo = s->repo;
-  unsigned char *pstart = p;
-  int tag, l;
-  unsigned char keyid[8];
-  char subkeyofstr[17];
-  unsigned int kcr = 0, maxex = 0, maxsigcr = 0;
-  unsigned char *pubkey = 0;
-  int pubkeyl = 0;
-  int insubkey = 0;
-  unsigned char *userid = 0;
-  int useridl = 0;
-  unsigned char *pubdata = 0;
-  int pubdatal = 0;
-
-  *subkeyofstr = 0;
-  for (; ; p += l, pl -= l)
-    {
-      int hl = parsepkgheader(p, pl, &tag, &l);
-      if (!hl || (pubkey && (tag == 6 || tag == 14)))
-       {
-         /* finish old key */
-         if (kcr)
-           repodata_set_num(data, s - repo->pool->solvables, SOLVABLE_BUILDTIME, kcr);
-         if (maxex && maxex != -1)
-           repodata_set_num(data, s - repo->pool->solvables, PUBKEY_EXPIRES, maxex);
-         s->name = pool_str2id(s->repo->pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1);
-         s->evr = 1;
-         s->arch = 1;
-         if (userid && useridl)
-           {
-             char *useridstr = solv_malloc(useridl + 1);
-             memcpy(useridstr, userid, useridl);
-             useridstr[useridl] = 0;
-             setutf8string(data, s - repo->pool->solvables, SOLVABLE_SUMMARY, useridstr);
-             free(useridstr);
-           }
-         if (pubdata)
-           {
-             char keyidstr[17];
-             char evr[8 + 1 + 8 + 1];
-             solv_bin2hex(keyid, 8, keyidstr);
-             repodata_set_str(data, s - repo->pool->solvables, PUBKEY_KEYID, keyidstr);
-             /* build rpm-style evr */
-             strcpy(evr, keyidstr + 8);
-             sprintf(evr + 8, "-%08x", maxsigcr);
-             s->evr = pool_str2id(repo->pool, evr, 1);
-           }
-         if (insubkey && *subkeyofstr)
-           repodata_set_str(data, s - repo->pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr);
-         if (pubdata)          /* set data blob */
-           repodata_set_binary(data, s - repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal);
-         if (!pl)
-           break;
-         if (!hl)
-           {
-             p = 0;    /* parse error */
-             break;
-           }
-         if (tag == 6 || (tag == 14 && !(flags & ADD_WITH_SUBKEYS)))
-           break;
-         if (tag == 14 && pubdata && !insubkey)
-           solv_bin2hex(keyid, 8, subkeyofstr);
-         /* create new solvable for subkey */
-         s = pool_id2solvable(repo->pool, repo_add_solvable(repo));
-       }
-      p += hl;
-      pl -= hl;
-      if (!pubkey && tag != 6)
-       continue;
-      if (tag == 6 || (tag == 14 && (flags & ADD_WITH_SUBKEYS) != 0))          /* Public-Key Packet */
-       {
-         if (tag == 6)
-           {
-             pubkey = solv_memdup(p, l);
-             pubkeyl = l;
-           }
-         else
-           insubkey = 1;
-         pubdata = 0;
-         pubdatal = 0;
-         if (p[0] == 3 && l >= 10)
-           {
-             unsigned int ex;
-             Chksum *h;
-             maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
-             ex = 0;
-             if (p[5] || p[6])
-               {
-                 ex = kcr + 24*3600 * (p[5] << 8 | p[6]);
-                 if (ex > maxex)
-                   maxex = ex;
-               }
-             memset(keyid, 0, 8);
-             if (p[7] == 1)    /* RSA */
-               {
-                 int ql, ql2;
-                 unsigned char fp[16];
-                 char fpx[32 + 1];
-                 unsigned char *q;
-
-                 ql = ((p[8] << 8 | p[9]) + 7) / 8;            /* length of public modulus */
-                 if (ql >= 8 && 10 + ql + 2 <= l)
-                   {
-                     memcpy(keyid, p + 10 + ql - 8, 8);        /* keyid is last 64 bits of public modulus */
-                     q = p + 10 + ql;
-                     ql2 = ((q[0] << 8 | q[1]) + 7) / 8;       /* length of encryption exponent */
-                     if (10 + ql + 2 + ql2 <= l)
-                       {
-                         /* fingerprint is the md5 over the two MPI bodies */
-                         h = solv_chksum_create(REPOKEY_TYPE_MD5);
-                         solv_chksum_add(h, p + 10, ql);
-                         solv_chksum_add(h, q + 2, ql2);
-                         solv_chksum_free(h, fp);
-                         solv_bin2hex(fp, 16, fpx);
-                         repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
-                       }
-                   }
-                 pubdata = p + 7;
-                 pubdatal = l - 7;
-               }
-           }
-         else if (p[0] == 4 && l >= 6)
-           {
-             Chksum *h;
-             unsigned char hdr[3];
-             unsigned char fp[20];
-             char fpx[40 + 1];
-
-             maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
-             hdr[0] = 0x99;
-             hdr[1] = l >> 8;
-             hdr[2] = l;
-             /* fingerprint is the sha1 over the packet */
-             h = solv_chksum_create(REPOKEY_TYPE_SHA1);
-             solv_chksum_add(h, hdr, 3);
-             solv_chksum_add(h, p, l);
-             solv_chksum_free(h, fp);
-             solv_bin2hex(fp, 20, fpx);
-             repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
-             memcpy(keyid, fp + 12, 8);        /* keyid is last 64 bits of fingerprint */
-             pubdata = p + 5;
-             pubdatal = l - 5;
-           }
-       }
-      if (tag == 2)            /* Signature Packet */
-       {
-         struct pgpsig sig;
-         Id htype;
-         if (!pubdata)
-           continue;
-         pgpsig_init(&sig, p, l);
-         if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f))
-           continue;
-         if (sig.type >= 0x10 && sig.type <= 0x13 && !userid)
-           continue;
-         htype = pgphashalgo2type(sig.hashalgo);
-         if (htype && sig.mpioff)
-           {
-             Chksum *h = solv_chksum_create(htype);
-             pgpsig_makesigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h);
-             solv_chksum_free(h, 0);
-           }
-         if (!memcmp(keyid, sig.issuer, 8))
-           {
-#ifdef ENABLE_PGPVRFY
-             /* found self sig, verify */
-             if (solv_pgpvrfy(pubdata, pubdatal, sig.sigdata, sig.sigdatal))
-#endif
-               {
-                 if (sig.keyexpires && maxex != -1)
-                   {
-                     if (sig.keyexpires == -1)
-                       maxex = -1;
-                     else if (sig.keyexpires + kcr > maxex)
-                       maxex = sig.keyexpires + kcr;
-                   }
-                 if (sig.created > maxsigcr)
-                   maxsigcr = sig.created;
-               }
-           }
-         else if (flags & ADD_WITH_KEYSIGNATURES)
-           {
-             char issuerstr[17];
-             Id shandle = repodata_new_handle(data);
-             solv_bin2hex(sig.issuer, 8, issuerstr);
-             repodata_set_str(data, shandle, SIGNATURE_ISSUER, issuerstr);
-             if (sig.created)
-               repodata_set_num(data, shandle, SIGNATURE_TIME, sig.created);
-             if (sig.expires)
-               repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires);
-             if (sig.sigdata)
-               repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal);
-             repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle);
-           }
-         solv_free(sig.sigdata);
-       }
-      if (tag == 13 && !insubkey)              /* User ID Packet */
-       {
-         userid = solv_realloc(userid, l);
-         if (l)
-           memcpy(userid, p, l);
-         useridl = l;
-       }
-    }
-  solv_free(pubkey);
-  solv_free(userid);
-  return p ? p - pstart : 0;
-}
-
-
-#ifdef ENABLE_RPMDB
-
-/* this is private to rpm, but rpm lacks an interface to retrieve
- * the values. Sigh. */
-struct pgpDigParams_s {
-    const char * userid;
-    const unsigned char * hash;
-#ifndef HAVE_PGPDIGGETPARAMS
-    const char * params[4];
-#endif
-    unsigned char tag;
-    unsigned char version;               /*!< version number. */
-    unsigned char time[4];               /*!< time that the key was created. */
-    unsigned char pubkey_algo;           /*!< public key algorithm. */
-    unsigned char hash_algo;
-    unsigned char sigtype;
-    unsigned char hashlen;
-    unsigned char signhash16[2];
-    unsigned char signid[8];
-    unsigned char saved;
-};
-
-#ifndef HAVE_PGPDIGGETPARAMS
-struct pgpDig_s {
-    struct pgpDigParams_s signature;
-    struct pgpDigParams_s pubkey;
-};
-#endif
-
-
-/* only rpm knows how to do the release calculation, we don't dare
- * to recreate all the bugs in libsolv */
-static void
-parsepubkey_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl)
-{
-  Pool *pool = s->repo->pool;
-  struct pgpDigParams_s *digpubkey;
-  pgpDig dig = 0;
-  char keyid[16 + 1];
-  char evrbuf[8 + 1 + 8 + 1];
-  unsigned int btime;
-
-#ifndef RPM5
-  dig = pgpNewDig();
-#else
-  dig = pgpDigNew(RPMVSF_DEFAULT, 0);
-#endif
-  (void) pgpPrtPkts(pkts, pktsl, dig, 0);
-#ifdef HAVE_PGPDIGGETPARAMS
-  digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
-#else
-  digpubkey = &dig->pubkey;
-#endif
-  if (digpubkey)
-    {
-      btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3];
-      solv_bin2hex(digpubkey->signid, 8, keyid);
-      solv_bin2hex(digpubkey->signid + 4, 4, evrbuf);
-      evrbuf[8] = '-';
-      solv_bin2hex(digpubkey->time, 4, evrbuf + 9);
-      s->evr = pool_str2id(pool, evrbuf, 1);
-      repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid);
-      if (digpubkey->userid)
-       setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid);
-      if (btime)
-       repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime);
-    }
-#ifndef RPM5
-  (void)pgpFreeDig(dig);
-#else
-  (void)pgpDigFree(dig);
-#endif
-}
-
-#endif /* ENABLE_RPMDB */
-
-/* parse an ascii armored pubkey
- * adds multiple pubkeys if ADD_MULTIPLE_PUBKEYS is set */
-static int
-pubkey2solvable(Pool *pool, Id p, Repodata *data, char *pubkey, int flags)
-{
-  unsigned char *pkts, *pkts_orig;
-  int pktsl, pl = 0, tag, l, hl;
-
-  if (!unarmor(pubkey, &pkts, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----"))
-    {
-      pool_error(pool, 0, "unarmor failure");
-      return 0;
-    }
-  pkts_orig = pkts;
-  tag = 6;
-  while (pktsl)
-    {
-      if (tag == 6)
-       {
-         setutf8string(data, p, SOLVABLE_DESCRIPTION, pubkey);
-         pl = parsepubkey(pool->solvables + p, data, pkts, pktsl, flags);
-#ifdef ENABLE_RPMDB
-         parsepubkey_rpm(pool->solvables + p, data, pkts, pktsl);
-#endif
-         if (!pl || !(flags & ADD_MULTIPLE_PUBKEYS))
-           break;
-       }
-      pkts += pl;
-      pktsl -= pl;
-      hl = parsepkgheader(pkts, pktsl, &tag, &l);
-      if (!hl)
-       break;
-      pl = l + hl;
-      if (tag == 6)
-        p = repo_add_solvable(pool->solvables[p].repo);
-    }
-  solv_free((void *)pkts_orig);
-  return 1;
-}
-
-#ifdef ENABLE_RPMDB
-
-int
-repo_add_rpmdb_pubkeys(Repo *repo, int flags)
-{
-  Pool *pool = repo->pool;
-  Queue q;
-  int i;
-  char *str;
-  Repodata *data;
-  const char *rootdir = 0;
-  void *state;
-
-  data = repo_add_repodata(repo, flags);
-  if (flags & REPO_USE_ROOTDIR)
-    rootdir = pool_get_rootdir(pool);
-  state = rpm_state_create(repo->pool, rootdir);
-  queue_init(&q);
-  rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q);
-  for (i = 0; i < q.count; i++)
-    {
-      Id p, p2;
-      void *handle;
-      unsigned long long itime;
-
-      handle = rpm_byrpmdbid(state, q.elements[i]);
-      if (!handle)
-       continue;
-      str = rpm_query(handle, SOLVABLE_DESCRIPTION);
-      if (!str)
-       continue;
-      p = repo_add_solvable(repo);
-      if (!pubkey2solvable(pool, p, data, str, flags))
-       {
-         solv_free(str);
-         repo_free_solvable(repo, p, 1);
-         continue;
-       }
-      solv_free(str);
-      itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0);
-      for (p2 = p; p2 < pool->nsolvables; p2++)
-       {
-         if (itime)
-           repodata_set_num(data, p2, SOLVABLE_INSTALLTIME, itime);
-         if (!repo->rpmdbid)
-           repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
-         repo->rpmdbid[p2 - repo->start] = q.elements[i];
-       }
-    }
-  queue_free(&q);
-  rpm_state_free(state);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-#endif
-
-static char *
-solv_slurp(FILE *fp, int *lenp)
-{
-  int l, ll;
-  char *buf = 0;
-  int bufl = 0;
-
-  for (l = 0; ; l += ll)
-    {
-      if (bufl - l < 4096)
-       {
-         bufl += 4096;
-         buf = solv_realloc(buf, bufl);
-       }
-      ll = fread(buf + l, 1, bufl - l, fp);
-      if (ll < 0)
-       {
-         buf = solv_free(buf);
-         l = 0;
-         break;
-       }
-      if (ll == 0)
-       {
-         buf[l] = 0;   /* always zero-terminate */
-         break;
-       }
-    }
-  if (lenp)
-    *lenp = l;
-  return buf;
-}
-
-Id
-repo_add_pubkey(Repo *repo, const char *keyfile, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  Id p;
-  char *buf;
-  FILE *fp;
-
-  data = repo_add_repodata(repo, flags);
-  buf = 0;
-  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keyfile) : keyfile, "r")) == 0)
-    {
-      pool_error(pool, -1, "%s: %s", keyfile, strerror(errno));
-      return 0;
-    }
-  if ((buf = solv_slurp(fp, 0)) == 0)
-    {
-      pool_error(pool, -1, "%s: %s", keyfile, strerror(errno));
-      fclose(fp);
-      return 0;
-    }
-  fclose(fp);
-  p = repo_add_solvable(repo);
-  if (!pubkey2solvable(pool, p, data, buf, flags))
-    {
-      repo_free_solvable(repo, p, 1);
-      solv_free(buf);
-      return 0;
-    }
-  if (!(flags & REPO_NO_LOCATION))
-    {
-      Id p2;
-      for (p2 = p; p2 < pool->nsolvables; p2++)
-        repodata_set_location(data, p2, 0, 0, keyfile);
-    }
-  solv_free(buf);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return p;
-}
-
-static int
-is_sig_packet(unsigned char *sig, int sigl)
-{
-  if (!sigl)
-    return 0;
-  if ((sig[0] & 0x80) == 0 || (sig[0] & 0x40 ? sig[0] & 0x3f : sig[0] >> 2 & 0x0f) != 2)
-    return 0;
-  return 1;
-}
-
-static int
-is_pubkey_packet(unsigned char *pkt, int pktl)
-{
-  if (!pktl)
-    return 0;
-  if ((pkt[0] & 0x80) == 0 || (pkt[0] & 0x40 ? pkt[0] & 0x3f : pkt[0] >> 2 & 0x0f) != 6)
-    return 0;
-  return 1;
-}
-
-static void
-add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int pbufl, int flags)
-{
-  Id p = repo_add_solvable(repo);
-  char *solvversion = pool_tmpjoin(pool, "libsolv-", LIBSOLV_VERSION_STRING, 0);
-  char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion);
-  setutf8string(data, p, SOLVABLE_DESCRIPTION, descr);
-  parsepubkey(pool->solvables + p, data, pbuf, pbufl, flags);
-#ifdef ENABLE_RPMDB
-  parsepubkey_rpm(pool->solvables + p, data, pbuf, pbufl);
-#endif
-}
-
-int
-repo_add_keyring(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  unsigned char *buf, *p, *pbuf;
-  int bufl, l, pl, pbufl;
-
-  data = repo_add_repodata(repo, flags);
-  buf = (unsigned char *)solv_slurp(fp, &bufl);
-  if (buf && !is_pubkey_packet(buf, bufl))
-    {
-      /* assume ascii armored */
-      unsigned char *nbuf = 0, *ubuf;
-      int nl, ubufl;
-      bufl = 0;
-      for (l = 0; (nl = unarmor((char *)buf + l, &ubuf, &ubufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) != 0; l += nl)
-       {
-         /* found another block. concat. */
-         nbuf = solv_realloc(nbuf, bufl + ubufl);
-         if (ubufl)
-           memcpy(nbuf + bufl, ubuf, ubufl);
-          bufl += ubufl;
-         solv_free(ubuf);
-       }
-      solv_free(buf);
-      buf = nbuf;
-    }
-  /* now split into pubkey parts, ignoring the packets we don't know */
-  pbuf = 0;
-  pbufl = 0;
-  for (p = buf; bufl; p += pl, bufl -= pl)
-    {
-      int tag;
-      int hl = parsepkgheader(p, bufl, &tag, &pl);
-      if (!hl)
-       break;
-      pl += hl;
-      if (tag == 6)
-       {
-         /* found new pubkey! flush old */
-         if (pbufl)
-           {
-             add_one_pubkey(pool, repo, data, pbuf, pbufl, flags);
-             pbuf = solv_free(pbuf);
-             pbufl = 0;
-           }
-       }
-      if (tag != 6 && !pbufl)
-       continue;
-      if (tag != 6 && tag != 2 && tag != 13 && tag != 14 && tag != 17)
-       continue;
-      /* we want that packet. concat. */
-      pbuf = solv_realloc(pbuf, pbufl + pl);
-      memcpy(pbuf + pbufl, p, pl);
-      pbufl += pl;
-    }
-  if (pbufl)
-    add_one_pubkey(pool, repo, data, pbuf, pbufl, flags);
-  solv_free(pbuf);
-  solv_free(buf);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-int
-repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i, nent, sl;
-  struct dirent **namelist;
-  char *rkeydir;
-
-  data = repo_add_repodata(repo, flags);
-  nent = scandir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keydir) : keydir, &namelist, 0, alphasort);
-  if (nent == -1)
-    return pool_error(pool, -1, "%s: %s", keydir, strerror(errno));
-  rkeydir = pool_prepend_rootdir(pool, keydir);
-  sl = suffix ? strlen(suffix) : 0;
-  for (i = 0; i < nent; i++)
-    {
-      const char *dn = namelist[i]->d_name;
-      int l;
-      if (*dn == '.' && !(flags & ADD_KEYDIR_WITH_DOTFILES))
-       continue;
-      l = strlen(dn);
-      if (sl && (l < sl || strcmp(dn + l - sl, suffix) != 0))
-       continue;
-      repo_add_pubkey(repo, pool_tmpjoin(pool, rkeydir, "/", dn), flags | REPO_REUSE_REPODATA);
-    }
-  solv_free(rkeydir);
-  for (i = 0; i < nent; i++)
-    solv_free(namelist[i]);
-  solv_free(namelist);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-Solvsig *
-solvsig_create(FILE *fp)
-{
-  Solvsig *ss;
-  unsigned char *sig;
-  int sigl, hl, tag, pktl;
-  struct pgpsig pgpsig;
-
-  if ((sig = (unsigned char *)solv_slurp(fp, &sigl)) == 0)
-    return 0;
-  if (!is_sig_packet(sig, sigl))
-    {
-      /* not a raw sig, check armored */
-      unsigned char *nsig;
-      if (!unarmor((char *)sig, &nsig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----"))
-       {
-         solv_free(sig);
-         return 0;
-       }
-      solv_free(sig);
-      sig = nsig;
-      if (!is_sig_packet(sig, sigl))
-       {
-         solv_free(sig);
-         return 0;
-       }
-    }
-  hl = parsepkgheader(sig, sigl, &tag, &pktl);
-  if (!hl || tag != 2 || !pktl)
-    {
-      solv_free(sig);
-      return 0;
-    }
-  pgpsig_init(&pgpsig, sig + hl, pktl);
-  if (pgpsig.type != 0 || !pgpsig.haveissuer)
-    {
-      solv_free(sig);
-      return 0;
-    }
-  ss = solv_calloc(1, sizeof(*ss));
-  ss->sigpkt = solv_memdup(sig + hl, pktl);
-  ss->sigpktl = pktl;
-  solv_free(sig);
-  solv_bin2hex(pgpsig.issuer, 8, ss->keyid);
-  ss->htype = pgphashalgo2type(pgpsig.hashalgo);
-  ss->created = pgpsig.created;
-  ss->expires = pgpsig.expires;
-  return ss;
-}
-
-void
-solvsig_free(Solvsig *ss)
-{
-  solv_free(ss->sigpkt);
-  solv_free(ss);
-}
-
-static int
-repo_find_all_pubkeys_cmp(const void *va, const void *vb, void *dp)
-{
-  Pool *pool = dp;
-  Id a = *(Id *)va;
-  Id b = *(Id *)vb;
-  /* cannot use evrcmp, as rpm says '0' > 'a' */
-  return strcmp(pool_id2str(pool, pool->solvables[b].evr), pool_id2str(pool, pool->solvables[a].evr));
-}
-
-void
-repo_find_all_pubkeys(Repo *repo, const char *keyid, Queue *q)
-{
-  Id p;
-  Solvable *s;
-
-  queue_empty(q);
-  if (!keyid)
-    return;
-  queue_init(q);
-  FOR_REPO_SOLVABLES(repo, p, s)
-    {
-      const char *kidstr, *evr = pool_id2str(s->repo->pool, s->evr);
-
-      if (!evr || strncmp(evr, keyid + 8, 8) != 0)
-       continue;
-      kidstr = solvable_lookup_str(s, PUBKEY_KEYID);
-      if (kidstr && !strcmp(kidstr, keyid))
-        queue_push(q, p);
-    }
-  if (q->count > 1)
-    solv_sort(q->elements, q->count, sizeof(Id), repo_find_all_pubkeys_cmp, repo->pool);
-}
-
-Id
-repo_find_pubkey(Repo *repo, const char *keyid)
-{
-  Queue q;
-  Id p;
-  queue_init(&q);
-  repo_find_all_pubkeys(repo, keyid, &q);
-  p = q.count ? q.elements[0] : 0;
-  queue_free(&q);
-  return p;
-}
-
-#ifdef ENABLE_PGPVRFY
-
-/* warning: does not check key expiry/revokation, same as with gpgv or rpm */
-/* returns the Id of the pubkey that verified the signature */
-Id
-repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid)
-{
-  Id p;
-  Queue q;
-  int i;
-
-  if (!sigdata || !keyid)
-    return 0;
-  queue_init(&q);
-  repo_find_all_pubkeys(repo, keyid, &q);
-  for (i = 0; i < q.count; i++)
-    {
-      int pubdatal;
-      const unsigned char *pubdata = repo_lookup_binary(repo, q.elements[i], PUBKEY_DATA, &pubdatal);
-      if (pubdata && solv_pgpvrfy(pubdata, pubdatal, sigdata, sigdatal))
-       break;
-    }
-  p = i < q.count? q.elements[i] : 0;
-  queue_free(&q);
-  return p;
-}
-
-Id
-solvsig_verify(Solvsig *ss, Repo *repo, Chksum *chk)
-{
-  struct pgpsig pgpsig;
-  void *chk2;
-  Id p;
-
-  if (!chk || solv_chksum_isfinished(chk))
-    return 0;
-  pgpsig_init(&pgpsig, ss->sigpkt, ss->sigpktl);
-  chk2 = solv_chksum_create_clone(chk);
-  pgpsig_makesigdata(&pgpsig, ss->sigpkt, ss->sigpktl, 0, 0, 0, 0, chk2);
-  solv_chksum_free(chk2, 0);
-  if (!pgpsig.sigdata)
-    return 0;
-  p = repo_verify_sigdata(repo, pgpsig.sigdata, pgpsig.sigdatal, ss->keyid);
-  solv_free(pgpsig.sigdata);
-  return p;
-}
-
-#endif
-
diff --git a/libsolv-0.6.15/ext/repo_pubkey.h b/libsolv-0.6.15/ext/repo_pubkey.h
deleted file mode 100644 (file)
index dbc7f9c..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include "repo.h"
-#include "chksum.h"
-
-#define ADD_KEYDIR_WITH_DOTFILES       (1 << 8)
-#define ADD_WITH_SUBKEYS               (1 << 9)
-#define ADD_MULTIPLE_PUBKEYS           (1 << 10)
-#define ADD_WITH_KEYSIGNATURES         (1 << 11)
-
-extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags);
-extern Id repo_add_pubkey(Repo *repo, const char *keyfile, int flags);
-extern int repo_add_keyring(Repo *repo, FILE *fp, int flags);
-extern int repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags);
-
-/* signature parsing */
-typedef struct _solvsig {
-  unsigned char *sigpkt;
-  int sigpktl;
-  Id htype;
-  unsigned int created;
-  unsigned int expires;
-  char keyid[17];
-} Solvsig;
-
-Solvsig *solvsig_create(FILE *fp);
-void solvsig_free(Solvsig *ss);
-Id solvsig_verify(Solvsig *ss, Repo *repo, Chksum *chk);
-
-Id repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid);
-Id repo_find_pubkey(Repo *repo, const char *keyid);
-void repo_find_all_pubkeys(Repo *repo, const char *keyid, Queue *q);
-
diff --git a/libsolv-0.6.15/ext/repo_releasefile_products.c b/libsolv-0.6.15/ext/repo_releasefile_products.c
deleted file mode 100644 (file)
index a40bc98..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * repo_products.c
- *
- * Parses all files below 'proddir'
- * See http://en.opensuse.org/Product_Management/Code11
- *
- *
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#define DISABLE_SPLIT
-#include "tools_util.h"
-#include "repo_releasefile_products.h"
-
-#define BUFF_SIZE 8192
-
-struct parsedata {
-  Repo *repo;
-  struct joindata jd;
-};
-
-static void
-add_releasefile_product(struct parsedata *pd, FILE *fp)
-{
-  Repo *repo = pd->repo;
-  Pool *pool = repo->pool;
-  char buf[BUFF_SIZE];
-  Id name = 0;
-  Id arch = 0;
-  Id version = 0;
-  int lnum = 0; /* line number */
-  char *ptr, *ptr1;
-
-  /* parse /etc/<xyz>-release file */
-  while (fgets(buf, sizeof(buf), fp))
-    {
-      /* remove trailing \n */
-      int l = strlen(buf);
-      if (l && buf[l - 1] == '\n')
-       buf[--l] = 0;
-      ++lnum;
-
-      if (lnum == 1)
-       {
-         /* 1st line, <name> [(<arch>)] */
-         ptr = strchr(buf, '(');
-         if (ptr)
-           {
-             ptr1 = ptr - 1;
-             *ptr++ = 0;
-           }
-         else
-           ptr1 = buf + l - 1;
-
-         /* track back until non-blank, non-digit */
-         while (ptr1 > buf
-                && (*ptr1 == ' ' || isdigit(*ptr1) || *ptr1 == '.'))
-           --ptr1;
-         *(++ptr1) = 0;
-         name = pool_str2id(pool, join2(&pd->jd, "product", ":", buf), 1);
-
-         if (ptr)
-           {
-             /* have arch */
-             char *ptr1 = strchr(ptr, ')');
-             if (ptr1)
-               {
-                 *ptr1 = 0;
-                 /* downcase arch */
-                 ptr1 = ptr;
-                 while (*ptr1)
-                   {
-                     if (isupper(*ptr1))
-                        *ptr1 = tolower(*ptr1);
-                     ++ptr1;
-                   }
-                 arch = pool_str2id(pool, ptr, 1);
-               }
-           }
-       }
-      else if (strncmp(buf, "VERSION", 7) == 0)
-       {
-         ptr = strchr(buf + 7, '=');
-         if (ptr)
-           {
-             while (*++ptr == ' ')
-               ;
-             version = makeevr(pool, ptr);
-           }
-       }
-    }
-  if (name)
-    {
-      Solvable *s = pool_id2solvable(pool, repo_add_solvable(repo));
-      s->name = name;
-      s->evr = version ? version : ID_EMPTY;
-      s->arch = arch ? arch : ARCH_NOARCH;
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-       s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-    }
-}
-
-
-int
-repo_add_releasefile_products(Repo *repo, const char *dirpath, int flags)
-{
-  DIR *dir;
-  struct dirent *entry;
-  FILE *fp;
-  char *fullpath;
-  struct parsedata pd;
-
-  if (!dirpath)
-    dirpath = "/etc";
-  if (flags & REPO_USE_ROOTDIR)
-    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
-  dir = opendir(dirpath);
-  if (!dir)
-    {
-      if (flags & REPO_USE_ROOTDIR)
-        solv_free((char *)dirpath);
-      return 0;
-    }
-
-  memset(&pd, 0, sizeof(pd));
-  pd.repo = repo;
-  while ((entry = readdir(dir)))
-    {
-      int len = strlen(entry->d_name);
-      if (len > 8 && !strcmp(entry->d_name + len - 8, "-release"))
-        {
-         /* skip /etc/lsb-release, thats not a product per-se */
-         if (strcmp(entry->d_name, "lsb-release") == 0)
-           continue;
-         fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
-         if ((fp = fopen(fullpath, "r")) == 0)
-           {
-             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
-             continue;
-           }
-         add_releasefile_product(&pd, fp);
-         fclose(fp);
-       }
-    }
-  closedir(dir);
-  join_freemem(&pd.jd);
-  if (flags & REPO_USE_ROOTDIR)
-    solv_free((char *)dirpath);
-
-  if (!(flags & REPO_NO_INTERNALIZE) && (flags & REPO_REUSE_REPODATA) != 0)
-    repodata_internalize(repo_last_repodata(repo));
-  return 0;
-}
-
diff --git a/libsolv-0.6.15/ext/repo_releasefile_products.h b/libsolv-0.6.15/ext/repo_releasefile_products.h
deleted file mode 100644 (file)
index 0535975..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_releasefile_products(Repo *repo, const char *dirpath, int flags);
diff --git a/libsolv-0.6.15/ext/repo_repomdxml.c b/libsolv-0.6.15/ext/repo_repomdxml.c
deleted file mode 100644 (file)
index 1d1197e..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define DO_ARRAY 1
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <expat.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_repomdxml.h"
-
-/*
-<repomd>
-
-  <!-- these tags are available in create repo > 0.9.6 -->
-  <revision>timestamp_or_arbitrary_user_supplied_string</revision>
-  <tags>
-    <content>opensuse</content>
-    <content>i386</content>
-    <content>other string</content>
-    <distro cpeid="cpe://o:opensuse_project:opensuse:11">openSUSE 11.0</distro>
-  </tags>
-  <!-- end -->
-
-  <data type="primary">
-    <location href="repodata/primary.xml.gz"/>
-    <checksum type="sha">e9162516fa25fec8d60caaf4682d2e49967786cc</checksum>
-    <timestamp>1215708444</timestamp>
-    <open-checksum type="sha">c796c48184cd5abc260e4ba929bdf01be14778a7</open-checksum>
-  </data>
-  <data type="filelists">
-    <location href="repodata/filelists.xml.gz"/>
-    <checksum type="sha">1c638295c49e9707c22810004ebb0799791fcf45</checksum>
-    <timestamp>1215708445</timestamp>
-    <open-checksum type="sha">54a40d5db3df0813b8acbe58cea616987eb9dc16</open-checksum>
-  </data>
-  <data type="other">
-    <location href="repodata/other.xml.gz"/>
-    <checksum type="sha">a81ef39eaa70e56048f8351055119d8c82af2491</checksum>
-    <timestamp>1215708447</timestamp>
-    <open-checksum type="sha">4d1ee867c8864025575a2fb8fde3b85371d51978</open-checksum>
-  </data>
-  <data type="deltainfo">
-    <location href="repodata/deltainfo.xml.gz"/>
-    <checksum type="sha">5880cfa5187026a24a552d3c0650904a44908c28</checksum>
-    <timestamp>1215708447</timestamp>
-    <open-checksum type="sha">7c964a2c3b17df5bfdd962c3be952c9ca6978d8b</open-checksum>
-  </data>
-  <data type="updateinfo">
-    <location href="repodata/updateinfo.xml.gz"/>
-    <checksum type="sha">4097f7e25c7bb0770ae31b2471a9c8c077ee904b</checksum>
-    <timestamp>1215708447</timestamp>
-    <open-checksum type="sha">24f8252f3dd041e37e7c3feb2d57e02b4422d316</open-checksum>
-  </data>
-  <data type="diskusage">
-    <location href="repodata/diskusage.xml.gz"/>
-    <checksum type="sha">4097f7e25c7bb0770ae31b2471a9c8c077ee904b</checksum>
-    <timestamp>1215708447</timestamp>
-    <open-checksum type="sha">24f8252f3dd041e37e7c3feb2d57e02b4422d316</open-checksum>
-  </data>
-</repomd>
-
-support also extension suseinfo format
-<suseinfo>
-  <expire>timestamp</expire>
-  <products>
-    <id>...</id>
-  </products>
-  <kewwords>
-    <k>...</k>
-  </keywords>
-</suseinfo>
-
-*/
-
-enum state {
-  STATE_START,
-  /* extension tags */
-  STATE_SUSEINFO,
-  STATE_EXPIRE,
-  STATE_KEYWORDS,
-  STATE_KEYWORD,
-
-  /* normal repomd.xml */
-  STATE_REPOMD,
-  STATE_REVISION,
-  STATE_TAGS,
-  STATE_REPO,
-  STATE_CONTENT,
-  STATE_DISTRO,
-  STATE_UPDATES,
-  STATE_DATA,
-  STATE_LOCATION,
-  STATE_CHECKSUM,
-  STATE_TIMESTAMP,
-  STATE_OPENCHECKSUM,
-  STATE_SIZE,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
-  /* suseinfo tags */
-  { STATE_START,       "repomd",          STATE_REPOMD, 0 },
-  { STATE_START,       "suseinfo",        STATE_SUSEINFO, 0 },
-  /* we support the tags element in suseinfo in case
-     createrepo version does not support it yet */
-  { STATE_SUSEINFO,    "tags",            STATE_TAGS, 0 },
-  { STATE_SUSEINFO,    "expire",          STATE_EXPIRE, 1 },
-  { STATE_SUSEINFO,    "keywords",        STATE_KEYWORDS, 0 },
-  /* keywords is the suse extension equivalent of
-     tags/content when this one was not yet available.
-     therefore we parse both */
-  { STATE_KEYWORDS,    "k",               STATE_KEYWORD, 1 },
-  /* standard tags */
-  { STATE_REPOMD,      "revision",        STATE_REVISION, 1 },
-  { STATE_REPOMD,      "tags",            STATE_TAGS,  0 },
-  { STATE_REPOMD,      "data",            STATE_DATA,  0 },
-
-  { STATE_TAGS,        "repo",            STATE_REPO,    1 },
-  { STATE_TAGS,        "content",         STATE_CONTENT, 1 },
-  { STATE_TAGS,        "distro",          STATE_DISTRO,  1 },
-  /* this tag is only valid in suseinfo.xml for now */
-  { STATE_TAGS,        "updates",         STATE_UPDATES,  1 },
-
-  { STATE_DATA,        "location",        STATE_LOCATION, 0 },
-  { STATE_DATA,        "checksum",        STATE_CHECKSUM, 1 },
-  { STATE_DATA,        "timestamp",       STATE_TIMESTAMP, 1 },
-  { STATE_DATA,        "open-checksum",   STATE_OPENCHECKSUM, 1 },
-  { STATE_DATA,        "size",            STATE_SIZE, 1 },
-  { NUMSTATES }
-};
-
-
-struct parsedata {
-  int ret;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-
-  XML_Parser *parser;
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  int timestamp;
-  /* handles for collection
-     structures */
-  /* repo updates */
-  Id ruhandle;
-  /* repo products */
-  Id rphandle;
-  /* repo data handle */
-  Id rdhandle;
-
-  Id chksumtype;
-};
-
-/*
- * find attribute
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  /*Pool *pool = pd->pool;*/
-  struct stateswitch *sw;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_REPOMD:
-      {
-        const char *updstr;
-
-        /* this should be OBSOLETE soon */
-        updstr = find_attr("updates", atts);
-        if (updstr)
-          {
-            char *value = solv_strdup(updstr);
-            char *fvalue = value; /* save the first */
-            while (value)
-             {
-               char *p = strchr(value, ',');
-               if (*p)
-                 *p++ = 0;
-               if (*value)
-                 repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value);
-               value = p;
-             }
-           free(fvalue);
-          }
-        break;
-      }
-    case STATE_DISTRO:
-      {
-        /* this is extra metadata about the product this repository
-           was designed for */
-        const char *cpeid = find_attr("cpeid", atts);
-        pd->rphandle = repodata_new_handle(pd->data);
-        /* set the cpeid for the product
-           the label is set in the content of the tag */
-        if (cpeid)
-          repodata_set_poolstr(pd->data, pd->rphandle, REPOSITORY_PRODUCT_CPEID, cpeid);
-        break;
-      }
-    case STATE_UPDATES:
-      {
-        /* this is extra metadata about the product this repository
-           was designed for */
-        const char *cpeid = find_attr("cpeid", atts);
-        pd->ruhandle = repodata_new_handle(pd->data);
-        /* set the cpeid for the product
-           the label is set in the content of the tag */
-        if (cpeid)
-          repodata_set_poolstr(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_CPEID, cpeid);
-        break;
-      }
-    case STATE_DATA:
-      {
-        const char *type= find_attr("type", atts);
-        pd->rdhandle = repodata_new_handle(pd->data);
-       if (type)
-          repodata_set_poolstr(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TYPE, type);
-        break;
-      }
-    case STATE_LOCATION:
-      {
-        const char *href = find_attr("href", atts);
-       if (href)
-          repodata_set_str(pd->data, pd->rdhandle, REPOSITORY_REPOMD_LOCATION, href);
-        break;
-      }
-    case STATE_CHECKSUM:
-    case STATE_OPENCHECKSUM:
-      {
-        const char *type= find_attr("type", atts);
-        pd->chksumtype = type && *type ? solv_chksum_str2type(type) : 0;
-       if (!pd->chksumtype)
-          pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), type ? type : "NULL");
-        break;
-      }
-    default:
-      break;
-    }
-  return;
-}
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  /* Pool *pool = pd->pool; */
-
-#if 0
-  fprintf(stderr, "endElement: %s\n", name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
-    {
-    case STATE_REPOMD:
-      if (pd->timestamp > 0)
-        repodata_set_num(pd->data, SOLVID_META, REPOSITORY_TIMESTAMP, pd->timestamp);
-      break;
-    case STATE_DATA:
-      if (pd->rdhandle)
-        repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_REPOMD, pd->rdhandle);
-      pd->rdhandle = 0;
-      break;
-
-    case STATE_CHECKSUM:
-    case STATE_OPENCHECKSUM:
-      if (!pd->chksumtype)
-       break;
-      if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype))
-        pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype));
-      else
-        repodata_set_checksum(pd->data, pd->rdhandle, pd->state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, pd->content);
-      break;
-
-    case STATE_TIMESTAMP:
-      {
-        /**
-         * we want to look for the newest timestamp
-         * of all resources to save it as the time
-         * the metadata was generated
-         */
-        int timestamp = atoi(pd->content);
-       if (timestamp)
-          repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TIMESTAMP, timestamp);
-        if (timestamp > pd->timestamp)
-          pd->timestamp = timestamp;
-        break;
-      }
-    case STATE_EXPIRE:
-      {
-        int expire = atoi(pd->content);
-       if (expire > 0)
-         repodata_set_num(pd->data, SOLVID_META, REPOSITORY_EXPIRE, expire);
-        break;
-      }
-      /* repomd.xml content and suseinfo.xml keywords are equivalent */
-    case STATE_CONTENT:
-    case STATE_KEYWORD:
-      if (*pd->content)
-       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, pd->content);
-      break;
-    case STATE_REVISION:
-      if (*pd->content)
-       repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, pd->content);
-      break;
-    case STATE_DISTRO:
-      /* distro tag is used in repomd.xml to say the product this repo is
-         made for */
-      if (*pd->content)
-        repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, pd->content);
-      repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_DISTROS, pd->rphandle);
-      break;
-    case STATE_UPDATES:
-      /* updates tag is used in suseinfo.xml to say the repo updates a product
-         however it s not yet a tag standarized for repomd.xml */
-      if (*pd->content)
-        repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, pd->content);
-      repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_UPDATES, pd->ruhandle);
-      break;
-    case STATE_REPO:
-      if (*pd->content)
-       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, pd->content);
-      break;
-    case STATE_SIZE:
-      if (*pd->content)
-       repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(pd->content, 0, 10));
-      break;
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-  return;
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-int
-repo_add_repomdxml(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  struct parsedata pd;
-  Repodata *data;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  XML_Parser parser;
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  pd.timestamp = 0;
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-  pd.pool = pool;
-  pd.repo = repo;
-  pd.data = data;
-
-  pd.content = malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  pd.parser = &parser;
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_repomdxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-
-  free(pd.content);
-  return pd.ret;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/ext/repo_repomdxml.h b/libsolv-0.6.15/ext/repo_repomdxml.h
deleted file mode 100644 (file)
index 90d9d69..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_repomdxml(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.6.15/ext/repo_rpmdb.c b/libsolv-0.6.15/ext/repo_rpmdb.c
deleted file mode 100644 (file)
index d49f9d8..0000000
+++ /dev/null
@@ -1,2718 +0,0 @@
-/*
- * Copyright (c) 2007-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_rpmdb
- *
- * convert rpm db to repo
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <stdint.h>
-#include <errno.h>
-
-#include <rpm/rpmio.h>
-#include <rpm/rpmpgp.h>
-#ifndef RPM5
-#include <rpm/header.h>
-#endif
-#include <rpm/rpmdb.h>
-
-#ifndef DB_CREATE
-# if defined(SUSE) || defined(HAVE_RPM_DB_H)
-#  include <rpm/db.h>
-# else
-#  include <db.h>
-# endif
-#endif
-
-#include "pool.h"
-#include "repo.h"
-#include "hash.h"
-#include "util.h"
-#include "queue.h"
-#include "chksum.h"
-#include "repo_rpmdb.h"
-#include "repo_solv.h"
-#ifdef ENABLE_COMPLEX_DEPS
-#include "pool_parserpmrichdep.h"
-#endif
-
-/* 3: added triggers */
-/* 4: fixed triggers */
-/* 5: fixed checksum copying */
-#define RPMDB_COOKIE_VERSION 5
-
-#define TAG_NAME               1000
-#define TAG_VERSION            1001
-#define TAG_RELEASE            1002
-#define TAG_EPOCH              1003
-#define TAG_SUMMARY            1004
-#define TAG_DESCRIPTION                1005
-#define TAG_BUILDTIME          1006
-#define TAG_BUILDHOST          1007
-#define TAG_INSTALLTIME                1008
-#define TAG_SIZE               1009
-#define TAG_DISTRIBUTION       1010
-#define TAG_VENDOR             1011
-#define TAG_LICENSE            1014
-#define TAG_PACKAGER           1015
-#define TAG_GROUP              1016
-#define TAG_URL                        1020
-#define TAG_ARCH               1022
-#define TAG_FILESIZES          1028
-#define TAG_FILEMODES          1030
-#define TAG_FILEMD5S           1035
-#define TAG_FILELINKTOS                1036
-#define TAG_FILEFLAGS          1037
-#define TAG_SOURCERPM          1044
-#define TAG_PROVIDENAME                1047
-#define TAG_REQUIREFLAGS       1048
-#define TAG_REQUIRENAME                1049
-#define TAG_REQUIREVERSION     1050
-#define TAG_NOSOURCE           1051
-#define TAG_NOPATCH            1052
-#define TAG_CONFLICTFLAGS      1053
-#define TAG_CONFLICTNAME       1054
-#define TAG_CONFLICTVERSION    1055
-#define TAG_TRIGGERNAME                1066
-#define TAG_TRIGGERVERSION     1067
-#define TAG_TRIGGERFLAGS       1068
-#define TAG_CHANGELOGTIME      1080
-#define TAG_CHANGELOGNAME      1081
-#define TAG_CHANGELOGTEXT      1082
-#define TAG_OBSOLETENAME       1090
-#define TAG_FILEDEVICES                1095
-#define TAG_FILEINODES         1096
-#define TAG_SOURCEPACKAGE      1106
-#define TAG_PROVIDEFLAGS       1112
-#define TAG_PROVIDEVERSION     1113
-#define TAG_OBSOLETEFLAGS      1114
-#define TAG_OBSOLETEVERSION    1115
-#define TAG_DIRINDEXES         1116
-#define TAG_BASENAMES          1117
-#define TAG_DIRNAMES           1118
-#define TAG_PAYLOADFORMAT      1124
-#define TAG_PATCHESNAME                1133
-#define TAG_FILECOLORS         1140
-#define TAG_OLDSUGGESTSNAME    1156
-#define TAG_OLDSUGGESTSVERSION 1157
-#define TAG_OLDSUGGESTSFLAGS   1158
-#define TAG_OLDENHANCESNAME    1159
-#define TAG_OLDENHANCESVERSION 1160
-#define TAG_OLDENHANCESFLAGS   1161
-
-/* rpm5 tags */
-#define TAG_DISTEPOCH          1218
-
-/* rpm4 tags */
-#define TAG_LONGFILESIZES      5008
-#define TAG_LONGSIZE           5009
-#define TAG_RECOMMENDNAME      5046
-#define TAG_RECOMMENDVERSION   5047
-#define TAG_RECOMMENDFLAGS     5048
-#define TAG_SUGGESTNAME                5049
-#define TAG_SUGGESTVERSION     5050
-#define TAG_SUGGESTFLAGS       5051
-#define TAG_SUPPLEMENTNAME     5052
-#define TAG_SUPPLEMENTVERSION  5053
-#define TAG_SUPPLEMENTFLAGS    5054
-#define TAG_ENHANCENAME                5055
-#define TAG_ENHANCEVERSION     5056
-#define TAG_ENHANCEFLAGS       5057
-
-/* signature tags */
-#define        TAG_SIGBASE             256
-#define TAG_SIGMD5             (TAG_SIGBASE + 5)
-#define TAG_SHA1HEADER         (TAG_SIGBASE + 13)
-
-#define SIGTAG_SIZE            1000
-#define SIGTAG_PGP             1002    /* RSA signature */
-#define SIGTAG_MD5             1004    /* header+payload md5 checksum */
-#define SIGTAG_GPG             1005    /* DSA signature */
-
-#define DEP_LESS               (1 << 1)
-#define DEP_GREATER            (1 << 2)
-#define DEP_EQUAL              (1 << 3)
-#define DEP_STRONG             (1 << 27)
-#define DEP_PRE_IN             ((1 << 6) | (1 << 9) | (1 << 10))
-#define DEP_PRE_UN             ((1 << 6) | (1 << 11) | (1 << 12))
-
-#define FILEFLAG_GHOST         (1 <<  6)
-
-
-#ifdef RPM5
-# define RPM_INDEX_SIZE 4      /* just the rpmdbid */
-#else
-# define RPM_INDEX_SIZE 8      /* rpmdbid + array index */
-#endif
-
-
-typedef struct rpmhead {
-  int cnt;
-  int dcnt;
-  unsigned char *dp;
-  int forcebinary;             /* sigh, see rh#478907 */
-  unsigned char data[1];
-} RpmHead;
-
-
-static inline unsigned char *
-headfindtag(RpmHead *h, int tag)
-{
-  unsigned int i;
-  unsigned char *d, taga[4];
-  d = h->dp - 16;
-  taga[0] = tag >> 24;
-  taga[1] = tag >> 16;
-  taga[2] = tag >> 8;
-  taga[3] = tag;
-  for (i = 0; i < h->cnt; i++, d -= 16)
-    if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
-      return d;
-  return 0;
-}
-
-static int
-headexists(RpmHead *h, int tag)
-{
-  return headfindtag(h, tag) ? 1 : 0;
-}
-
-static unsigned int *
-headint32array(RpmHead *h, int tag, int *cnt)
-{
-  unsigned int i, o, *r;
-  unsigned char *d = headfindtag(h, tag);
-
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o + 4 * i > h->dcnt)
-    return 0;
-  d = h->dp + o;
-  r = solv_calloc(i ? i : 1, sizeof(unsigned int));
-  if (cnt)
-    *cnt = i;
-  for (o = 0; o < i; o++, d += 4)
-    r[o] = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
-  return r;
-}
-
-/* returns the first entry of an integer array */
-static unsigned int
-headint32(RpmHead *h, int tag)
-{
-  unsigned int i, o;
-  unsigned char *d = headfindtag(h, tag);
-
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (i == 0 || o + 4 * i > h->dcnt)
-    return 0;
-  d = h->dp + o;
-  return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
-}
-
-static unsigned long long *
-headint64array(RpmHead *h, int tag, int *cnt)
-{
-  unsigned int i, o;
-  unsigned long long *r;
-  unsigned char *d = headfindtag(h, tag);
-
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o + 8 * i > h->dcnt)
-    return 0;
-  d = h->dp + o;
-  r = solv_calloc(i ? i : 1, sizeof(unsigned long long));
-  if (cnt)
-    *cnt = i;
-  for (o = 0; o < i; o++, d += 8)
-    {
-      unsigned int x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
-      r[o] = (unsigned long long)x << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
-    }
-  return r;
-}
-
-/* returns the first entry of an 64bit integer array */
-static unsigned long long
-headint64(RpmHead *h, int tag)
-{
-  unsigned int i, o;
-  unsigned char *d = headfindtag(h, tag);
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (i == 0 || o + 8 * i > h->dcnt)
-    return 0;
-  d = h->dp + o;
-  i = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
-  return (unsigned long long)i << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
-}
-
-static unsigned int *
-headint16array(RpmHead *h, int tag, int *cnt)
-{
-  unsigned int i, o, *r;
-  unsigned char *d = headfindtag(h, tag);
-
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o + 4 * i > h->dcnt)
-    return 0;
-  d = h->dp + o;
-  r = solv_calloc(i ? i : 1, sizeof(unsigned int));
-  if (cnt)
-    *cnt = i;
-  for (o = 0; o < i; o++, d += 2)
-    r[o] = d[0] << 8 | d[1];
-  return r;
-}
-
-static char *
-headstring(RpmHead *h, int tag)
-{
-  unsigned int o;
-  unsigned char *d = headfindtag(h, tag);
-  /* 6: STRING, 9: I18NSTRING */
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || (d[7] != 6 && d[7] != 9))
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  if (o >= h->dcnt)
-    return 0;
-  return (char *)h->dp + o;
-}
-
-static char **
-headstringarray(RpmHead *h, int tag, int *cnt)
-{
-  unsigned int i, o;
-  unsigned char *d = headfindtag(h, tag);
-  char **r;
-
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  r = solv_calloc(i ? i : 1, sizeof(char *));
-  if (cnt)
-    *cnt = i;
-  d = h->dp + o;
-  for (o = 0; o < i; o++)
-    {
-      r[o] = (char *)d;
-      if (o + 1 < i)
-        d += strlen((char *)d) + 1;
-      if (d >= h->dp + h->dcnt)
-        {
-          solv_free(r);
-          return 0;
-        }
-    }
-  return r;
-}
-
-static unsigned char *
-headbinary(RpmHead *h, int tag, unsigned int *sizep)
-{
-  unsigned int i, o;
-  unsigned char *d = headfindtag(h, tag);
-  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 7)
-    return 0;
-  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
-  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
-  if (o > h->dcnt || o + i < o || o + i > h->dcnt)
-    return 0;
-  if (sizep)
-    *sizep = i;
-  return h->dp + o;
-}
-
-static char *headtoevr(RpmHead *h)
-{
-  unsigned int epoch;
-  char *version, *v;
-  char *release;
-  char *evr;
-  char *distepoch;
-
-  version  = headstring(h, TAG_VERSION);
-  release  = headstring(h, TAG_RELEASE);
-  epoch = headint32(h, TAG_EPOCH);
-  if (!version || !release)
-    {
-      fprintf(stderr, "headtoevr: bad rpm header\n");
-      return 0;
-    }
-  for (v = version; *v >= '0' && *v <= '9'; v++)
-    ;
-  if (epoch || (v != version && *v == ':'))
-    {
-      char epochbuf[11];        /* 32bit decimal will fit in */
-      sprintf(epochbuf, "%u", epoch);
-      evr = solv_malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1);
-      sprintf(evr, "%s:%s-%s", epochbuf, version, release);
-    }
-  else
-    {
-      evr = solv_malloc(strlen(version) + 1 + strlen(release) + 1);
-      sprintf(evr, "%s-%s", version, release);
-    }
-  distepoch = headstring(h, TAG_DISTEPOCH);
-  if (distepoch && *distepoch)
-    {
-      int l = strlen(evr);
-      evr = solv_realloc(evr, l + strlen(distepoch) + 2);
-      evr[l++] = ':';
-      strcpy(evr + l, distepoch);
-    }
-  return evr;
-}
-
-
-static void
-setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
-{
-  if (str[solv_validutf8(str)])
-    {
-      char *ustr = solv_latin1toutf8(str);     /* not utf8, assume latin1 */
-      repodata_set_str(repodata, handle, tag, ustr);
-      solv_free(ustr);
-    }
-  else
-    repodata_set_str(repodata, handle, tag, str);
-}
-
-/*
- * strong: 0: ignore strongness
- *         1: filter to strong
- *         2: filter to weak
- */
-static unsigned int
-makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags)
-{
-  char **n, **v;
-  unsigned int *f;
-  int i, cc, nc, vc, fc;
-  int haspre, premask;
-  unsigned int olddeps;
-  Id *ida;
-  int strong = 0;
-
-  n = headstringarray(rpmhead, tagn, &nc);
-  if (!n)
-    {
-      switch (tagn)
-       {
-       case TAG_SUGGESTNAME:
-         tagn = TAG_OLDSUGGESTSNAME;
-         tagv = TAG_OLDSUGGESTSVERSION;
-         tagf = TAG_OLDSUGGESTSFLAGS;
-         strong = -1;
-         break;
-       case TAG_ENHANCENAME:
-         tagn = TAG_OLDENHANCESNAME;
-         tagv = TAG_OLDENHANCESVERSION;
-         tagf = TAG_OLDENHANCESFLAGS;
-         strong = -1;
-         break;
-       case TAG_RECOMMENDNAME:
-         tagn = TAG_OLDSUGGESTSNAME;
-         tagv = TAG_OLDSUGGESTSVERSION;
-         tagf = TAG_OLDSUGGESTSFLAGS;
-         strong = 1;
-         break;
-       case TAG_SUPPLEMENTNAME:
-         tagn = TAG_OLDENHANCESNAME;
-         tagv = TAG_OLDENHANCESVERSION;
-         tagf = TAG_OLDENHANCESFLAGS;
-         strong = 1;
-         break;
-       default:
-         return 0;
-       }
-      n = headstringarray(rpmhead, tagn, &nc);
-    }
-  if (!n || !nc)
-    return 0;
-  vc = fc = 0;
-  v = headstringarray(rpmhead, tagv, &vc);
-  f = headint32array(rpmhead, tagf, &fc);
-  if (!v || !f || nc != vc || nc != fc)
-    {
-      char *pkgname = rpm_query(rpmhead, 0);
-      pool_error(pool, 0, "bad dependency entries for %s: %d %d %d", pkgname ? pkgname : "<NULL>", nc, vc, fc);
-      solv_free(pkgname);
-      solv_free(n);
-      solv_free(v);
-      solv_free(f);
-      return 0;
-    }
-
-  cc = nc;
-  haspre = 0;  /* add no prereq marker */
-  premask = tagn == TAG_REQUIRENAME ? DEP_PRE_IN | DEP_PRE_UN : 0;
-  if ((flags & RPM_ADD_NO_RPMLIBREQS) || strong)
-    {
-      /* we do filtering */
-      cc = 0;
-      for (i = 0; i < nc; i++)
-       {
-         if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
-           continue;
-         if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
-           if (!strncmp(n[i], "rpmlib(", 7))
-             continue;
-         if ((f[i] & premask) != 0)
-           haspre = 1;
-         cc++;
-       }
-    }
-  else if (premask)
-    {
-      /* no filtering, just look for the first prereq */
-      for (i = 0; i < nc; i++)
-       if ((f[i] & premask) != 0)
-         {
-           haspre = 1;
-           break;
-         }
-    }
-  if (cc == 0)
-    {
-      solv_free(n);
-      solv_free(v);
-      solv_free(f);
-      return 0;
-    }
-  cc += haspre;                /* add slot for the prereq marker */
-  olddeps = repo_reserve_ids(repo, 0, cc);
-  ida = repo->idarraydata + olddeps;
-  for (i = 0; ; i++)
-    {
-      Id id;
-      if (i == nc)
-       {
-         if (haspre != 1)
-           break;
-         haspre = 2;   /* pass two: prereqs */
-         i = 0;
-         *ida++ = SOLVABLE_PREREQMARKER;
-       }
-      if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
-       continue;
-      if (haspre)
-       {
-         if (haspre == 1 && (f[i] & premask) != 0)
-           continue;
-         if (haspre == 2 && (f[i] & premask) == 0)
-           continue;
-       }
-      if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
-       if (!strncmp(n[i], "rpmlib(", 7))
-         continue;
-#ifdef ENABLE_COMPLEX_DEPS
-      if ((f[i] & (DEP_LESS|DEP_EQUAL|DEP_GREATER)) == 0 && n[i][0] == '(')
-       {
-         id = pool_parserpmrichdep(pool, n[i]);
-         if (id)
-           *ida++ = id;
-         else
-           cc--;
-         continue;
-       }
-#endif
-      id = pool_str2id(pool, n[i], 1);
-      if (f[i] & (DEP_LESS|DEP_GREATER|DEP_EQUAL))
-       {
-         Id evr;
-         int fl = 0;
-         if ((f[i] & DEP_LESS) != 0)
-           fl |= REL_LT;
-         if ((f[i] & DEP_EQUAL) != 0)
-           fl |= REL_EQ;
-         if ((f[i] & DEP_GREATER) != 0)
-           fl |= REL_GT;
-         if (v[i][0] == '0' && v[i][1] == ':' && v[i][2])
-           evr = pool_str2id(pool, v[i] + 2, 1);
-         else
-           evr = pool_str2id(pool, v[i], 1);
-         id = pool_rel2id(pool, id, evr, fl, 1);
-       }
-      *ida++ = id;
-    }
-  *ida++ = 0;
-  repo->idarraysize += cc + 1;
-  solv_free(n);
-  solv_free(v);
-  solv_free(f);
-  return olddeps;
-}
-
-
-static void
-adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc)
-{
-  Id did;
-  int i, fszc;
-  unsigned int *fkb, *fn, *fsz, *fm, *fino;
-  unsigned long long *fsz64;
-  unsigned int inotest[256], inotestok;
-
-  if (!fc)
-    return;
-  if ((fsz64 = headint64array(rpmhead, TAG_LONGFILESIZES, &fszc)) != 0)
-    {
-      /* convert to kbyte */
-      fsz = solv_malloc2(fszc, sizeof(*fsz));
-      for (i = 0; i < fszc; i++)
-        fsz[i] = fsz64[i] ? fsz64[i] / 1024 + 1 : 0;
-      solv_free(fsz64);
-    }
-  else if ((fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc)) != 0)
-    {
-      /* convert to kbyte */
-      for (i = 0; i < fszc; i++)
-        if (fsz[i])
-         fsz[i] = fsz[i] / 1024 + 1;
-    }
-  else
-    return;
-  if (fc != fszc)
-    {
-      solv_free(fsz);
-      return;
-    }
-
-  /* stupid rpm records sizes of directories, so we have to check the mode */
-  fm = headint16array(rpmhead, TAG_FILEMODES, &fszc);
-  if (!fm || fc != fszc)
-    {
-      solv_free(fsz);
-      solv_free(fm);
-      return;
-    }
-  fino = headint32array(rpmhead, TAG_FILEINODES, &fszc);
-  if (!fino || fc != fszc)
-    {
-      solv_free(fsz);
-      solv_free(fm);
-      solv_free(fino);
-      return;
-    }
-
-  /* kill hardlinked entries */
-  inotestok = 0;
-  if (fc < sizeof(inotest))
-    {
-      /* quick test just hashing the inode numbers */
-      memset(inotest, 0, sizeof(inotest));
-      for (i = 0; i < fc; i++)
-       {
-         int off, bit;
-         if (fsz[i] == 0 || !S_ISREG(fm[i]))
-           continue;   /* does not matter */
-         off = (fino[i] >> 5) & (sizeof(inotest)/sizeof(*inotest) - 1);
-         bit = 1 << (fino[i] & 31);
-         if ((inotest[off] & bit) != 0)
-           break;
-         inotest[off] |= bit;
-       }
-      if (i == fc)
-       inotestok = 1;  /* no conflict found */
-    }
-  if (!inotestok)
-    {
-      /* hardlinked files are possible, check ino/dev pairs */
-      unsigned int *fdev = headint32array(rpmhead, TAG_FILEDEVICES, &fszc);
-      unsigned int *fx, j;
-      unsigned int mask, hash, hh;
-      if (!fdev || fc != fszc)
-       {
-         solv_free(fsz);
-         solv_free(fm);
-         solv_free(fdev);
-         solv_free(fino);
-         return;
-       }
-      mask = fc;
-      while ((mask & (mask - 1)) != 0)
-       mask = mask & (mask - 1);
-      mask <<= 2;
-      if (mask > sizeof(inotest)/sizeof(*inotest))
-        fx = solv_calloc(mask, sizeof(unsigned int));
-      else
-       {
-         fx = inotest;
-         memset(fx, 0, mask * sizeof(unsigned int));
-       }
-      mask--;
-      for (i = 0; i < fc; i++)
-       {
-         if (fsz[i] == 0 || !S_ISREG(fm[i]))
-           continue;
-         hash = (fino[i] + fdev[i] * 31) & mask;
-          hh = 7;
-         while ((j = fx[hash]) != 0)
-           {
-             if (fino[j - 1] == fino[i] && fdev[j - 1] == fdev[i])
-               {
-                 fsz[i] = 0;   /* kill entry */
-                 break;
-               }
-             hash = (hash + hh++) & mask;
-           }
-         if (!j)
-           fx[hash] = i + 1;
-       }
-      if (fx != inotest)
-        solv_free(fx);
-      solv_free(fdev);
-    }
-  solv_free(fino);
-
-  /* sum up inode count and kbytes for each directory */
-  fn = solv_calloc(dc, sizeof(unsigned int));
-  fkb = solv_calloc(dc, sizeof(unsigned int));
-  for (i = 0; i < fc; i++)
-    {
-      if (di[i] >= dc)
-       continue;       /* corrupt entry */
-      fn[di[i]]++;
-      if (fsz[i] == 0 || !S_ISREG(fm[i]))
-       continue;
-      fkb[di[i]] += fsz[i];
-    }
-  solv_free(fsz);
-  solv_free(fm);
-  /* commit */
-  for (i = 0; i < dc; i++)
-    {
-      if (!fn[i])
-       continue;
-      if (!*dn[i])
-       {
-         Solvable *s = data->repo->pool->solvables + handle;
-          if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-           did = repodata_str2dir(data, "/usr/src", 1);
-         else
-           continue;   /* work around rpm bug */
-       }
-      else
-        did = repodata_str2dir(data, dn[i], 1);
-      repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, did, fkb[i], fn[i]);
-    }
-  solv_free(fn);
-  solv_free(fkb);
-}
-
-static int
-is_filtered(const char *dir)
-{
-  if (!dir)
-    return 1;
-  /* the dirs always have a trailing / in rpm */
-  if (strstr(dir, "bin/"))
-    return 0;
-  if (!strncmp(dir, "/etc/", 5))
-    return 0;
-  if (!strcmp(dir, "/usr/lib/"))
-    return 2;
-  return 1;
-}
-
-static void
-addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
-{
-  char **bn;
-  char **dn;
-  unsigned int *di;
-  int bnc, dnc, dic;
-  int i;
-  Id lastdid = 0;
-  unsigned int lastdii = -1;
-  int lastfiltered = 0;
-
-  if (!data)
-    return;
-  bn = headstringarray(rpmhead, TAG_BASENAMES, &bnc);
-  if (!bn)
-    return;
-  dn = headstringarray(rpmhead, TAG_DIRNAMES, &dnc);
-  if (!dn)
-    {
-      solv_free(bn);
-      return;
-    }
-  di = headint32array(rpmhead, TAG_DIRINDEXES, &dic);
-  if (!di)
-    {
-      solv_free(bn);
-      solv_free(dn);
-      return;
-    }
-  if (bnc != dic)
-    {
-      pool_error(data->repo->pool, 0, "bad filelist");
-      return;
-    }
-
-  adddudata(data, handle, rpmhead, dn, di, bnc, dnc);
-
-  for (i = 0; i < bnc; i++)
-    {
-      Id did;
-      char *b = bn[i];
-
-      if (di[i] == lastdii)
-       did = lastdid;
-      else
-       {
-         if (di[i] >= dnc)
-           continue;   /* corrupt entry */
-         lastdii = di[i];
-         if ((flags & RPM_ADD_FILTERED_FILELIST) != 0)
-           {
-             lastfiltered = is_filtered(dn[di[i]]);
-             if (lastfiltered == 1)
-               continue;
-           }
-         did = repodata_str2dir(data, dn[lastdii], 1);
-         if (!did)
-           did = repodata_str2dir(data, "/", 1);
-         lastdid = did;
-       }
-      if (b && *b == '/')      /* work around rpm bug */
-       b++;
-      if (lastfiltered)
-       {
-         if (lastfiltered != 2 || strcmp(b, "sendmail"))
-           continue;
-       }
-      repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b);
-    }
-  solv_free(bn);
-  solv_free(dn);
-  solv_free(di);
-}
-
-static void
-addchangelog(Repodata *data, Id handle, RpmHead *rpmhead)
-{
-  char **cn;
-  char **cx;
-  unsigned int *ct;
-  int i, cnc, cxc, ctc;
-  Queue hq;
-
-  ct = headint32array(rpmhead, TAG_CHANGELOGTIME, &ctc);
-  cx = headstringarray(rpmhead, TAG_CHANGELOGTEXT, &cxc);
-  cn = headstringarray(rpmhead, TAG_CHANGELOGNAME, &cnc);
-  if (!ct || !cx || !cn || !ctc || ctc != cxc || ctc != cnc)
-    {
-      solv_free(ct);
-      solv_free(cx);
-      solv_free(cn);
-      return;
-    }
-  queue_init(&hq);
-  for (i = 0; i < ctc; i++)
-    {
-      Id h = repodata_new_handle(data);
-      if (ct[i])
-        repodata_set_num(data, h, SOLVABLE_CHANGELOG_TIME, ct[i]);
-      if (cn[i])
-        setutf8string(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]);
-      if (cx[i])
-        setutf8string(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]);
-      queue_push(&hq, h);
-    }
-  for (i = 0; i < hq.count; i++)
-    repodata_add_flexarray(data, handle, SOLVABLE_CHANGELOG, hq.elements[i]);
-  queue_free(&hq);
-  solv_free(ct);
-  solv_free(cx);
-  solv_free(cn);
-}
-
-static void
-set_description_author(Repodata *data, Id handle, char *str)
-{
-  char *aut, *p;
-  for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
-    if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
-      break;
-  if (aut)
-    {
-      /* oh my, found SUSE special author section */
-      int l = aut - str;
-      str = solv_strdup(str);
-      aut = str + l;
-      str[l] = 0;
-      while (l > 0 && str[l - 1] == '\n')
-       str[--l] = 0;
-      if (l)
-       setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
-      p = aut + 19;
-      aut = str;       /* copy over */
-      while (*p == ' ' || *p == '\n')
-       p++;
-      while (*p)
-       {
-         if (*p == '\n')
-           {
-             *aut++ = *p++;
-             while (*p == ' ')
-               p++;
-             continue;
-           }
-         *aut++ = *p++;
-       }
-      while (aut != str && aut[-1] == '\n')
-       aut--;
-      *aut = 0;
-      if (*str)
-       setutf8string(data, handle, SOLVABLE_AUTHORS, str);
-      free(str);
-    }
-  else if (*str)
-    setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
-}
-
-static int
-rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
-{
-  char *name;
-  char *evr;
-  char *sourcerpm;
-
-  name = headstring(rpmhead, TAG_NAME);
-  if (!name)
-    {
-      pool_error(pool, 0, "package has no name");
-      return 0;
-    }
-  if (!strcmp(name, "gpg-pubkey"))
-    return 0;
-  s->name = pool_str2id(pool, name, 1);
-  sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
-  if (sourcerpm || (rpmhead->forcebinary && !headexists(rpmhead, TAG_SOURCEPACKAGE)))
-    s->arch = pool_str2id(pool, headstring(rpmhead, TAG_ARCH), 1);
-  else
-    {
-      if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
-        s->arch = ARCH_NOSRC;
-      else
-        s->arch = ARCH_SRC;
-    }
-  if (!s->arch)
-    s->arch = ARCH_NOARCH;
-  evr = headtoevr(rpmhead);
-  s->evr = pool_str2id(pool, evr, 1);
-  s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
-
-  s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0);
-  if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-  s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags);
-  s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0);
-  s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0);
-
-  s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0);
-  s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0);
-  s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0);
-  s->enhances  = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0);
-
-  s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0);
-  s->conflicts = repo_fix_conflicts(repo, s->conflicts);
-
-  if (data)
-    {
-      Id handle;
-      char *str;
-      unsigned int u32;
-      unsigned long long u64;
-
-      handle = s - pool->solvables;
-      str = headstring(rpmhead, TAG_SUMMARY);
-      if (str)
-        setutf8string(data, handle, SOLVABLE_SUMMARY, str);
-      str = headstring(rpmhead, TAG_DESCRIPTION);
-      if (str)
-       set_description_author(data, handle, str);
-      str = headstring(rpmhead, TAG_GROUP);
-      if (str)
-        repodata_set_poolstr(data, handle, SOLVABLE_GROUP, str);
-      str = headstring(rpmhead, TAG_LICENSE);
-      if (str)
-        repodata_set_poolstr(data, handle, SOLVABLE_LICENSE, str);
-      str = headstring(rpmhead, TAG_URL);
-      if (str)
-       repodata_set_str(data, handle, SOLVABLE_URL, str);
-      str = headstring(rpmhead, TAG_DISTRIBUTION);
-      if (str)
-       repodata_set_poolstr(data, handle, SOLVABLE_DISTRIBUTION, str);
-      str = headstring(rpmhead, TAG_PACKAGER);
-      if (str)
-       repodata_set_poolstr(data, handle, SOLVABLE_PACKAGER, str);
-      if ((flags & RPM_ADD_WITH_PKGID) != 0)
-       {
-         unsigned char *chksum;
-         unsigned int chksumsize;
-         chksum = headbinary(rpmhead, TAG_SIGMD5, &chksumsize);
-         if (chksum && chksumsize == 16)
-           repodata_set_bin_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, chksum);
-       }
-      if ((flags & RPM_ADD_WITH_HDRID) != 0)
-       {
-         str = headstring(rpmhead, TAG_SHA1HEADER);
-         if (str && strlen(str) == 40)
-           repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA1, str);
-         else if (str && strlen(str) == 64)
-           repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA256, str);
-       }
-      u32 = headint32(rpmhead, TAG_BUILDTIME);
-      if (u32)
-        repodata_set_num(data, handle, SOLVABLE_BUILDTIME, u32);
-      u32 = headint32(rpmhead, TAG_INSTALLTIME);
-      if (u32)
-        repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, u32);
-      u64 = headint64(rpmhead, TAG_LONGSIZE);
-      if (u64)
-        repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u64);
-      else
-       {
-         u32 = headint32(rpmhead, TAG_SIZE);
-         if (u32)
-           repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u32);
-       }
-      if (sourcerpm)
-       repodata_set_sourcepkg(data, handle, sourcerpm);
-      if ((flags & RPM_ADD_TRIGGERS) != 0)
-       {
-         Id id, lastid;
-         unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0);
-
-         lastid = 0;
-         for (; (id = repo->idarraydata[ida]) != 0; ida++)
-           {
-             /* we currently do not support rel ids in incore data, so
-              * strip off versioning information */
-             while (ISRELDEP(id))
-               {
-                 Reldep *rd = GETRELDEP(pool, id);
-                 id = rd->name;
-               }
-             if (id == lastid)
-               continue;
-             repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id);
-             lastid = id;
-           }
-       }
-      if ((flags & RPM_ADD_NO_FILELIST) == 0)
-       addfilelist(data, handle, rpmhead, flags);
-      if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
-       addchangelog(data, handle, rpmhead);
-    }
-  solv_free(evr);
-  return 1;
-}
-
-
-/******************************************************************/
-/*  Rpm Database stuff
- */
-
-struct rpmdbstate {
-  Pool *pool;
-  char *rootdir;
-
-  RpmHead *rpmhead;    /* header storage space */
-  int rpmheadsize;
-
-  int dbopened;
-  DB_ENV *dbenv;       /* database environment */
-  DB *db;              /* packages database */
-  int byteswapped;     /* endianess of packages database */
-  int is_ostree;       /* read-only db that lives in /usr/share/rpm */
-};
-
-struct rpmdbentry {
-  Id rpmdbid;
-  Id nameoff;
-};
-
-#define ENTRIES_BLOCK 255
-#define NAMEDATA_BLOCK 1023
-
-
-static inline Id db2rpmdbid(unsigned char *db, int byteswapped)
-{
-#ifdef RPM5
-  return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
-#else
-# if defined(WORDS_BIGENDIAN)
-  if (!byteswapped)
-# else
-  if (byteswapped)
-# endif
-    return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
-  else
-    return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0];
-#endif
-}
-
-static inline void rpmdbid2db(unsigned char *db, Id id, int byteswapped)
-{
-#ifdef RPM5
-  db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
-#else
-# if defined(WORDS_BIGENDIAN)
-  if (!byteswapped)
-# else
-  if (byteswapped)
-# endif
-    db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
-  else
-    db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id;
-#endif
-}
-
-#ifdef FEDORA
-int
-serialize_dbenv_ops(struct rpmdbstate *state)
-{
-  char lpath[PATH_MAX];
-  mode_t oldmask;
-  int fd;
-  struct flock fl;
-
-  snprintf(lpath, PATH_MAX, "%s/var/lib/rpm/.dbenv.lock", state->rootdir ? state->rootdir : "");
-  oldmask = umask(022);
-  fd = open(lpath, (O_RDWR|O_CREAT), 0644);
-  umask(oldmask);
-  if (fd < 0)
-    return -1;
-  memset(&fl, 0, sizeof(fl));
-  fl.l_type = F_WRLCK;
-  fl.l_whence = SEEK_SET;
-  for (;;)
-    {
-      if (fcntl(fd, F_SETLKW, &fl) != -1)
-       return fd;
-      if (errno != EINTR)
-       break;
-    }
-  close(fd);
-  return -1;
-}
-#endif
-
-/* should look in /usr/lib/rpm/macros instead, but we want speed... */
-static int
-opendbenv(struct rpmdbstate *state)
-{
-  const char *rootdir = state->rootdir;
-  char dbpath[PATH_MAX];
-  DB_ENV *dbenv = 0;
-  int r;
-
-  if (db_env_create(&dbenv, 0))
-    return pool_error(state->pool, 0, "db_env_create: %s", strerror(errno));
-#if defined(FEDORA) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5))
-  dbenv->set_thread_count(dbenv, 8);
-#endif
-  snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm", rootdir ? rootdir : "");
-  if (access(dbpath, W_OK) == -1)
-    {
-      snprintf(dbpath, PATH_MAX, "%s/usr/share/rpm/Packages", rootdir ? rootdir : "");
-      if (access(dbpath, R_OK) == 0)
-       state->is_ostree = 1;
-      snprintf(dbpath, PATH_MAX, "%s%s", rootdir ? rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
-      r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
-    }
-  else
-    {
-#ifdef FEDORA
-      int serialize_fd = serialize_dbenv_ops(state);
-      r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 0644);
-      if (serialize_fd >= 0)
-       close(serialize_fd);
-#else
-      r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
-#endif
-    }
-  if (r)
-    {
-      pool_error(state->pool, 0, "dbenv->open: %s", strerror(errno));
-      dbenv->close(dbenv, 0);
-      return 0;
-    }
-  state->dbenv = dbenv;
-  return 1;
-}
-
-static void
-closedbenv(struct rpmdbstate *state)
-{
-#ifdef FEDORA
-  uint32_t eflags = 0;
-#endif
-
-  if (!state->dbenv)
-    return;
-#ifdef FEDORA
-  (void)state->dbenv->get_open_flags(state->dbenv, &eflags);
-  if (!(eflags & DB_PRIVATE))
-    {
-      int serialize_fd = serialize_dbenv_ops(state);
-      state->dbenv->close(state->dbenv, 0);
-      if (serialize_fd >= 0)
-       close(serialize_fd);
-    }
-  else
-    state->dbenv->close(state->dbenv, 0);
-#else
-  state->dbenv->close(state->dbenv, 0);
-#endif
-  state->dbenv = 0;
-}
-
-static int
-openpkgdb(struct rpmdbstate *state)
-{
-  if (state->dbopened)
-    return state->dbopened > 0 ? 1 : 0;
-  state->dbopened = -1;
-  if (!state->dbenv && !opendbenv(state))
-    return 0;
-  if (db_create(&state->db, state->dbenv, 0))
-    {
-      pool_error(state->pool, 0, "db_create: %s", strerror(errno));
-      state->db = 0;
-      closedbenv(state);
-      return 0;
-    }
-  if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664))
-    {
-      pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno));
-      state->db->close(state->db, 0);
-      state->db = 0;
-      closedbenv(state);
-      return 0;
-    }
-  if (state->db->get_byteswapped(state->db, &state->byteswapped))
-    {
-      pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
-      state->db->close(state->db, 0);
-      state->db = 0;
-      closedbenv(state);
-      return 0;
-    }
-  state->dbopened = 1;
-  return 1;
-}
-
-/* get the rpmdbids of all installed packages from the Name index database.
- * This is much faster then querying the big Packages database */
-static struct rpmdbentry *
-getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap)
-{
-  DB_ENV *dbenv = 0;
-  DB *db = 0;
-  DBC *dbc = 0;
-  int byteswapped;
-  DBT dbkey;
-  DBT dbdata;
-  unsigned char *dp;
-  int dl;
-  Id nameoff;
-
-  char *namedata = 0;
-  int namedatal = 0;
-  struct rpmdbentry *entries = 0;
-  int nentries = 0;
-
-  *nentriesp = 0;
-  if (namedatap)
-    *namedatap = 0;
-
-  if (!state->dbenv && !opendbenv(state))
-    return 0;
-  dbenv = state->dbenv;
-  if (db_create(&db, dbenv, 0))
-    {
-      pool_error(state->pool, 0, "db_create: %s", strerror(errno));
-      return 0;
-    }
-  if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664))
-    {
-      pool_error(state->pool, 0, "db->open %s: %s", index, strerror(errno));
-      db->close(db, 0);
-      return 0;
-    }
-  if (db->get_byteswapped(db, &byteswapped))
-    {
-      pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
-      db->close(db, 0);
-      return 0;
-    }
-  if (db->cursor(db, NULL, &dbc, 0))
-    {
-      pool_error(state->pool, 0, "db->cursor: %s", strerror(errno));
-      db->close(db, 0);
-      return 0;
-    }
-  memset(&dbkey, 0, sizeof(dbkey));
-  memset(&dbdata, 0, sizeof(dbdata));
-  if (match)
-    {
-      dbkey.data = (void *)match;
-      dbkey.size = strlen(match);
-    }
-  while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0)
-    {
-      if (!match && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10))
-       continue;
-      dl = dbdata.size;
-      dp = dbdata.data;
-      nameoff = namedatal;
-      if (namedatap)
-       {
-         namedata = solv_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK);
-         memcpy(namedata + namedatal, dbkey.data, dbkey.size);
-         namedata[namedatal + dbkey.size] = 0;
-         namedatal += dbkey.size + 1;
-       }
-      while(dl >= RPM_INDEX_SIZE)
-       {
-         entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
-         entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped);
-         entries[nentries].nameoff = nameoff;
-         nentries++;
-         dp += RPM_INDEX_SIZE;
-         dl -= RPM_INDEX_SIZE;
-       }
-      if (match)
-       break;
-    }
-  dbc->c_close(dbc);
-  db->close(db, 0);
-  /* make sure that enteries is != 0 if there was no error */
-  if (!entries)
-    entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
-  *nentriesp = nentries;
-  if (namedatap)
-    *namedatap = namedata;
-  return entries;
-}
-
-/* retrive header by rpmdbid */
-static int
-getrpmdbid(struct rpmdbstate *state, Id rpmdbid)
-{
-  unsigned char buf[16];
-  DBT dbkey;
-  DBT dbdata;
-  RpmHead *rpmhead;
-
-  if (!rpmdbid)
-    {
-      pool_error(state->pool, 0, "illegal rpmdbid");
-      return -1;
-    }
-  if (state->dbopened != 1 && !openpkgdb(state))
-    return -1;
-  rpmdbid2db(buf, rpmdbid, state->byteswapped);
-  memset(&dbkey, 0, sizeof(dbkey));
-  memset(&dbdata, 0, sizeof(dbdata));
-  dbkey.data = buf;
-  dbkey.size = 4;
-  dbdata.data = 0;
-  dbdata.size = 0;
-  if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
-    return 0;
-  if (dbdata.size < 8)
-    {
-      pool_error(state->pool, 0, "corrupt rpm database (size)");
-      return -1;
-    }
-  if (dbdata.size > state->rpmheadsize)
-    {
-      state->rpmheadsize = dbdata.size + 128;
-      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
-    }
-  rpmhead = state->rpmhead;
-  memcpy(buf, dbdata.data, 8);
-  rpmhead->forcebinary = 1;
-  rpmhead->cnt = buf[0] << 24  | buf[1] << 16  | buf[2] << 8 | buf[3];
-  rpmhead->dcnt = buf[4] << 24  | buf[5] << 16  | buf[6] << 8 | buf[7];
-  if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
-    {
-      pool_error(state->pool, 0, "corrupt rpm database (data size)");
-      return -1;
-    }
-  memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
-  rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-  return 1;
-}
-
-/* retrive header by berkeleydb cursor */
-static Id
-getrpmcursor(struct rpmdbstate *state, DBC *dbc)
-{
-  unsigned char buf[16];
-  DBT dbkey;
-  DBT dbdata;
-  RpmHead *rpmhead;
-  Id dbid;
-
-  memset(&dbkey, 0, sizeof(dbkey));
-  memset(&dbdata, 0, sizeof(dbdata));
-  while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0)
-    {
-      if (dbkey.size != 4)
-       return pool_error(state->pool, -1, "corrupt Packages database (key size)");
-      dbid = db2rpmdbid(dbkey.data, state->byteswapped);
-      if (dbid == 0)           /* the join key */
-       continue;
-      if (dbdata.size < 8)
-       return pool_error(state->pool, -1, "corrupt rpm database (size %u)\n", dbdata.size);
-      if (dbdata.size > state->rpmheadsize)
-       {
-         state->rpmheadsize = dbdata.size + 128;
-         state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
-       }
-      rpmhead = state->rpmhead;
-      memcpy(buf, dbdata.data, 8);
-      rpmhead->forcebinary = 1;
-      rpmhead->cnt = buf[0] << 24  | buf[1] << 16  | buf[2] << 8 | buf[3];
-      rpmhead->dcnt = buf[4] << 24  | buf[5] << 16  | buf[6] << 8 | buf[7];
-      if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
-       return pool_error(state->pool, -1, "corrupt rpm database (data size)\n");
-      memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
-      rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-      return dbid;
-    }
-  return 0;
-}
-
-static void
-freestate(struct rpmdbstate *state)
-{
-  /* close down */
-  if (!state)
-    return;
-  if (state->db)
-    state->db->close(state->db, 0);
-  if (state->dbenv)
-    closedbenv(state);
-  if (state->rootdir)
-    solv_free(state->rootdir);
-  solv_free(state->rpmhead);
-}
-
-void *
-rpm_state_create(Pool *pool, const char *rootdir)
-{
-  struct rpmdbstate *state;
-  state = solv_calloc(1, sizeof(*state));
-  state->pool = pool;
-  if (rootdir)
-    state->rootdir = solv_strdup(rootdir);
-  return state;
-}
-
-void *
-rpm_state_free(void *state)
-{
-  freestate(state);
-  return solv_free(state);
-}
-
-static int
-count_headers(struct rpmdbstate *state)
-{
-  Pool *pool = state->pool;
-  char dbpath[PATH_MAX];
-  struct stat statbuf;
-  DB *db = 0;
-  DBC *dbc = 0;
-  int count = 0;
-  DBT dbkey;
-  DBT dbdata;
-
-  snprintf(dbpath, PATH_MAX, "%s%s/Name", state->rootdir ? state->rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
-  if (stat(dbpath, &statbuf))
-    return 0;
-  memset(&dbkey, 0, sizeof(dbkey));
-  memset(&dbdata, 0, sizeof(dbdata));
-  if (db_create(&db, state->dbenv, 0))
-    {
-      pool_error(pool, 0, "db_create: %s", strerror(errno));
-      return 0;
-    }
-  if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664))
-    {
-      pool_error(pool, 0, "db->open Name: %s", strerror(errno));
-      db->close(db, 0);
-      return 0;
-    }
-  if (db->cursor(db, NULL, &dbc, 0))
-    {
-      db->close(db, 0);
-      pool_error(pool, 0, "db->cursor: %s", strerror(errno));
-      return 0;
-    }
-  while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0)
-    count += dbdata.size / RPM_INDEX_SIZE;
-  dbc->c_close(dbc);
-  db->close(db, 0);
-  return count;
-}
-
-/******************************************************************/
-
-static Offset
-copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
-{
-  int cc;
-  Id *ida, *from;
-  Offset ido;
-
-  if (!fromoff)
-    return 0;
-  from = fromrepo->idarraydata + fromoff;
-  for (ida = from, cc = 0; *ida; ida++, cc++)
-    ;
-  if (cc == 0)
-    return 0;
-  ido = repo_reserve_ids(repo, 0, cc);
-  ida = repo->idarraydata + ido;
-  memcpy(ida, from, (cc + 1) * sizeof(Id));
-  repo->idarraysize += cc + 1;
-  return ido;
-}
-
-#define COPYDIR_DIRCACHE_SIZE 512
-
-static Id copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache);
-
-static inline Id
-copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  if (cache && cache[did & 255] == did)
-    return cache[(did & 255) + 256];
-  return copydir_complex(pool, data, fromdata, did, cache);
-}
-
-static Id
-copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  Id parent = dirpool_parent(&fromdata->dirpool, did);
-  Id compid = dirpool_compid(&fromdata->dirpool, did);
-  if (parent)
-    parent = copydir(pool, data, fromdata, parent, cache);
-  if (data->localpool || fromdata->localpool)
-    compid = repodata_translate_id(data, fromdata, compid, 1);
-  compid = dirpool_add_dir(&data->dirpool, parent, compid, 1);
-  if (cache)
-    {
-      cache[did & 255] = did;
-      cache[(did & 255) + 256] = compid;
-    }
-  return compid;
-}
-
-struct solvable_copy_cbdata {
-  Repodata *data;
-  Id handle;
-  Id subhandle;
-  Id *dircache;
-};
-
-static int
-solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv)
-{
-  struct solvable_copy_cbdata *cbdata = vcbdata;
-  Id id, keyname;
-  Repodata *data = cbdata->data;
-  Id handle = cbdata->handle;
-  Pool *pool = data->repo->pool;
-
-  keyname = key->name;
-  switch(key->type)
-    {
-    case REPOKEY_TYPE_ID:
-    case REPOKEY_TYPE_CONSTANTID:
-    case REPOKEY_TYPE_IDARRAY: /* used for triggers */
-      id = kv->id;
-      if (data->localpool || fromdata->localpool)
-       id = repodata_translate_id(data, fromdata, id, 1);
-      if (key->type == REPOKEY_TYPE_ID)
-        repodata_set_id(data, handle, keyname, id);
-      else if (key->type == REPOKEY_TYPE_CONSTANTID)
-        repodata_set_constantid(data, handle, keyname, id);
-      else
-        repodata_add_idarray(data, handle, keyname, id);
-      break;
-    case REPOKEY_TYPE_STR:
-      repodata_set_str(data, handle, keyname, kv->str);
-      break;
-    case REPOKEY_TYPE_VOID:
-      repodata_set_void(data, handle, keyname);
-      break;
-    case REPOKEY_TYPE_NUM:
-      repodata_set_num(data, handle, keyname, SOLV_KV_NUM64(kv));
-      break;
-    case REPOKEY_TYPE_CONSTANT:
-      repodata_set_constant(data, handle, keyname, kv->num);
-      break;
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      id = kv->id;
-      id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
-      break;
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      id = kv->id;
-      id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      repodata_add_dirstr(data, handle, keyname, id, kv->str);
-      break;
-    case REPOKEY_TYPE_FLEXARRAY:
-      if (kv->eof == 2)
-       {
-         assert(cbdata->subhandle);
-         cbdata->handle = cbdata->subhandle;
-         cbdata->subhandle = 0;
-         break;
-       }
-      if (!kv->entry)
-        {
-         assert(!cbdata->subhandle);
-         cbdata->subhandle = cbdata->handle;
-       }
-      cbdata->handle = repodata_new_handle(data);
-      repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle);
-      break;
-    default:
-      if (solv_chksum_len(key->type))
-       {
-         repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str);
-         break;
-       }
-      break;
-    }
-  return 0;
-}
-
-static void
-solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
-{
-  int p, i;
-  Repo *repo = s->repo;
-  Pool *pool = repo->pool;
-  Repo *fromrepo = r->repo;
-  struct solvable_copy_cbdata cbdata;
-
-  /* copy solvable data */
-  s->name = r->name;
-  s->evr = r->evr;
-  s->arch = r->arch;
-  s->vendor = r->vendor;
-  s->provides = copydeps(pool, repo, r->provides, fromrepo);
-  s->requires = copydeps(pool, repo, r->requires, fromrepo);
-  s->conflicts = copydeps(pool, repo, r->conflicts, fromrepo);
-  s->obsoletes = copydeps(pool, repo, r->obsoletes, fromrepo);
-  s->recommends = copydeps(pool, repo, r->recommends, fromrepo);
-  s->suggests = copydeps(pool, repo, r->suggests, fromrepo);
-  s->supplements = copydeps(pool, repo, r->supplements, fromrepo);
-  s->enhances  = copydeps(pool, repo, r->enhances, fromrepo);
-
-  /* copy all attributes */
-  if (!data)
-    return;
-  cbdata.data = data;
-  cbdata.handle = s - pool->solvables;
-  cbdata.subhandle = 0;
-  cbdata.dircache = dircache;
-  p = r - fromrepo->pool->solvables;
-#if 0
-  repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-#else
-  FOR_REPODATAS(fromrepo, i, data)
-    {
-      if (p >= data->start && p < data->end)
-        repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-      cbdata.dircache = 0;     /* only for first repodata */
-    }
-#endif
-}
-
-/* used to sort entries by package name that got returned in some database order */
-static int
-rpmids_sort_cmp(const void *va, const void *vb, void *dp)
-{
-  struct rpmdbentry const *a = va, *b = vb;
-  char *namedata = dp;
-  int r;
-  r = strcmp(namedata + a->nameoff, namedata + b->nameoff);
-  if (r)
-    return r;
-  return a->rpmdbid - b->rpmdbid;
-}
-
-static int
-pkgids_sort_cmp(const void *va, const void *vb, void *dp)
-{
-  Repo *repo = dp;
-  Pool *pool = repo->pool;
-  Solvable *a = pool->solvables + *(Id *)va;
-  Solvable *b = pool->solvables + *(Id *)vb;
-  Id *rpmdbid;
-
-  if (a->name != b->name)
-    return strcmp(pool_id2str(pool, a->name), pool_id2str(pool, b->name));
-  rpmdbid = repo->rpmdbid;
-  return rpmdbid[(a - pool->solvables) - repo->start] - rpmdbid[(b - pool->solvables) - repo->start];
-}
-
-static void
-swap_solvables(Repo *repo, Repodata *data, Id pa, Id pb)
-{
-  Pool *pool = repo->pool;
-  Solvable tmp;
-
-  tmp = pool->solvables[pa];
-  pool->solvables[pa] = pool->solvables[pb];
-  pool->solvables[pb] = tmp;
-  if (repo->rpmdbid)
-    {
-      Id tmpid = repo->rpmdbid[pa - repo->start];
-      repo->rpmdbid[pa - repo->start] = repo->rpmdbid[pb - repo->start];
-      repo->rpmdbid[pb - repo->start] = tmpid;
-    }
-  /* only works if nothing is already internalized! */
-  if (data)
-    repodata_swap_attrs(data, pa, pb);
-}
-
-static void
-mkrpmdbcookie(struct stat *st, unsigned char *cookie, int flags)
-{
-  int f = 0;
-  memset(cookie, 0, 32);
-  cookie[3] = RPMDB_COOKIE_VERSION;
-  memcpy(cookie + 16, &st->st_ino, sizeof(st->st_ino));
-  memcpy(cookie + 24, &st->st_dev, sizeof(st->st_dev));
-  if ((flags & RPM_ADD_WITH_PKGID) != 0)
-    f |= 1;
-  if ((flags & RPM_ADD_WITH_HDRID) != 0)
-    f |= 2;
-  if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
-    f |= 4;
-  if ((flags & RPM_ADD_NO_FILELIST) == 0)
-    f |= 8;
-  if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
-    cookie[1] = 1;
-  cookie[0] = f;
-}
-
-/*
- * read rpm db as repo
- *
- */
-
-int
-repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
-{
-  Pool *pool = repo->pool;
-  char dbpath[PATH_MAX];
-  struct stat packagesstat;
-  unsigned char newcookie[32];
-  const unsigned char *oldcookie = 0;
-  Id oldcookietype = 0;
-  Repodata *data;
-  int count = 0, done = 0;
-  struct rpmdbstate state;
-  int i;
-  Solvable *s;
-  unsigned int now;
-
-  now = solv_timems(0);
-  memset(&state, 0, sizeof(state));
-  state.pool = pool;
-  if (flags & REPO_USE_ROOTDIR)
-    state.rootdir = solv_strdup(pool_get_rootdir(pool));
-
-  data = repo_add_repodata(repo, flags);
-
-  if (ref && !(ref->nsolvables && ref->rpmdbid && ref->pool == repo->pool))
-    {
-      if ((flags & RPMDB_EMPTY_REFREPO) != 0)
-       repo_empty(ref, 1);
-      ref = 0;
-    }
-
-  if (!opendbenv(&state))
-    {
-      solv_free(state.rootdir);
-      return -1;
-    }
-
-  /* XXX: should get ro lock of Packages database! */
-  snprintf(dbpath, PATH_MAX, "%s%s/Packages", state.rootdir ? state.rootdir : "", state.is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
-  if (stat(dbpath, &packagesstat))
-    {
-      pool_error(pool, -1, "%s: %s", dbpath, strerror(errno));
-      freestate(&state);
-      return -1;
-    }
-  mkrpmdbcookie(&packagesstat, newcookie, flags);
-  repodata_set_bin_checksum(data, SOLVID_META, REPOSITORY_RPMDBCOOKIE, REPOKEY_TYPE_SHA256, newcookie);
-
-  if (ref)
-    oldcookie = repo_lookup_bin_checksum(ref, SOLVID_META, REPOSITORY_RPMDBCOOKIE, &oldcookietype);
-  if (!ref || !oldcookie || oldcookietype != REPOKEY_TYPE_SHA256 || memcmp(oldcookie, newcookie, 32) != 0)
-    {
-      int solvstart = 0, solvend = 0;
-      Id dbid;
-      DBC *dbc = 0;
-
-      if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
-       repo_empty(ref, 1);     /* get it out of the way */
-      if ((flags & RPMDB_REPORT_PROGRESS) != 0)
-       count = count_headers(&state);
-      if (!openpkgdb(&state))
-       {
-         freestate(&state);
-         return -1;
-       }
-      if (state.db->cursor(state.db, NULL, &dbc, 0))
-       {
-         freestate(&state);
-         return pool_error(pool, -1, "db->cursor failed");
-       }
-      i = 0;
-      s = 0;
-      while ((dbid = getrpmcursor(&state, dbc)) != 0)
-       {
-         if (dbid == -1)
-           {
-             dbc->c_close(dbc);
-             freestate(&state);
-             return -1;
-           }
-         if (!s)
-           {
-             s = pool_id2solvable(pool, repo_add_solvable(repo));
-             if (!solvstart)
-               solvstart = s - pool->solvables;
-             solvend = s - pool->solvables + 1;
-           }
-         if (!repo->rpmdbid)
-           repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
-         repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
-         if (rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
-           {
-             i++;
-             s = 0;
-           }
-         else
-           {
-             /* We can reuse this solvable, but make sure it's still
-                associated with this repo.  */
-             memset(s, 0, sizeof(*s));
-             s->repo = repo;
-           }
-         if ((flags & RPMDB_REPORT_PROGRESS) != 0)
-           {
-             if (done < count)
-               done++;
-             if (done < count && (done - 1) * 100 / count != done * 100 / count)
-               pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
-           }
-       }
-      dbc->c_close(dbc);
-      if (s)
-       {
-         /* oops, could not reuse. free it instead */
-          repo_free_solvable(repo, s - pool->solvables, 1);
-         solvend--;
-         s = 0;
-       }
-      /* now sort all solvables in the new solvstart..solvend block */
-      if (solvend - solvstart > 1)
-       {
-         Id *pkgids = solv_malloc2(solvend - solvstart, sizeof(Id));
-         for (i = solvstart; i < solvend; i++)
-           pkgids[i - solvstart] = i;
-         solv_sort(pkgids, solvend - solvstart, sizeof(Id), pkgids_sort_cmp, repo);
-         /* adapt order */
-         for (i = solvstart; i < solvend; i++)
-           {
-             int j = pkgids[i - solvstart];
-             while (j < i)
-               j = pkgids[i - solvstart] = pkgids[j - solvstart];
-             if (j != i)
-               swap_solvables(repo, data, i, j);
-           }
-         solv_free(pkgids);
-       }
-    }
-  else
-    {
-      Id dircache[COPYDIR_DIRCACHE_SIZE];              /* see copydir */
-      struct rpmdbentry *entries = 0, *rp;
-      int nentries = 0;
-      char *namedata = 0;
-      unsigned int refmask, h;
-      Id id, *refhash;
-      int res;
-
-      memset(dircache, 0, sizeof(dircache));
-
-      /* get ids of installed rpms */
-      entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata);
-      if (!entries)
-       {
-         freestate(&state);
-         return -1;
-       }
-
-      /* sort by name */
-      if (nentries > 1)
-        solv_sort(entries, nentries, sizeof(*entries), rpmids_sort_cmp, namedata);
-
-      /* create hash from dbid to ref */
-      refmask = mkmask(ref->nsolvables);
-      refhash = solv_calloc(refmask + 1, sizeof(Id));
-      for (i = 0; i < ref->end - ref->start; i++)
-       {
-         if (!ref->rpmdbid[i])
-           continue;
-         h = ref->rpmdbid[i] & refmask;
-         while (refhash[h])
-           h = (h + 317) & refmask;
-         refhash[h] = i + 1;   /* make it non-zero */
-       }
-
-      /* count the misses, they will cost us time */
-      if ((flags & RPMDB_REPORT_PROGRESS) != 0)
-        {
-         for (i = 0, rp = entries; i < nentries; i++, rp++)
-           {
-             if (refhash)
-               {
-                 Id dbid = rp->rpmdbid;
-                 h = dbid & refmask;
-                 while ((id = refhash[h]))
-                   {
-                     if (ref->rpmdbid[id - 1] == dbid)
-                       break;
-                     h = (h + 317) & refmask;
-                   }
-                 if (id)
-                   continue;
-               }
-             count++;
-           }
-        }
-
-      if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
-        s = pool_id2solvable(pool, repo_add_solvable_block_before(repo, nentries, ref));
-      else
-        s = pool_id2solvable(pool, repo_add_solvable_block(repo, nentries));
-      if (!repo->rpmdbid)
-        repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
-
-      for (i = 0, rp = entries; i < nentries; i++, rp++, s++)
-       {
-         Id dbid = rp->rpmdbid;
-         repo->rpmdbid[(s - pool->solvables) - repo->start] = rp->rpmdbid;
-         if (refhash)
-           {
-             h = dbid & refmask;
-             while ((id = refhash[h]))
-               {
-                 if (ref->rpmdbid[id - 1] == dbid)
-                   break;
-                 h = (h + 317) & refmask;
-               }
-             if (id)
-               {
-                 Solvable *r = ref->pool->solvables + ref->start + (id - 1);
-                 if (r->repo == ref)
-                   {
-                     solvable_copy(s, r, data, dircache);
-                     continue;
-                   }
-               }
-           }
-         res = getrpmdbid(&state, dbid);
-         if (res <= 0)
-           {
-             if (!res)
-               pool_error(pool, -1, "inconsistent rpm database, key %d not found. run 'rpm --rebuilddb' to fix.", dbid);
-             freestate(&state);
-             solv_free(entries);
-             solv_free(namedata);
-             solv_free(refhash);
-             return -1;
-           }
-         rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
-         if ((flags & RPMDB_REPORT_PROGRESS) != 0)
-           {
-             if (done < count)
-               done++;
-             if (done < count && (done - 1) * 100 / count != done * 100 / count)
-               pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
-           }
-       }
-
-      solv_free(entries);
-      solv_free(namedata);
-      solv_free(refhash);
-      if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
-       repo_empty(ref, 1);
-    }
-
-  freestate(&state);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  if ((flags & RPMDB_REPORT_PROGRESS) != 0)
-    pool_debug(pool, SOLV_ERROR, "%%%% 100\n");
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmdb took %d ms\n", solv_timems(now));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
-  return 0;
-}
-
-int
-repo_add_rpmdb_reffp(Repo *repo, FILE *fp, int flags)
-{
-  int res;
-  Repo *ref = 0;
-
-  if (!fp)
-    return repo_add_rpmdb(repo, 0, flags);
-  ref = repo_create(repo->pool, "add_rpmdb_reffp");
-  if (repo_add_solv(ref, fp, 0) != 0)
-    {
-      repo_free(ref, 1);
-      ref = 0;
-    }
-  if (ref && ref->start == ref->end)
-    {
-      repo_free(ref, 1);
-      ref = 0;
-    }
-  if (ref)
-    repo_disable_paging(ref);
-  res = repo_add_rpmdb(repo, ref, flags | RPMDB_EMPTY_REFREPO);
-  if (ref)
-    repo_free(ref, 1);
-  return res;
-}
-
-static inline unsigned int
-getu32(const unsigned char *dp)
-{
-  return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
-}
-
-
-Id
-repo_add_rpm(Repo *repo, const char *rpm, int flags)
-{
-  unsigned int sigdsize, sigcnt, l;
-  Pool *pool = repo->pool;
-  Solvable *s;
-  RpmHead *rpmhead = 0;
-  int rpmheadsize = 0;
-  char *payloadformat;
-  FILE *fp;
-  unsigned char lead[4096];
-  int headerstart, headerend;
-  struct stat stb;
-  Repodata *data;
-  unsigned char pkgid[16];
-  unsigned char leadsigid[16];
-  unsigned char hdrid[32];
-  int pkgidtype, leadsigidtype, hdridtype;
-  Id chksumtype = 0;
-  Chksum *chksumh = 0;
-  Chksum *leadsigchksumh = 0;
-  int forcebinary = 0;
-
-  data = repo_add_repodata(repo, flags);
-
-  if ((flags & RPM_ADD_WITH_SHA256SUM) != 0)
-    chksumtype = REPOKEY_TYPE_SHA256;
-  else if ((flags & RPM_ADD_WITH_SHA1SUM) != 0)
-    chksumtype = REPOKEY_TYPE_SHA1;
-
-  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, rpm) : rpm, "r")) == 0)
-    {
-      pool_error(pool, -1, "%s: %s", rpm, strerror(errno));
-      return 0;
-    }
-  if (fstat(fileno(fp), &stb))
-    {
-      pool_error(pool, -1, "fstat: %s", strerror(errno));
-      fclose(fp);
-      return 0;
-    }
-  if (chksumtype)
-    chksumh = solv_chksum_create(chksumtype);
-  if ((flags & RPM_ADD_WITH_LEADSIGID) != 0)
-    leadsigchksumh = solv_chksum_create(REPOKEY_TYPE_MD5);
-  if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
-    {
-      pool_error(pool, -1, "%s: not a rpm", rpm);
-      fclose(fp);
-      return 0;
-    }
-  forcebinary = lead[6] != 0 || lead[7] != 1;
-  if (chksumh)
-    solv_chksum_add(chksumh, lead, 96 + 16);
-  if (leadsigchksumh)
-    solv_chksum_add(leadsigchksumh, lead, 96 + 16);
-  if (lead[78] != 0 || lead[79] != 5)
-    {
-      pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
-      fclose(fp);
-      return 0;
-    }
-  if (getu32(lead + 96) != 0x8eade801)
-    {
-      pool_error(pool, -1, "%s: bad signature header", rpm);
-      fclose(fp);
-      return 0;
-    }
-  sigcnt = getu32(lead + 96 + 8);
-  sigdsize = getu32(lead + 96 + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x100000)
-    {
-      pool_error(pool, -1, "%s: bad signature header", rpm);
-      fclose(fp);
-      return 0;
-    }
-  sigdsize += sigcnt * 16;
-  sigdsize = (sigdsize + 7) & ~7;
-  headerstart = 96 + 16 + sigdsize;
-  pkgidtype = leadsigidtype = hdridtype = 0;
-  if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0)
-    {
-      /* extract pkgid or hdrid from the signature header */
-      if (sigdsize > rpmheadsize)
-       {
-         rpmheadsize = sigdsize + 128;
-         rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
-       }
-      if (fread(rpmhead->data, sigdsize, 1, fp) != 1)
-       {
-         pool_error(pool, -1, "%s: unexpected EOF", rpm);
-         fclose(fp);
-         return 0;
-       }
-      if (chksumh)
-       solv_chksum_add(chksumh, rpmhead->data, sigdsize);
-      if (leadsigchksumh)
-       solv_chksum_add(leadsigchksumh, rpmhead->data, sigdsize);
-      rpmhead->forcebinary = 0;
-      rpmhead->cnt = sigcnt;
-      rpmhead->dcnt = sigdsize - sigcnt * 16;
-      rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-      if ((flags & RPM_ADD_WITH_PKGID) != 0)
-       {
-         unsigned char *chksum;
-         unsigned int chksumsize;
-         chksum = headbinary(rpmhead, SIGTAG_MD5, &chksumsize);
-         if (chksum && chksumsize == 16)
-           {
-             pkgidtype = REPOKEY_TYPE_MD5;
-             memcpy(pkgid, chksum, 16);
-           }
-       }
-      if ((flags & RPM_ADD_WITH_HDRID) != 0)
-       {
-         const char *str = headstring(rpmhead, TAG_SHA1HEADER);
-         if (str && strlen(str) == 40)
-           {
-             if (solv_hex2bin(&str, hdrid, 20) == 20)
-               hdridtype = REPOKEY_TYPE_SHA1;
-           }
-         else if (str && strlen(str) == 64)
-           {
-             if (solv_hex2bin(&str, hdrid, 32) == 32)
-               hdridtype = REPOKEY_TYPE_SHA256;
-           }
-       }
-    }
-  else
-    {
-      /* just skip the signature header */
-      while (sigdsize)
-       {
-         l = sigdsize > 4096 ? 4096 : sigdsize;
-         if (fread(lead, l, 1, fp) != 1)
-           {
-             pool_error(pool, -1, "%s: unexpected EOF", rpm);
-             fclose(fp);
-             return 0;
-           }
-         if (chksumh)
-           solv_chksum_add(chksumh, lead, l);
-         if (leadsigchksumh)
-           solv_chksum_add(leadsigchksumh, lead, l);
-         sigdsize -= l;
-       }
-    }
-  if (leadsigchksumh)
-    {
-      leadsigchksumh = solv_chksum_free(leadsigchksumh, leadsigid);
-      leadsigidtype = REPOKEY_TYPE_MD5;
-    }
-  if (fread(lead, 16, 1, fp) != 1)
-    {
-      pool_error(pool, -1, "%s: unexpected EOF", rpm);
-      fclose(fp);
-      return 0;
-    }
-  if (chksumh)
-    solv_chksum_add(chksumh, lead, 16);
-  if (getu32(lead) != 0x8eade801)
-    {
-      pool_error(pool, -1, "%s: bad header", rpm);
-      fclose(fp);
-      return 0;
-    }
-  sigcnt = getu32(lead + 8);
-  sigdsize = getu32(lead + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x2000000)
-    {
-      pool_error(pool, -1, "%s: bad header", rpm);
-      fclose(fp);
-      return 0;
-    }
-  l = sigdsize + sigcnt * 16;
-  headerend = headerstart + 16 + l;
-  if (l > rpmheadsize)
-    {
-      rpmheadsize = l + 128;
-      rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
-    }
-  if (fread(rpmhead->data, l, 1, fp) != 1)
-    {
-      pool_error(pool, -1, "%s: unexpected EOF", rpm);
-      fclose(fp);
-      return 0;
-    }
-  if (chksumh)
-    solv_chksum_add(chksumh, rpmhead->data, l);
-  rpmhead->forcebinary = forcebinary;
-  rpmhead->cnt = sigcnt;
-  rpmhead->dcnt = sigdsize;
-  rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-  if (headexists(rpmhead, TAG_PATCHESNAME))
-    {
-      /* this is a patch rpm, ignore */
-      pool_error(pool, -1, "%s: is patch rpm", rpm);
-      fclose(fp);
-      solv_chksum_free(chksumh, 0);
-      solv_free(rpmhead);
-      return 0;
-    }
-  payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT);
-  if (payloadformat && !strcmp(payloadformat, "drpm"))
-    {
-      /* this is a delta rpm */
-      pool_error(pool, -1, "%s: is delta rpm", rpm);
-      fclose(fp);
-      solv_chksum_free(chksumh, 0);
-      solv_free(rpmhead);
-      return 0;
-    }
-  if (chksumh)
-    while ((l = fread(lead, 1, sizeof(lead), fp)) > 0)
-      solv_chksum_add(chksumh, lead, l);
-  fclose(fp);
-  s = pool_id2solvable(pool, repo_add_solvable(repo));
-  if (!rpm2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
-    {
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      solv_chksum_free(chksumh, 0);
-      solv_free(rpmhead);
-      return 0;
-    }
-  if (!(flags & REPO_NO_LOCATION))
-    repodata_set_location(data, s - pool->solvables, 0, 0, rpm);
-  if (S_ISREG(stb.st_mode))
-    repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
-  repodata_set_num(data, s - pool->solvables, SOLVABLE_HEADEREND, headerend);
-  if (pkgidtype)
-    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, pkgidtype, pkgid);
-  if (hdridtype)
-    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_HDRID, hdridtype, hdrid);
-  if (leadsigidtype)
-    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_LEADSIGID, leadsigidtype, leadsigid);
-  if (chksumh)
-    {
-      repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0));
-      chksumh = solv_chksum_free(chksumh, 0);
-    }
-  solv_free(rpmhead);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return s - pool->solvables;
-}
-
-Id
-repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  RpmHead *rpmhead = rpmhandle;
-  Solvable *s;
-  char *payloadformat;
-
-  data = repo_add_repodata(repo, flags);
-  if (headexists(rpmhead, TAG_PATCHESNAME))
-    {
-      pool_error(pool, -1, "is a patch rpm");
-      return 0;
-    }
-  payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT);
-  if (payloadformat && !strcmp(payloadformat, "drpm"))
-    {
-      /* this is a delta rpm */
-      pool_error(pool, -1, "is a delta rpm");
-      return 0;
-    }
-  s = pool_id2solvable(pool, repo_add_solvable(repo));
-  if (!rpm2solv(pool, repo, data, s, rpmhead, flags))
-    {
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      return 0;
-    }
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return s - pool->solvables;
-}
-
-static inline void
-linkhash(const char *lt, char *hash)
-{
-  unsigned int r = 0;
-  const unsigned char *str = (const unsigned char *)lt;
-  int l, c;
-
-  l = strlen(lt);
-  while ((c = *str++) != 0)
-    r += (r << 3) + c;
-  sprintf(hash, "%08x%08x%08x%08x", r, l, 0, 0);
-}
-
-void
-rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata)
-{
-  RpmHead *rpmhead = rpmhandle;
-  char **bn;
-  char **dn;
-  char **md = 0;
-  char **lt = 0;
-  unsigned int *di, diidx;
-  unsigned int *co = 0;
-  unsigned int *ff = 0;
-  unsigned int lastdir;
-  int lastdirl;
-  unsigned int *fm;
-  int cnt, dcnt, cnt2;
-  int i, l1, l;
-  char *space = 0;
-  int spacen = 0;
-  char md5[33];
-  struct filelistinfo info;
-
-  dn = headstringarray(rpmhead, TAG_DIRNAMES, &dcnt);
-  if (!dn)
-    return;
-  if ((flags & RPM_ITERATE_FILELIST_ONLYDIRS) != 0)
-    {
-      for (i = 0; i < dcnt; i++)
-       (*cb)(cbdata, dn[i], 0);
-      solv_free(dn);
-      return;
-    }
-  bn = headstringarray(rpmhead, TAG_BASENAMES, &cnt);
-  if (!bn)
-    {
-      solv_free(dn);
-      return;
-    }
-  di = headint32array(rpmhead, TAG_DIRINDEXES, &cnt2);
-  if (!di || cnt != cnt2)
-    {
-      solv_free(di);
-      solv_free(bn);
-      solv_free(dn);
-      return;
-    }
-  fm = headint16array(rpmhead, TAG_FILEMODES, &cnt2);
-  if (!fm || cnt != cnt2)
-    {
-      solv_free(fm);
-      solv_free(di);
-      solv_free(bn);
-      solv_free(dn);
-      return;
-    }
-  if ((flags & RPM_ITERATE_FILELIST_WITHMD5) != 0)
-    {
-      md = headstringarray(rpmhead, TAG_FILEMD5S, &cnt2);
-      if (!md || cnt != cnt2)
-       {
-         solv_free(md);
-         solv_free(fm);
-         solv_free(di);
-         solv_free(bn);
-         solv_free(dn);
-         return;
-       }
-    }
-  if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0)
-    {
-      co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2);
-      if (!co || cnt != cnt2)
-       {
-         solv_free(co);
-         solv_free(md);
-         solv_free(fm);
-         solv_free(di);
-         solv_free(bn);
-         solv_free(dn);
-         return;
-       }
-    }
-  if ((flags & RPM_ITERATE_FILELIST_NOGHOSTS) != 0)
-    {
-      ff = headint32array(rpmhead, TAG_FILEFLAGS, &cnt2);
-      if (!ff || cnt != cnt2)
-       {
-         solv_free(ff);
-         solv_free(co);
-         solv_free(md);
-         solv_free(fm);
-         solv_free(di);
-         solv_free(bn);
-         solv_free(dn);
-         return;
-       }
-    }
-  lastdir = dcnt;
-  lastdirl = 0;
-  memset(&info, 0, sizeof(info));
-  for (i = 0; i < cnt; i++)
-    {
-      if (ff && (ff[i] & FILEFLAG_GHOST) != 0)
-       continue;
-      diidx = di[i];
-      if (diidx >= dcnt)
-       continue;
-      l1 = lastdir == diidx ? lastdirl : strlen(dn[diidx]);
-      l = l1 + strlen(bn[i]) + 1;
-      if (l > spacen)
-       {
-         spacen = l + 16;
-         space = solv_realloc(space, spacen);
-       }
-      if (lastdir != diidx)
-       {
-          strcpy(space, dn[diidx]);
-         lastdir = diidx;
-         lastdirl = l1;
-       }
-      strcpy(space + l1, bn[i]);
-      info.diridx = diidx;
-      info.dirlen = l1;
-      if (fm)
-        info.mode = fm[i];
-      if (md)
-       {
-         info.digest = md[i];
-         if (fm && S_ISLNK(fm[i]))
-           {
-             info.digest = 0;
-             if (!lt)
-               {
-                 lt = headstringarray(rpmhead, TAG_FILELINKTOS, &cnt2);
-                 if (cnt != cnt2)
-                   lt = solv_free(lt);
-               }
-             if (lt)
-               {
-                 linkhash(lt[i], md5);
-                 info.digest = md5;
-               }
-           }
-         if (!info.digest)
-           {
-             sprintf(md5, "%08x%08x%08x%08x", (fm[i] >> 12) & 65535, 0, 0, 0);
-             info.digest = md5;
-           }
-       }
-      if (co)
-       info.color = co[i];
-      (*cb)(cbdata, space, &info);
-    }
-  solv_free(space);
-  solv_free(lt);
-  solv_free(md);
-  solv_free(fm);
-  solv_free(di);
-  solv_free(bn);
-  solv_free(dn);
-  solv_free(co);
-  solv_free(ff);
-}
-
-char *
-rpm_query(void *rpmhandle, Id what)
-{
-  const char *name, *arch, *sourcerpm;
-  char *evr, *r;
-  int l;
-
-  RpmHead *rpmhead = rpmhandle;
-  r = 0;
-  switch (what)
-    {
-    case 0:
-      name = headstring(rpmhead, TAG_NAME);
-      if (!name)
-       name = "";
-      sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
-      if (sourcerpm || (rpmhead->forcebinary && !headexists(rpmhead, TAG_SOURCEPACKAGE)))
-       arch = headstring(rpmhead, TAG_ARCH);
-      else
-       {
-         if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
-           arch = "nosrc";
-         else
-           arch = "src";
-       }
-      if (!arch)
-       arch = "noarch";
-      evr = headtoevr(rpmhead);
-      l = strlen(name) + 1 + strlen(evr ? evr : "") + 1 + strlen(arch) + 1;
-      r = solv_malloc(l);
-      sprintf(r, "%s-%s.%s", name, evr ? evr : "", arch);
-      solv_free(evr);
-      break;
-    case SOLVABLE_NAME:
-      name = headstring(rpmhead, TAG_NAME);
-      r = solv_strdup(name);
-      break;
-    case SOLVABLE_SUMMARY:
-      name = headstring(rpmhead, TAG_SUMMARY);
-      r = solv_strdup(name);
-      break;
-    case SOLVABLE_DESCRIPTION:
-      name = headstring(rpmhead, TAG_DESCRIPTION);
-      r = solv_strdup(name);
-      break;
-    case SOLVABLE_EVR:
-      r = headtoevr(rpmhead);
-      break;
-    }
-  return r;
-}
-
-unsigned long long
-rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound)
-{
-  RpmHead *rpmhead = rpmhandle;
-  unsigned int u32;
-
-  switch (what)
-    {
-    case SOLVABLE_INSTALLTIME:
-      u32 = headint32(rpmhead, TAG_INSTALLTIME);
-      return u32 ? u32 : notfound;
-    }
-  return notfound;
-}
-
-int
-rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq)
-{
-  struct rpmdbentry *entries;
-  int nentries, i;
-
-  entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0);
-  if (rpmdbidq)
-    {
-      queue_empty(rpmdbidq);
-      for (i = 0; i < nentries; i++)
-        queue_push(rpmdbidq, entries[i].rpmdbid);
-    }
-  solv_free(entries);
-  return nentries;
-}
-
-void *
-rpm_byrpmdbid(void *rpmstate, Id rpmdbid)
-{
-  struct rpmdbstate *state = rpmstate;
-  int r;
-
-  r = getrpmdbid(state, rpmdbid);
-  if (!r)
-    pool_error(state->pool, 0, "header #%d not in database", rpmdbid);
-  return r <= 0 ? 0 : state->rpmhead;
-}
-
-void *
-rpm_byfp(void *rpmstate, FILE *fp, const char *name)
-{
-  struct rpmdbstate *state = rpmstate;
-  /* int headerstart, headerend; */
-  RpmHead *rpmhead;
-  unsigned int sigdsize, sigcnt, l;
-  unsigned char lead[4096];
-  int forcebinary = 0;
-
-  if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
-    {
-      pool_error(state->pool, 0, "%s: not a rpm", name);
-      return 0;
-    }
-  forcebinary = lead[6] != 0 || lead[7] != 1;
-  if (lead[78] != 0 || lead[79] != 5)
-    {
-      pool_error(state->pool, 0, "%s: not a V5 header", name);
-      return 0;
-    }
-  if (getu32(lead + 96) != 0x8eade801)
-    {
-      pool_error(state->pool, 0, "%s: bad signature header", name);
-      return 0;
-    }
-  sigcnt = getu32(lead + 96 + 8);
-  sigdsize = getu32(lead + 96 + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x100000)
-    {
-      pool_error(state->pool, 0, "%s: bad signature header", name);
-      return 0;
-    }
-  sigdsize += sigcnt * 16;
-  sigdsize = (sigdsize + 7) & ~7;
-  /* headerstart = 96 + 16 + sigdsize; */
-  while (sigdsize)
-    {
-      l = sigdsize > 4096 ? 4096 : sigdsize;
-      if (fread(lead, l, 1, fp) != 1)
-       {
-         pool_error(state->pool, 0, "%s: unexpected EOF", name);
-         return 0;
-       }
-      sigdsize -= l;
-    }
-  if (fread(lead, 16, 1, fp) != 1)
-    {
-      pool_error(state->pool, 0, "%s: unexpected EOF", name);
-      return 0;
-    }
-  if (getu32(lead) != 0x8eade801)
-    {
-      pool_error(state->pool, 0, "%s: bad header", name);
-      return 0;
-    }
-  sigcnt = getu32(lead + 8);
-  sigdsize = getu32(lead + 12);
-  if (sigcnt >= 0x100000 || sigdsize >= 0x2000000)
-    {
-      pool_error(state->pool, 0, "%s: bad header", name);
-      return 0;
-    }
-  l = sigdsize + sigcnt * 16;
-  /* headerend = headerstart + 16 + l; */
-  if (l > state->rpmheadsize)
-    {
-      state->rpmheadsize = l + 128;
-      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
-    }
-  rpmhead = state->rpmhead;
-  if (fread(rpmhead->data, l, 1, fp) != 1)
-    {
-      pool_error(state->pool, 0, "%s: unexpected EOF", name);
-      return 0;
-    }
-  rpmhead->forcebinary = forcebinary;
-  rpmhead->cnt = sigcnt;
-  rpmhead->dcnt = sigdsize;
-  rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-  return rpmhead;
-}
-
-#ifdef ENABLE_RPMDB_BYRPMHEADER
-
-void *
-rpm_byrpmh(void *rpmstate, Header h)
-{
-  struct rpmdbstate *state = rpmstate;
-  const unsigned char *uh;
-  unsigned int sigdsize, sigcnt, l;
-  RpmHead *rpmhead;
-
-#ifndef RPM5
-  uh = headerUnload(h);
-#else
-  uh = headerUnload(h, NULL);
-#endif
-  if (!uh)
-    return 0;
-  sigcnt = getu32(uh);
-  sigdsize = getu32(uh + 4);
-  l = sigdsize + sigcnt * 16;
-  if (l > state->rpmheadsize)
-    {
-      state->rpmheadsize = l + 128;
-      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
-    }
-  rpmhead = state->rpmhead;
-  memcpy(rpmhead->data, uh + 8, l - 8);
-  free((void *)uh);
-  rpmhead->forcebinary = 0;
-  rpmhead->cnt = sigcnt;
-  rpmhead->dcnt = sigdsize;
-  rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
-  return rpmhead;
-}
-
-#endif
-
diff --git a/libsolv-0.6.15/ext/repo_rpmdb.h b/libsolv-0.6.15/ext/repo_rpmdb.h
deleted file mode 100644 (file)
index 9e3bd0d..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2007-2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include "queue.h"
-#include "repo.h"
-
-struct headerToken_s;
-
-extern int repo_add_rpmdb(Repo *repo, Repo *ref, int flags);
-extern int repo_add_rpmdb_reffp(Repo *repo, FILE *reffp, int flags);
-extern Id repo_add_rpm(Repo *repo, const char *rpm, int flags);
-
-#define RPMDB_REPORT_PROGRESS  (1 << 8)
-#define RPM_ADD_WITH_PKGID     (1 << 9)
-#define RPM_ADD_NO_FILELIST    (1 << 10)
-#define RPM_ADD_NO_RPMLIBREQS  (1 << 11)
-#define RPM_ADD_WITH_SHA1SUM   (1 << 12)
-#define RPM_ADD_WITH_SHA256SUM (1 << 13)
-#define RPM_ADD_TRIGGERS       (1 << 14)
-#define RPM_ADD_WITH_HDRID     (1 << 15)
-#define RPM_ADD_WITH_LEADSIGID (1 << 16)
-#define RPM_ADD_WITH_CHANGELOG (1 << 17)
-#define RPM_ADD_FILTERED_FILELIST (1 << 18)
-
-#define RPMDB_EMPTY_REFREPO    (1 << 30)       /* internal */
-
-#define RPM_ITERATE_FILELIST_ONLYDIRS  (1 << 0)
-#define RPM_ITERATE_FILELIST_WITHMD5   (1 << 1)
-#define RPM_ITERATE_FILELIST_WITHCOL   (1 << 2)
-#define RPM_ITERATE_FILELIST_NOGHOSTS  (1 << 3)
-
-/* create and free internal state, rootdir is the rootdir of the rpm database */
-extern void *rpm_state_create(Pool *pool, const char *rootdir);
-extern void *rpm_state_free(void *rpmstate);
-
-/* return all matching rpmdbids */
-extern int  rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq);
-
-/* return handles to a rpm header */
-extern void *rpm_byrpmdbid(void *rpmstate, Id rpmdbid);
-extern void *rpm_byfp(void *rpmstate, FILE *fp, const char *name);
-extern void *rpm_byrpmh(void *rpmstate, struct headerToken_s *h);
-
-/* operations on a rpm header handle */
-
-struct filelistinfo {
-  unsigned int dirlen;
-  unsigned int diridx;
-  const char *digest;
-  unsigned int mode;
-  unsigned int color;
-};
-
-extern char *rpm_query(void *rpmhandle, Id what);
-extern unsigned long long rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound);
-extern void rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata);
-extern Id   repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags);
diff --git a/libsolv-0.6.15/ext/repo_rpmmd.c b/libsolv-0.6.15/ext/repo_rpmmd.c
deleted file mode 100644 (file)
index 4272b6f..0000000
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <expat.h>
-
-#include "pool.h"
-#include "repo.h"
-#define DISABLE_SPLIT
-#include "tools_util.h"
-#include "repo_rpmmd.h"
-#include "chksum.h"
-#ifdef ENABLE_COMPLEX_DEPS
-#include "pool_parserpmrichdep.h"
-#endif
-
-enum state {
-  STATE_START,
-
-  STATE_SOLVABLE,
-
-  STATE_NAME,
-  STATE_ARCH,
-  STATE_VERSION,
-
-  /* package rpm-md */
-  STATE_LOCATION,
-  STATE_CHECKSUM,
-  STATE_RPM_GROUP,
-  STATE_RPM_LICENSE,
-
-  /* resobject attributes */
-  STATE_SUMMARY,
-  STATE_DESCRIPTION,
-  STATE_DISTRIBUTION,
-  STATE_PACKAGER,
-  STATE_URL,
-  STATE_INSNOTIFY,
-  STATE_DELNOTIFY,
-  STATE_VENDOR,
-  STATE_SIZE,
-  STATE_TIME,
-  STATE_DOWNLOADSIZE,
-  STATE_INSTALLTIME,
-  STATE_INSTALLONLY,
-
-  /* Novell/SUSE extended attributes */
-  STATE_EULA,
-  STATE_KEYWORD,
-  STATE_DISKUSAGE,
-  STATE_DIRS,
-  STATE_DIR,
-
-  /* patch */
-  STATE_ID,
-  STATE_TIMESTAMP,
-  STATE_AFFECTSPKG,
-  STATE_REBOOTNEEDED,
-
-  /* pattern attributes */
-  STATE_CATEGORY, /* pattern and patches */
-  STATE_ORDER,
-  STATE_INCLUDES,
-  STATE_INCLUDESENTRY,
-  STATE_EXTENDS,
-  STATE_EXTENDSENTRY,
-  STATE_SCRIPT,
-  STATE_ICON,
-  STATE_USERVISIBLE,
-  STATE_DEFAULT,
-  STATE_INSTALL_TIME,
-
-  /* product */
-  STATE_RELNOTESURL,
-  STATE_UPDATEURL,
-  STATE_OPTIONALURL,
-  STATE_FLAG,
-
-  /* rpm-md dependencies inside the
-     format tag */
-  STATE_PROVIDES,
-  STATE_REQUIRES,
-  STATE_OBSOLETES,
-  STATE_CONFLICTS,
-  STATE_RECOMMENDS,
-  STATE_SUPPLEMENTS,
-  STATE_SUGGESTS,
-  STATE_ENHANCES,
-  STATE_FRESHENS,
-  STATE_SOURCERPM,
-  STATE_HEADERRANGE,
-
-  STATE_PROVIDESENTRY,
-  STATE_REQUIRESENTRY,
-  STATE_OBSOLETESENTRY,
-  STATE_CONFLICTSENTRY,
-  STATE_RECOMMENDSENTRY,
-  STATE_SUPPLEMENTSENTRY,
-  STATE_SUGGESTSENTRY,
-  STATE_ENHANCESENTRY,
-  STATE_FRESHENSENTRY,
-
-  STATE_FILE,
-
-  STATE_CHANGELOG,
-
-  /* general */
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-static struct stateswitch stateswitches[] = {
-  /** fake tag used to enclose 2 different xml files in one **/
-  { STATE_START,       "rpmmd",           STATE_START,    0 },
-
-  /** tags for different package data, we just ignore the tag **/
-  { STATE_START,       "metadata",        STATE_START,    0 },
-  { STATE_START,       "otherdata",       STATE_START,    0 },
-  { STATE_START,       "filelists",       STATE_START,    0 },
-  { STATE_START,       "diskusagedata",   STATE_START,    0 },
-  { STATE_START,       "susedata",        STATE_START,    0 },
-
-  { STATE_START,       "product",         STATE_SOLVABLE, 0 },
-  { STATE_START,       "pattern",         STATE_SOLVABLE, 0 },
-  { STATE_START,       "patch",           STATE_SOLVABLE, 0 },
-  { STATE_START,       "package",         STATE_SOLVABLE, 0 },
-
-  { STATE_SOLVABLE,    "name",            STATE_NAME, 1 },
-  { STATE_SOLVABLE,    "arch",            STATE_ARCH, 1 },
-  { STATE_SOLVABLE,    "version",         STATE_VERSION, 0 },
-
-  /* package attributes rpm-md */
-  { STATE_SOLVABLE,    "location",        STATE_LOCATION, 0 },
-  { STATE_SOLVABLE,    "checksum",        STATE_CHECKSUM, 1 },
-
-  /* resobject attributes */
-
-  { STATE_SOLVABLE,    "summary",         STATE_SUMMARY,      1 },
-  { STATE_SOLVABLE,    "description",     STATE_DESCRIPTION,  1 },
-  { STATE_SOLVABLE,    "distribution",    STATE_DISTRIBUTION, 1 },
-  { STATE_SOLVABLE,    "url",             STATE_URL,          1 },
-  { STATE_SOLVABLE,    "packager",        STATE_PACKAGER,     1 },
-  { STATE_SOLVABLE,    "vendor",          STATE_VENDOR,       1 },
-  { STATE_SOLVABLE,    "size",            STATE_SIZE,         0 },
-  { STATE_SOLVABLE,    "archive-size",    STATE_DOWNLOADSIZE, 1 },
-  { STATE_SOLVABLE,    "install-time",    STATE_INSTALLTIME,  1 },
-  { STATE_SOLVABLE,    "install-only",    STATE_INSTALLONLY,  1 },
-  { STATE_SOLVABLE,    "time",            STATE_TIME,         0 },
-
-  /* extended Novell/SUSE attributes (susedata.xml) */
-  { STATE_SOLVABLE,    "eula",            STATE_EULA,         1 },
-  { STATE_SOLVABLE,    "keyword",         STATE_KEYWORD,      1 },
-  { STATE_SOLVABLE,    "diskusage",       STATE_DISKUSAGE,    0 },
-
-  /* pattern attribute */
-  { STATE_SOLVABLE,    "script",          STATE_SCRIPT,        1 },
-  { STATE_SOLVABLE,    "icon",            STATE_ICON,          1 },
-  { STATE_SOLVABLE,    "uservisible",     STATE_USERVISIBLE,   1 },
-  { STATE_SOLVABLE,    "category",        STATE_CATEGORY,      1 },
-  { STATE_SOLVABLE,    "order",           STATE_ORDER,         1 },
-  { STATE_SOLVABLE,    "includes",        STATE_INCLUDES,      0 },
-  { STATE_SOLVABLE,    "extends",         STATE_EXTENDS,       0 },
-  { STATE_SOLVABLE,    "default",         STATE_DEFAULT,       1 },
-  { STATE_SOLVABLE,    "install-time",    STATE_INSTALL_TIME,  1 },
-
-  /* product attributes */
-  /* note the product type is an attribute */
-  { STATE_SOLVABLE,    "release-notes-url", STATE_RELNOTESURL, 1 },
-  { STATE_SOLVABLE,    "update-url",      STATE_UPDATEURL,   1 },
-  { STATE_SOLVABLE,    "optional-url",    STATE_OPTIONALURL, 1 },
-  { STATE_SOLVABLE,    "flag",            STATE_FLAG,        1 },
-
-  { STATE_SOLVABLE,    "rpm:vendor",      STATE_VENDOR,      1 },
-  { STATE_SOLVABLE,    "rpm:group",       STATE_RPM_GROUP,   1 },
-  { STATE_SOLVABLE,    "rpm:license",     STATE_RPM_LICENSE, 1 },
-
-  /* rpm-md dependencies */
-  { STATE_SOLVABLE,    "rpm:provides",    STATE_PROVIDES,     0 },
-  { STATE_SOLVABLE,    "rpm:requires",    STATE_REQUIRES,     0 },
-  { STATE_SOLVABLE,    "rpm:obsoletes",   STATE_OBSOLETES,    0 },
-  { STATE_SOLVABLE,    "rpm:conflicts",   STATE_CONFLICTS,    0 },
-  { STATE_SOLVABLE,    "rpm:recommends",  STATE_RECOMMENDS ,  0 },
-  { STATE_SOLVABLE,    "rpm:supplements", STATE_SUPPLEMENTS,  0 },
-  { STATE_SOLVABLE,    "rpm:suggests",    STATE_SUGGESTS,     0 },
-  { STATE_SOLVABLE,    "rpm:enhances",    STATE_ENHANCES,     0 },
-  { STATE_SOLVABLE,    "rpm:freshens",    STATE_FRESHENS,     0 },
-  { STATE_SOLVABLE,    "rpm:sourcerpm",   STATE_SOURCERPM,    1 },
-  { STATE_SOLVABLE,    "rpm:header-range", STATE_HEADERRANGE, 0 },
-  { STATE_SOLVABLE,    "file",            STATE_FILE, 1 },
-  { STATE_SOLVABLE,    "changelog",       STATE_CHANGELOG, 1 },
-
-   /* extended Novell/SUSE diskusage attributes (susedata.xml) */
-  { STATE_DISKUSAGE,   "dirs",            STATE_DIRS,         0 },
-  { STATE_DIRS,        "dir",             STATE_DIR,          0 },
-
-  { STATE_PROVIDES,    "rpm:entry",       STATE_PROVIDESENTRY, 0 },
-  { STATE_REQUIRES,    "rpm:entry",       STATE_REQUIRESENTRY, 0 },
-  { STATE_OBSOLETES,   "rpm:entry",       STATE_OBSOLETESENTRY, 0 },
-  { STATE_CONFLICTS,   "rpm:entry",       STATE_CONFLICTSENTRY, 0 },
-  { STATE_RECOMMENDS,  "rpm:entry",       STATE_RECOMMENDSENTRY, 0 },
-  { STATE_SUPPLEMENTS, "rpm:entry",       STATE_SUPPLEMENTSENTRY, 0 },
-  { STATE_SUGGESTS,    "rpm:entry",       STATE_SUGGESTSENTRY, 0 },
-  { STATE_ENHANCES,    "rpm:entry",       STATE_ENHANCESENTRY, 0 },
-  { STATE_FRESHENS,    "rpm:entry",       STATE_FRESHENSENTRY, 0 },
-
-  { STATE_INCLUDES,    "item",            STATE_INCLUDESENTRY, 0 },
-  { STATE_EXTENDS,     "item",            STATE_EXTENDSENTRY,  0 },
-
-  { NUMSTATES}
-};
-
-struct parsedata {
-  int ret;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-  char *kind;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Solvable *solvable;
-  Offset freshens;
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  struct joindata jd;
-  /* temporal to store attribute tag language */
-  const char *tmplang;
-  Id chksumtype;
-  Id handle;
-  XML_Parser *parser;
-  Id (*dirs)[3]; /* dirid, size, nfiles */
-  int ndirs;
-  const char *language;                        /* default language */
-  Id langcache[ID_NUM_INTERNAL];       /* cache for the default language */
-
-  Id lastdir;
-  char *lastdirstr;
-  int lastdirstrl;
-
-  Id changelog_handle;
-
-  /** Hash to maps checksums to solv */
-  Stringpool cspool;
-  /** Cache of known checksums to solvable id */
-  Id *cscache;
-  /* the current longest index in the table */
-  int ncscache;
-};
-
-static Id
-langtag(struct parsedata *pd, Id tag, const char *language)
-{
-  if (language)
-    {
-      if (!language[0] || !strcmp(language, "en"))
-       return tag;
-      return pool_id2langid(pd->pool, tag, language, 1);
-    }
-  if (!pd->language)
-    return tag;
-  if (tag >= ID_NUM_INTERNAL)
-    return pool_id2langid(pd->pool, tag, pd->language, 1);
-  if (!pd->langcache[tag])
-    pd->langcache[tag] = pool_id2langid(pd->pool, tag, pd->language, 1);
-  return pd->langcache[tag];
-}
-
-static int
-id3_cmp (const void *v1, const void *v2, void *dp)
-{
-  Id *i1 = (Id*)v1;
-  Id *i2 = (Id*)v2;
-  return i1[0] - i2[0];
-}
-
-static void
-commit_diskusage (struct parsedata *pd, Id handle)
-{
-  int i;
-  Dirpool *dp = &pd->data->dirpool;
-  /* Now sort in dirid order.  This ensures that parents come before
-     their children.  */
-  if (pd->ndirs > 1)
-    solv_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0);
-  /* Substract leaf numbers from all parents to make the numbers
-     non-cumulative.  This must be done post-order (i.e. all leafs
-     adjusted before parents).  We ensure this by starting at the end of
-     the array moving to the start, hence seeing leafs before parents.  */
-  for (i = pd->ndirs; i--;)
-    {
-      Id p = dirpool_parent(dp, pd->dirs[i][0]);
-      int j = i;
-      for (; p; p = dirpool_parent(dp, p))
-        {
-          for (; j--;)
-           if (pd->dirs[j][0] == p)
-             break;
-         if (j >= 0)
-           {
-             if (pd->dirs[j][1] < pd->dirs[i][1])
-               pd->dirs[j][1] = 0;
-             else
-               pd->dirs[j][1] -= pd->dirs[i][1];
-             if (pd->dirs[j][2] < pd->dirs[i][2])
-               pd->dirs[j][2] = 0;
-             else
-               pd->dirs[j][2] -= pd->dirs[i][2];
-           }
-         else
-           /* Haven't found this parent in the list, look further if
-              we maybe find the parents parent.  */
-           j = i;
-       }
-    }
-#if 0
-  char sbuf[1024];
-  char *buf = sbuf;
-  unsigned slen = sizeof (sbuf);
-  for (i = 0; i < pd->ndirs; i++)
-    {
-      dir2str (attr, pd->dirs[i][0], &buf, &slen);
-      fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
-    }
-  if (buf != sbuf)
-    free (buf);
-#endif
-  for (i = 0; i < pd->ndirs; i++)
-    if (pd->dirs[i][1] || pd->dirs[i][2])
-      {
-       repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
-      }
-  pd->ndirs = 0;
-}
-
-
-/*
- * makeevr_atts
- * parse 'epoch', 'ver' and 'rel', return evr Id
- *
- */
-
-static Id
-makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
-{
-  const char *e, *v, *r, *v2;
-  char *c;
-  int l;
-
-  e = v = r = 0;
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, "epoch"))
-       e = atts[1];
-      else if (!strcmp(*atts, "ver"))
-       v = atts[1];
-      else if (!strcmp(*atts, "rel"))
-       r = atts[1];
-    }
-  if (e && (!*e || !strcmp(e, "0")))
-    e = 0;
-  if (v && !e)
-    {
-      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
-        ;
-      if (v2 > v && *v2 == ':')
-       e = "0";
-    }
-  l = 1;
-  if (e)
-    l += strlen(e) + 1;
-  if (v)
-    l += strlen(v);
-  if (r)
-    l += strlen(r) + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content;
-  if (e)
-    {
-      strcpy(c, e);
-      c += strlen(c);
-      *c++ = ':';
-    }
-  if (v)
-    {
-      strcpy(c, v);
-      c += strlen(c);
-    }
-  if (r)
-    {
-      *c++ = '-';
-      strcpy(c, r);
-      c += strlen(c);
-    }
-  *c = 0;
-  if (!*pd->content)
-    return 0;
-#if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
-#endif
-  return pool_str2id(pool, pd->content, 1);
-}
-
-
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-/*
- * dependency relations
- */
-
-static char *flagtab[] = {
-  "GT",
-  "EQ",
-  "GE",
-  "LT",
-  "NE",
-  "LE"
-};
-
-
-/*
- * adddep
- * parse attributes to reldep Id
- *
- */
-
-static unsigned int
-adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq)
-{
-  Id id, marker;
-  const char *n, *f, *k;
-  const char **a;
-
-  n = f = k = 0;
-  marker = isreq ? -SOLVABLE_PREREQMARKER : 0;
-  for (a = atts; *a; a += 2)
-    {
-      if (!strcmp(*a, "name"))
-       n = a[1];
-      else if (!strcmp(*a, "flags"))
-       f = a[1];
-      else if (!strcmp(*a, "kind"))
-       k = a[1];
-      else if (isreq && !strcmp(*a, "pre") && a[1][0] == '1')
-       marker = SOLVABLE_PREREQMARKER;
-    }
-  if (!n)
-    return olddeps;
-  if (k && !strcmp(k, "package"))
-    k = 0;
-  if (k)
-    {
-      int l = strlen(k) + 1 + strlen(n) + 1;
-      if (l > pd->acontent)
-       {
-         pd->content = solv_realloc(pd->content, l + 256);
-         pd->acontent = l + 256;
-       }
-      sprintf(pd->content, "%s:%s", k, n);
-      id = pool_str2id(pool, pd->content, 1);
-    }
-#ifdef ENABLE_COMPLEX_DEPS
-  else if (!f && n[0] == '(')
-    {
-      id = pool_parserpmrichdep(pool, n);
-      if (!id)
-       return olddeps;
-    }
-#endif
-  else
-    id = pool_str2id(pool, (char *)n, 1);
-  if (f)
-    {
-      Id evr = makeevr_atts(pool, pd, atts);
-      int flags;
-      for (flags = 0; flags < 6; flags++)
-       if (!strcmp(f, flagtab[flags]))
-         break;
-      flags = flags < 6 ? flags + 1 : 0;
-      id = pool_rel2id(pool, id, evr, flags, 1);
-    }
-#if 0
-  fprintf(stderr, "new dep %s\n", pool_dep2str(pool, id));
-#endif
-  return repo_addid_dep(pd->repo, olddeps, id, marker);
-}
-
-
-/*
- * set_description_author
- *
- */
-static void
-set_description_author(Repodata *data, Id handle, char *str, struct parsedata *pd)
-{
-  char *aut, *p;
-
-  if (!str || !*str)
-    return;
-  for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
-    if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
-      break;
-  if (aut)
-    {
-      /* oh my, found SUSE special author section */
-      int l = aut - str;
-      str[l] = 0;
-      while (l > 0 && str[l - 1] == '\n')
-       str[--l] = 0;
-      if (l)
-       repodata_set_str(data, handle, langtag(pd, SOLVABLE_DESCRIPTION, pd->tmplang), str);
-      p = aut + 19;
-      aut = str;        /* copy over */
-      while (*p == ' ' || *p == '\n')
-       p++;
-      while (*p)
-       {
-         if (*p == '\n')
-           {
-             *aut++ = *p++;
-             while (*p == ' ')
-               p++;
-             continue;
-           }
-         *aut++ = *p++;
-       }
-      while (aut != str && aut[-1] == '\n')
-       aut--;
-      *aut = 0;
-      if (*str)
-       repodata_set_str(data, handle, SOLVABLE_AUTHORS, str);
-    }
-  else if (*str)
-    repodata_set_str(data, handle, langtag(pd, SOLVABLE_DESCRIPTION, pd->tmplang), str);
-}
-
-
-/*-----------------------------------------------*/
-/* XML callbacks */
-
-/*
- * startElement
- * XML callback
- *
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-  const char *str;
-  Id handle = pd->handle;
-  const char *pkgid;
-
-  /* fprintf(stderr, "into %s, from %d, depth %d, statedepth %d\n", name, pd->state, pd->depth, pd->statedepth); */
-
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  if (pd->state == STATE_START && !strcmp(name, "patterns"))
-    return;
-  if (pd->state == STATE_START && !strcmp(name, "products"))
-    return;
-#if 0
-  if (pd->state == STATE_START && !strcmp(name, "metadata"))
-    return;
-#endif
-  if (pd->state == STATE_SOLVABLE && !strcmp(name, "format"))
-    return;
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
-    if (!strcmp(sw->ename, name))
-      break;
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s\n", name);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  if (!s && pd->state != STATE_SOLVABLE)
-    return;
-
-  switch(pd->state)
-    {
-    case STATE_SOLVABLE:
-      pd->kind = 0;
-      if (name[2] == 't' && name[3] == 't')
-        pd->kind = "pattern";
-      else if (name[1] == 'r')
-        pd->kind = "product";
-      else if (name[2] == 't' && name[3] == 'c')
-        pd->kind = "patch";
-
-      /* to support extension metadata files like others.xml which
-         have the following structure:
-
-         <otherdata xmlns="http://linux.duke.edu/metadata/other"
-                    packages="101">
-           <package pkgid="b78f8664cd90efe42e09a345e272997ef1b53c18"
-                    name="zaptel-kmp-default"
-                    arch="i586"><version epoch="0"
-                    ver="1.2.10_2.6.22_rc4_git6_2" rel="70"/>
-              ...
-
-         we need to check if the pkgid is there and if it matches
-         an already seen package, that means we don't need to create
-         a new solvable but just append the attributes to the existing
-         one.
-      */
-      if ((pkgid = find_attr("pkgid", atts)) != NULL)
-        {
-          /* look at the checksum cache */
-          Id index = stringpool_str2id(&pd->cspool, pkgid, 0);
-          if (!index || index >= pd->ncscache || !pd->cscache[index])
-           {
-              pool_debug(pool, SOLV_WARN, "the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid);
-             pd->solvable = 0;
-             pd->handle = 0;
-             break;
-           }
-         pd->solvable = pool_id2solvable(pool, pd->cscache[index]);
-        }
-      else
-        {
-          /* this is a new package */
-          pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-          pd->freshens = 0;
-        }
-      pd->handle = handle = pd->solvable - pool->solvables;
-      if (pd->kind && pd->kind[1] == 'r')
-       {
-         /* products can have a type */
-         const char *type = find_attr("type", atts);
-         if (type && *type)
-           repodata_set_str(pd->data, handle, PRODUCT_TYPE, type);
-       }
-#if 0
-      fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables);
-#endif
-
-      break;
-    case STATE_VERSION:
-      s->evr = makeevr_atts(pool, pd, atts);
-      break;
-    case STATE_PROVIDES:
-      s->provides = 0;
-      break;
-    case STATE_PROVIDESENTRY:
-      s->provides = adddep(pool, pd, s->provides, atts, 0);
-      break;
-    case STATE_REQUIRES:
-      s->requires = 0;
-      break;
-    case STATE_REQUIRESENTRY:
-      s->requires = adddep(pool, pd, s->requires, atts, 1);
-      break;
-    case STATE_OBSOLETES:
-      s->obsoletes = 0;
-      break;
-    case STATE_OBSOLETESENTRY:
-      s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
-      break;
-    case STATE_CONFLICTS:
-      s->conflicts = 0;
-      break;
-    case STATE_CONFLICTSENTRY:
-      s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
-      break;
-    case STATE_RECOMMENDS:
-      s->recommends = 0;
-      break;
-    case STATE_RECOMMENDSENTRY:
-      s->recommends = adddep(pool, pd, s->recommends, atts, 0);
-      break;
-    case STATE_SUPPLEMENTS:
-      s->supplements= 0;
-      break;
-    case STATE_SUPPLEMENTSENTRY:
-      s->supplements = adddep(pool, pd, s->supplements, atts, 0);
-      break;
-    case STATE_SUGGESTS:
-      s->suggests = 0;
-      break;
-    case STATE_SUGGESTSENTRY:
-      s->suggests = adddep(pool, pd, s->suggests, atts, 0);
-      break;
-    case STATE_ENHANCES:
-      s->enhances = 0;
-      break;
-    case STATE_ENHANCESENTRY:
-      s->enhances = adddep(pool, pd, s->enhances, atts, 0);
-      break;
-    case STATE_FRESHENS:
-      pd->freshens = 0;
-      break;
-    case STATE_FRESHENSENTRY:
-      pd->freshens = adddep(pool, pd, pd->freshens, atts, 0);
-      break;
-    case STATE_EULA:
-    case STATE_SUMMARY:
-    case STATE_CATEGORY:
-    case STATE_DESCRIPTION:
-      pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
-      break;
-    case STATE_USERVISIBLE:
-      repodata_set_void(pd->data, handle, SOLVABLE_ISVISIBLE);
-      break;
-    case STATE_INCLUDESENTRY:
-      str = find_attr("pattern", atts);
-      if (str)
-       repodata_add_poolstr_array(pd->data, handle, SOLVABLE_INCLUDES, join2(&pd->jd, "pattern", ":", str));
-      break;
-    case STATE_EXTENDSENTRY:
-      str = find_attr("pattern", atts);
-      if (str)
-       repodata_add_poolstr_array(pd->data, handle, SOLVABLE_EXTENDS, join2(&pd->jd, "pattern", ":", str));
-      break;
-    case STATE_LOCATION:
-      str = find_attr("href", atts);
-      if (str)
-       {
-         repodata_set_location(pd->data, handle, 0, 0, str);
-         str = find_attr("xml:base", atts);
-         if (str)
-           repodata_set_poolstr(pd->data, handle, SOLVABLE_MEDIABASE, str);
-       }
-      break;
-    case STATE_CHECKSUM:
-      str = find_attr("type", atts);
-      pd->chksumtype = str && *str ? solv_chksum_str2type(str) : 0;
-      if (!pd->chksumtype)
-       pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), str ? str : "NULL");
-      break;
-    case STATE_TIME:
-      {
-        unsigned int t;
-        str = find_attr("build", atts);
-        if (str && (t = atoi(str)) != 0)
-          repodata_set_num(pd->data, handle, SOLVABLE_BUILDTIME, t);
-       break;
-      }
-    case STATE_SIZE:
-      if ((str = find_attr("installed", atts)) != 0)
-       repodata_set_num(pd->data, handle, SOLVABLE_INSTALLSIZE, strtoull(str, 0, 10));
-      if ((str = find_attr("package", atts)) != 0)
-       repodata_set_num(pd->data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(str, 0, 10));
-      break;
-    case STATE_HEADERRANGE:
-      {
-        unsigned int end;
-        str = find_attr("end", atts);
-       if (str && (end = atoi(str)) != 0)
-         repodata_set_num(pd->data, handle, SOLVABLE_HEADEREND, end);
-       break;
-      }
-      /*
-        <diskusage>
-          <dirs>
-            <dir name="/" size="56" count="11"/>
-            <dir name="usr/" size="56" count="11"/>
-            <dir name="usr/bin/" size="38" count="10"/>
-            <dir name="usr/share/" size="18" count="1"/>
-            <dir name="usr/share/doc/" size="18" count="1"/>
-          </dirs>
-        </diskusage>
-      */
-    case STATE_DISKUSAGE:
-      {
-        /* Really, do nothing, wait for <dir> tag */
-        break;
-      }
-    case STATE_DIR:
-      {
-        long filesz = 0, filenum = 0;
-        Id dirid;
-        if ((str = find_attr("name", atts)) != 0)
-          dirid = repodata_str2dir(pd->data, str, 1);
-        else
-          {
-           pd->ret = pool_error(pool, -1, "<dir .../> tag without 'name' attribute");
-            break;
-          }
-        if (!dirid)
-          dirid = repodata_str2dir(pd->data, "/", 1);
-        if ((str = find_attr("size", atts)) != 0)
-          filesz = strtol(str, 0, 0);
-        if ((str = find_attr("count", atts)) != 0)
-          filenum = strtol(str, 0, 0);
-        pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
-        pd->dirs[pd->ndirs][0] = dirid;
-        pd->dirs[pd->ndirs][1] = filesz;
-        pd->dirs[pd->ndirs][2] = filenum;
-        pd->ndirs++;
-        break;
-      }
-    case STATE_CHANGELOG:
-      pd->changelog_handle = repodata_new_handle(pd->data);
-      if ((str = find_attr("date", atts)) != 0)
-       repodata_set_num(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TIME, strtoull(str, 0, 10));
-      if ((str = find_attr("author", atts)) != 0)
-       repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_AUTHOR, str);
-      break;
-    default:
-      break;
-    }
-}
-
-
-/*
- * endElement
- * XML callback
- *
- */
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  Repo *repo = pd->repo;
-  Id handle = pd->handle;
-  Id id;
-  char *p;
-
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-      /* printf("back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
-      return;
-    }
-
-  /* ignore patterns & metadata */
-  if (pd->state == STATE_START && !strcmp(name, "patterns"))
-    return;
-  if (pd->state == STATE_START && !strcmp(name, "products"))
-    return;
-#if 0
-  if (pd->state == STATE_START && !strcmp(name, "metadata"))
-    return;
-#endif
-  if (pd->state == STATE_SOLVABLE && !strcmp(name, "format"))
-    return;
-
-  pd->depth--;
-  pd->statedepth--;
-
-
-  if (!s)
-    {
-      pd->state = pd->sbtab[pd->state];
-      pd->docontent = 0;
-      return;
-    }
-
-  switch (pd->state)
-    {
-    case STATE_SOLVABLE:
-      if (pd->kind && !s->name) /* add namespace in case of NULL name */
-        s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", 0), 1);
-      if (!s->arch)
-        s->arch = ARCH_NOARCH;
-      if (!s->evr)
-        s->evr = ID_EMPTY;     /* some patterns have this */
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-        s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-      s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, pd->freshens);
-      s->conflicts = repo_fix_conflicts(repo, s->conflicts);
-      pd->freshens = 0;
-      pd->kind = 0;
-      pd->solvable = s = 0;
-      break;
-    case STATE_NAME:
-      if (pd->kind)
-        s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", pd->content), 1);
-      else
-        s->name = pool_str2id(pool, pd->content, 1);
-      break;
-    case STATE_ARCH:
-      s->arch = pool_str2id(pool, pd->content, 1);
-      break;
-    case STATE_VENDOR:
-      s->vendor = pool_str2id(pool, pd->content, 1);
-      break;
-    case STATE_RPM_GROUP:
-      repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, pd->content);
-      break;
-    case STATE_RPM_LICENSE:
-      repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, pd->content);
-      break;
-    case STATE_CHECKSUM:
-      {
-        Id index;
-       
-       if (!pd->chksumtype)
-         break;
-        if (strlen(pd->content) != 2 * solv_chksum_len(pd->chksumtype))
-          {
-           pd->ret = pool_error(pool, -1, "line %d: invalid checksum length for %s", (unsigned int)XML_GetCurrentLineNumber(*pd->parser), solv_chksum_type2str(pd->chksumtype));
-           break;
-          }
-        repodata_set_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, pd->content);
-        /* we save the checksum to solvable id relationship for extended
-           metadata */
-        index = stringpool_str2id(&pd->cspool, pd->content, 1 /* create it */);
-        if (index >= pd->ncscache)
-          {
-            pd->cscache = solv_zextend(pd->cscache, pd->ncscache, index + 1 - pd->ncscache, sizeof(Id), 255);
-            pd->ncscache = index + 1;
-          }
-        /* add the checksum to the cache */
-        pd->cscache[index] = s - pool->solvables;
-        break;
-      }
-    case STATE_FILE:
-#if 0
-      id = pool_str2id(pool, pd->content, 1);
-      s->provides = repo_addid_dep(repo, s->provides, id, SOLVABLE_FILEMARKER);
-#endif
-      if ((p = strrchr(pd->content, '/')) != 0)
-       {
-         *p++ = 0;
-         if (pd->lastdir && !strcmp(pd->lastdirstr, pd->content))
-           {
-             id = pd->lastdir;
-           }
-         else
-           {
-             int l;
-             id = repodata_str2dir(pd->data, pd->content, 1);
-             l = strlen(pd->content) + 1;
-             if (l > pd->lastdirstrl)
-               {
-                 pd->lastdirstrl = l + 128;
-                 pd->lastdirstr = solv_realloc(pd->lastdirstr, pd->lastdirstrl);
-               }
-             strcpy(pd->lastdirstr, pd->content);
-             pd->lastdir = id;
-           }
-       }
-      else
-       {
-         p = pd->content;
-         id = 0;
-       }
-      if (!id)
-       id = repodata_str2dir(pd->data, "/", 1);
-      repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, id, p);
-      break;
-    case STATE_SUMMARY:
-      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content);
-      break;
-    case STATE_DESCRIPTION:
-      set_description_author(pd->data, handle, pd->content, pd);
-      break;
-    case STATE_CATEGORY:
-      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), pd->content);
-      break;
-    case STATE_DISTRIBUTION:
-        repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, pd->content);
-        break;
-    case STATE_URL:
-      if (pd->content[0])
-       repodata_set_str(pd->data, handle, SOLVABLE_URL, pd->content);
-      break;
-    case STATE_PACKAGER:
-      if (pd->content[0])
-       repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, pd->content);
-      break;
-    case STATE_SOURCERPM:
-      if (pd->content[0])
-       repodata_set_sourcepkg(pd->data, handle, pd->content);
-      break;
-    case STATE_RELNOTESURL:
-      if (pd->content[0])
-        {
-          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
-          repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "releasenotes", 1));
-        }
-      break;
-    case STATE_UPDATEURL:
-      if (pd->content[0])
-        {
-          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
-          repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "update", 1));
-        }
-      break;
-    case STATE_OPTIONALURL:
-      if (pd->content[0])
-        {
-          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, pd->content);
-          repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "optional", 1));
-        }
-      break;
-    case STATE_FLAG:
-      if (pd->content[0])
-        repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, pd->content);
-      break;
-    case STATE_EULA:
-      if (pd->content[0])
-       repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), pd->content);
-      break;
-    case STATE_KEYWORD:
-      if (pd->content[0])
-        repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, pd->content);
-      break;
-    case STATE_DISKUSAGE:
-      if (pd->ndirs)
-        commit_diskusage(pd, handle);
-      break;
-    case STATE_ORDER:
-      if (pd->content[0])
-        repodata_set_str(pd->data, handle, SOLVABLE_ORDER, pd->content);
-      break;
-    case STATE_CHANGELOG:
-      repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, pd->content);
-      repodata_add_flexarray(pd->data, handle, SOLVABLE_CHANGELOG, pd->changelog_handle);
-      pd->changelog_handle = 0;
-      break;
-    default:
-      break;
-    }
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-  /* fprintf(stderr, "back from known %d %d %d\n", pd->state, pd->depth, pd->statedepth); */
-}
-
-
-/*
- * characterData
- * XML callback
- *
- */
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = solv_realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-
-/*-----------------------------------------------*/
-/* 'main' */
-
-#define BUFF_SIZE 8192
-
-/*
- * repo_add_rpmmd
- * parse rpm-md metadata (primary, others)
- *
- */
-
-int
-repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
-{
-  Pool *pool = repo->pool;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  Repodata *data;
-  unsigned int now;
-  XML_Parser parser;
-
-  now = solv_timems(0);
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-  pd.pool = pool;
-  pd.repo = repo;
-  pd.data = data;
-
-  pd.content = solv_malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-  pd.kind = 0;
-  pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0;
-
-  /* initialize the string pool where we will store
-     the package checksums we know about, to get an Id
-     we can use in a cache */
-  stringpool_init_empty(&pd.cspool);
-  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
-    {
-      /* setup join data */
-      Dataiterator di;
-      dataiterator_init(&di, pool, repo, 0, SOLVABLE_CHECKSUM, 0, 0);
-      while (dataiterator_step(&di))
-       {
-         const char *str;
-         int index;
-
-         if (!solv_chksum_len(di.key->type))
-           continue;
-         str = repodata_chk2str(di.data, di.key->type, (const unsigned char *)di.kv.str);
-          index = stringpool_str2id(&pd.cspool, str, 1);
-         if (index >= pd.ncscache)
-           {
-             pd.cscache = solv_zextend(pd.cscache, pd.ncscache, index + 1 - pd.ncscache, sizeof(Id), 255);
-             pd.ncscache = index + 1;
-           }
-          pd.cscache[index] = di.solvid;
-       }
-      dataiterator_free(&di);
-    }
-
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  pd.parser = &parser;
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  solv_free(pd.content);
-  solv_free(pd.lastdirstr);
-  join_freemem(&pd.jd);
-  stringpool_free(&pd.cspool);
-  solv_free(pd.cscache);
-  repodata_free_dircache(data);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmmd took %d ms\n", solv_timems(now));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
-  return pd.ret;
-}
diff --git a/libsolv-0.6.15/ext/repo_rpmmd.h b/libsolv-0.6.15/ext/repo_rpmmd.h
deleted file mode 100644 (file)
index 1e88df6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags);
diff --git a/libsolv-0.6.15/ext/repo_susetags.c b/libsolv-0.6.15/ext/repo_susetags.c
deleted file mode 100644 (file)
index a96ba97..0000000
+++ /dev/null
@@ -1,1183 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "hash.h"
-#include "chksum.h"
-#include "tools_util.h"
-#include "repo_susetags.h"
-#ifdef ENABLE_COMPLEX_DEPS
-#include "pool_parserpmrichdep.h"
-#endif
-
-struct datashare {
-  Id name;
-  Id evr;
-  Id arch;
-};
-
-struct parsedata {
-  int ret;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-  char *kind;
-  int flags;
-  int last_found_source;
-  struct datashare *share_with;
-  int nshare;
-  Id (*dirs)[3];                       /* dirid, size, nfiles */
-  int ndirs;
-  struct joindata jd;
-  char *language;                      /* the default language */
-  Id langcache[ID_NUM_INTERNAL];       /* cache for the default language */
-  int lineno;
-  char *filelist;
-  int afilelist;                       /* allocated */
-  int nfilelist;                       /* used */
-};
-
-static char *flagtab[] = {
-  ">",
-  "=",
-  ">=",
-  "<",
-  "!=",
-  "<="
-};
-
-
-static Id
-langtag(struct parsedata *pd, Id tag, const char *language)
-{
-  if (language && *language)
-    return pool_id2langid(pd->repo->pool, tag, language, 1);
-  if (!pd->language)
-    return tag;
-  if (tag >= ID_NUM_INTERNAL)
-    return pool_id2langid(pd->repo->pool, tag, pd->language, 1);
-  if (!pd->langcache[tag])
-    pd->langcache[tag] = pool_id2langid(pd->repo->pool, tag, pd->language, 1);
-  return pd->langcache[tag];
-}
-
-/*
- * adddep
- * create and add dependency
- */
-
-static unsigned int
-adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker, char *kind)
-{
-  int i, flags;
-  Id id, evrid;
-  char *sp[4];
-
-  if (line[6] == '/')
-    {
-      /* A file dependency. Do not try to parse it */
-      id = pool_str2id(pool, line + 6, 1);
-    }
-#ifdef ENABLE_COMPLEX_DEPS
-  else if (line[6] == '(')
-    {
-      id = pool_parserpmrichdep(pool, line + 6);
-      if (!id)
-       {
-         pd->ret = pool_error(pool, -1, "susetags: line %d: bad dependency: '%s'\n", pd->lineno, line);
-          return olddeps;
-       }
-    }
-#endif
-  else
-    {
-      i = split(line + 6, sp, 4); /* name, <op>, evr, ? */
-      if (i != 1 && i != 3) /* expect either 'name' or 'name' <op> 'evr' */
-        {
-         pd->ret = pool_error(pool, -1, "susetags: line %d: bad dependency: '%s'\n", pd->lineno, line);
-          return olddeps;
-        }
-      if (kind)
-        id = pool_str2id(pool, join2(&pd->jd, kind, ":", sp[0]), 1);
-      else
-        id = pool_str2id(pool, sp[0], 1);
-      if (i == 3)
-        {
-          evrid = makeevr(pool, sp[2]);
-          for (flags = 0; flags < 6; flags++)
-            if (!strcmp(sp[1], flagtab[flags]))
-              break;
-          if (flags == 6)
-            {
-             if (!strcmp(sp[1], "<>"))
-               flags = 4;
-             else
-               {
-                 pd->ret = pool_error(pool, -1, "susetags: line %d: unknown relation: '%s'\n", pd->lineno, sp[1]);
-                 return olddeps;
-               }
-            }
-          id = pool_rel2id(pool, id, evrid, flags + 1, 1);
-        }
-    }
-  return repo_addid_dep(pd->repo, olddeps, id, marker);
-}
-
-
-/*
- * add_source
- *
- */
-
-static void
-add_source(struct parsedata *pd, char *line, Solvable *s, Id handle)
-{
-  Pool *pool = s->repo->pool;
-  char *sp[5];
-  Id name;
-  Id arch;
-  const char *evr, *sevr;
-
-  if (split(line, sp, 5) != 4)
-    {
-      pd->ret = pool_error(pool, -1, "susetags: line %d: bad source line '%s'\n", pd->lineno, line);
-      return;
-    }
-
-  name = pool_str2id(pool, sp[0], 1);
-  arch = pool_str2id(pool, sp[3], 1);  /* do this before id2str */
-  evr = join2(&pd->jd, sp[1], "-", sp[2]);
-  sevr = pool_id2str(pool, s->evr);
-  if (sevr)
-    {
-      /* strip epoch */
-      const char *p;
-      for (p = sevr; *p >= '0' && *p <= '9'; p++)
-       ;
-      if (p != sevr && *p == ':' && p[1])
-       sevr = p;
-    }
-  if (name == s->name)
-    repodata_set_void(pd->data, handle, SOLVABLE_SOURCENAME);
-  else
-    repodata_set_id(pd->data, handle, SOLVABLE_SOURCENAME, name);
-  if (sevr && !strcmp(sevr, evr))
-    repodata_set_void(pd->data, handle, SOLVABLE_SOURCEEVR);
-  else
-    repodata_set_id(pd->data, handle, SOLVABLE_SOURCEEVR, pool_str2id(pool, evr, 1));
-  repodata_set_constantid(pd->data, handle, SOLVABLE_SOURCEARCH, arch);
-}
-
-/*
- * add_dirline
- * add a line with directory information
- *
- */
-
-static void
-add_dirline(struct parsedata *pd, char *line)
-{
-  char *sp[6];
-  long filesz;
-  long filenum;
-  Id dirid;
-  if (split(line, sp, 6) != 5)
-    return;
-  pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
-  filesz = strtol(sp[1], 0, 0);
-  filesz += strtol(sp[2], 0, 0);
-  filenum = strtol(sp[3], 0, 0);
-  filenum += strtol(sp[4], 0, 0);
-  /* hack: we know that there's room for a / */
-  if (*sp[0] != '/')
-    *--sp[0] = '/';
-  dirid = repodata_str2dir(pd->data, sp[0], 1);
-#if 0
-fprintf(stderr, "%s -> %d\n", sp[0], dirid);
-#endif
-  pd->dirs[pd->ndirs][0] = dirid;
-  pd->dirs[pd->ndirs][1] = filesz;
-  pd->dirs[pd->ndirs][2] = filenum;
-  pd->ndirs++;
-}
-
-static void
-set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *line)
-{
-  char *sp[3];
-  Id type;
-  if (split(line, sp, 3) != 2)
-    {
-      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: bad checksum line '%s'\n", pd->lineno, line);
-      return;
-    }
-  type = solv_chksum_str2type(sp[0]);
-  if (!type)
-    {
-      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: unknown checksum type: '%s'\n", pd->lineno, sp[0]);
-      return;
-    }
-  if (strlen(sp[1]) != 2 * solv_chksum_len(type))
-    {
-      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: bad checksum length for type %s: '%s'\n", pd->lineno, sp[0], sp[1]);
-      return;
-    }
-  repodata_set_checksum(data, handle, keyname, type, sp[1]);
-}
-
-
-/*
- * id3_cmp
- * compare
- *
- */
-
-static int
-id3_cmp(const void *v1, const void *v2, void *dp)
-{
-  Id *i1 = (Id*)v1;
-  Id *i2 = (Id*)v2;
-  return i1[0] - i2[0];
-}
-
-
-/*
- * commit_diskusage
- *
- */
-
-static void
-commit_diskusage(struct parsedata *pd, Id handle)
-{
-  int i;
-  Dirpool *dp = &pd->data->dirpool;
-  /* Now sort in dirid order.  This ensures that parents come before
-     their children.  */
-  if (pd->ndirs > 1)
-    solv_sort(pd->dirs, pd->ndirs, sizeof(pd->dirs[0]), id3_cmp, 0);
-  /* Substract leaf numbers from all parents to make the numbers
-     non-cumulative.  This must be done post-order (i.e. all leafs
-     adjusted before parents).  We ensure this by starting at the end of
-     the array moving to the start, hence seeing leafs before parents.  */
-  for (i = pd->ndirs; i--;)
-    {
-      Id p = dirpool_parent(dp, pd->dirs[i][0]);
-      int j = i;
-      for (; p; p = dirpool_parent(dp, p))
-        {
-          for (; j--;)
-           if (pd->dirs[j][0] == p)
-             break;
-         if (j >= 0)
-           {
-             if (pd->dirs[j][1] < pd->dirs[i][1])
-               pd->dirs[j][1] = 0;
-             else
-               pd->dirs[j][1] -= pd->dirs[i][1];
-             if (pd->dirs[j][2] < pd->dirs[i][2])
-               pd->dirs[j][2] = 0;
-             else
-               pd->dirs[j][2] -= pd->dirs[i][2];
-           }
-         else
-           /* Haven't found this parent in the list, look further if
-              we maybe find the parents parent.  */
-           j = i;
-       }
-    }
-#if 0
-  char sbuf[1024];
-  char *buf = sbuf;
-  unsigned slen = sizeof(sbuf);
-  for (i = 0; i < pd->ndirs; i++)
-    {
-      dir2str(attr, pd->dirs[i][0], &buf, &slen);
-      fprintf(stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
-    }
-  if (buf != sbuf)
-    free (buf);
-#endif
-  for (i = 0; i < pd->ndirs; i++)
-    if (pd->dirs[i][1] || pd->dirs[i][2])
-      {
-       repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
-      }
-  pd->ndirs = 0;
-}
-
-
-/* Unfortunately "a"[0] is no constant expression in the C languages,
-   so we need to pass the four characters individually :-/  */
-#define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \
- | ((unsigned char)b << 16) \
- | ((unsigned char)c << 8) \
- | ((unsigned char)d))
-
-/*
- * tag_from_string
- *
- */
-
-static inline unsigned
-tag_from_string(char *cs)
-{
-  unsigned char *s = (unsigned char *)cs;
-  return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]);
-}
-
-
-/*
- * repo_add_susetags
- * Parse susetags file passed in fp, fill solvables into repo
- *
- * susetags is key,value based
- *  for short values
- *    =key: value
- *  is used
- *  for long (multi-line) values,
- *    +key:
- *    value
- *    value
- *    -key:
- *  is used
- *
- * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata
- * and http://en.opensuse.org/Standards/YaST2_Repository_Metadata/packages
- * and http://en.opensuse.org/Standards/YaST2_Repository_Metadata/pattern
- *
- * Assumptions:
- *   All keys have 3 characters and end in ':'
- */
-
-static void
-finish_solvable(struct parsedata *pd, Solvable *s, Offset freshens)
-{
-  Pool *pool = pd->repo->pool;
-  Id handle = s - pool->solvables;
-
-  if (pd->nfilelist)
-    {
-      int l;
-      Id did;
-      for (l = 0; l < pd->nfilelist; l += strlen(pd->filelist + l) + 1)
-        {
-         char *p = strrchr(pd->filelist + l, '/');
-         if (!p)
-           continue;
-         *p++ = 0;
-         did = repodata_str2dir(pd->data, pd->filelist + l, 1);
-         p[-1] = '/';
-         if (!did)
-           did = repodata_str2dir(pd->data, "/", 1);
-         repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, did, p);
-       }
-      pd->nfilelist = 0;
-    }
-  /* A self provide, except for source packages.  This is harmless
-     to do twice (in case we see the same package twice).  */
-  if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-    s->provides = repo_addid_dep(pd->repo, s->provides,
-               pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-  /* XXX This uses repo_addid_dep internally, so should also be
-     harmless to do twice.  */
-  s->supplements = repo_fix_supplements(pd->repo, s->provides, s->supplements, freshens);
-  s->conflicts = repo_fix_conflicts(pd->repo, s->conflicts);
-  if (pd->ndirs)
-    commit_diskusage(pd, handle);
-}
-
-static Hashtable
-joinhash_init(Repo *repo, Hashval *hmp)
-{
-  Hashval hm = mkmask(repo->nsolvables);
-  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
-  Hashval h, hh;
-  Solvable *s;
-  int i;
-
-  FOR_REPO_SOLVABLES(repo, i, s)
-    {
-      hh = HASHCHAIN_START;
-      h = s->name & hm;
-      while (ht[h])
-        h = HASHCHAIN_NEXT(h, hh, hm);
-      ht[h] = i;
-    }
-  *hmp = hm;
-  return ht;
-}
-
-static Solvable *
-joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, Id name, Id evr, Id arch, Id start)
-{
-  Hashval h, hh;
-
-  if (!name || !arch || !evr)
-    return 0;
-  hh = HASHCHAIN_START;
-  h = name & hm;
-  while (ht[h])
-    {
-      Solvable *s = repo->pool->solvables + ht[h];
-      if (ht[h] >= start && s->name == name && s->evr == evr && s->arch == arch)
-       return s;
-      h = HASHCHAIN_NEXT(h, hh, hm);
-    }
-  return 0;
-}
-
-static Id
-lookup_shared_id(Repodata *data, Id p, Id keyname, Id voidid, int uninternalized)
-{
-  Id r;
-  r = repodata_lookup_type(data, p, keyname);
-  if (r)
-    {
-      if (r == REPOKEY_TYPE_VOID)
-       return voidid;
-      r = repodata_lookup_id(data, p, keyname);
-      if (r)
-       return r;
-    }
-  if (uninternalized)
-    return repodata_lookup_id_uninternalized(data, p, keyname, voidid);
-  return 0;
-}
-
-static inline Id
-toevr(Pool *pool, struct parsedata *pd, const char *version, const char *release)
-{
-  return makeevr(pool, !release || (release[0] == '-' && !release[1]) ?
-       version : join2(&pd->jd, version, "-", release));
-}
-
-
-/*
- * parse susetags
- *
- * fp: file to read from
- * defvendor: default vendor (0 if none)
- * language: current language (0 if none)
- * flags: flags
- */
-
-int
-repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int flags)
-{
-  Pool *pool = repo->pool;
-  char *line, *linep;
-  int aline;
-  Solvable *s;
-  Offset freshens;
-  int intag = 0;
-  int cummulate = 0;
-  int indesc = 0;
-  int indelta = 0;
-  int last_found_pack = 0;
-  Id first_new_pkg = 0;
-  char *sp[5];
-  struct parsedata pd;
-  Repodata *data = 0;
-  Id handle = 0;
-  Hashtable joinhash = 0;
-  Hashval joinhashm = 0;
-  int createdpkgs = 0;
-
-  if ((flags & (SUSETAGS_EXTEND|REPO_EXTEND_SOLVABLES)) != 0 && repo->nrepodata)
-    {
-      joinhash = joinhash_init(repo, &joinhashm);
-      indesc = 1;
-    }
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  line = solv_malloc(1024);
-  aline = 1024;
-
-  pd.pool = pool;
-  pd.repo = repo;
-  pd.data = data;
-  pd.flags = flags;
-  pd.language = language && *language ? solv_strdup(language) : 0;
-
-  linep = line;
-  s = 0;
-  freshens = 0;
-
-  /* if this is a join setup the recorded share data */
-  if (joinhash)
-    {
-      Repodata *sdata;
-      int i;
-
-      FOR_REPODATAS(repo, i, sdata)
-       {
-         int p;
-         if (!repodata_has_keyname(sdata, SUSETAGS_SHARE_NAME))
-           continue;
-         for (p = sdata->start; p < sdata->end; p++)
-           {
-             Id name, evr, arch;
-             name = lookup_shared_id(sdata, p, SUSETAGS_SHARE_NAME, pool->solvables[p].name, sdata == data);
-             if (!name)
-               continue;
-             evr = lookup_shared_id(sdata, p, SUSETAGS_SHARE_EVR, pool->solvables[p].evr, sdata == data);
-             if (!evr)
-               continue;
-             arch = lookup_shared_id(sdata, p, SUSETAGS_SHARE_ARCH, pool->solvables[p].arch, sdata == data);
-             if (!arch)
-               continue;
-             if (p - repo->start >= pd.nshare)
-               {
-                 pd.share_with = solv_realloc2(pd.share_with, p - repo->start + 256, sizeof(*pd.share_with));
-                 memset(pd.share_with + pd.nshare, 0, (p - repo->start + 256 - pd.nshare) * sizeof(*pd.share_with));
-                 pd.nshare = p - repo->start + 256;
-               }
-             pd.share_with[p - repo->start].name = name;
-             pd.share_with[p - repo->start].evr = evr;
-             pd.share_with[p - repo->start].arch = arch;
-           }
-       }
-    }
-
-  /*
-   * read complete file
-   *
-   * collect values in 'struct parsedata pd'
-   * then build .solv (and .attr) file
-   */
-
-  for (;;)
-    {
-      unsigned tag;
-      char *olinep; /* old line pointer */
-      char line_lang[6];
-      int keylen = 3;
-
-      if (pd.ret)
-       break;
-      if (linep - line + 16 > aline)              /* (re-)alloc buffer */
-       {
-         aline = linep - line;
-         line = solv_realloc(line, aline + 512);
-         linep = line + aline;
-         aline += 512;
-       }
-      if (!fgets(linep, aline - (linep - line), fp)) /* read line */
-       break;
-      olinep = linep;
-      linep += strlen(linep);
-      if (linep == line || linep[-1] != '\n')
-        continue;
-      pd.lineno++;
-      *--linep = 0;
-      if (linep == olinep)
-       continue;
-
-      if (intag)
-       {
-         /* check for multi-line value tags (+Key:/-Key:) */
-
-         int is_end = (linep[-intag - keylen + 1] == '-')
-                     && (linep[-1] == ':')
-                     && (linep == line + 1 + intag + 1 + 1 + 1 + intag + 1 || linep[-intag - keylen] == '\n');
-         if (is_end
-             && strncmp(linep - 1 - intag, line + 1, intag))
-           {
-             pool_debug(pool, SOLV_ERROR, "susetags: Nonmatching multi-line tags: %d: '%s' '%s' %d\n", pd.lineno, linep - 1 - intag, line + 1, intag);
-           }
-         if (cummulate && !is_end)
-           {
-             *linep++ = '\n';
-             continue;
-           }
-         if (cummulate && is_end)
-           {
-             linep[-intag - keylen + 1] = 0;
-             if (linep[-intag - keylen] == '\n')
-               linep[-intag - keylen] = 0;
-             linep = line;
-             intag = 0;
-           }
-         if (!cummulate && is_end)
-           {
-             intag = 0;
-             linep = line;
-             continue;
-           }
-         if (!cummulate && !is_end)
-           linep = line + intag + keylen;
-       }
-      else
-       linep = line;
-
-      if (!intag && line[0] == '+' && line[1] && line[1] != ':') /* start of +Key:/-Key: tag */
-       {
-         char *tagend = strchr(line, ':');
-         if (!tagend)
-           {
-             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
-             break;
-           }
-         intag = tagend - (line + 1);
-         cummulate = 0;
-         switch (tag_from_string(line))       /* check if accumulation is needed */
-           {
-             case CTAG('+', 'D', 'e', 's'):
-             case CTAG('+', 'E', 'u', 'l'):
-             case CTAG('+', 'I', 'n', 's'):
-             case CTAG('+', 'D', 'e', 'l'):
-             case CTAG('+', 'A', 'u', 't'):
-               if (line[4] == ':' || line[4] == '.')
-                 cummulate = 1;
-               break;
-             default:
-               break;
-           }
-         line[0] = '=';                       /* handle lines between +Key:/-Key: as =Key: */
-         line[intag + keylen - 1] = ' ';
-         linep = line + intag + keylen;
-         continue;
-       }
-      if (*line == '#' || !*line)
-       continue;
-      if (! (line[0] && line[1] && line[2] && line[3] && (line[4] == ':' || line[4] == '.')))
-        continue;
-      line_lang[0] = 0;
-      if (line[4] == '.')
-        {
-          char *endlang;
-          endlang = strchr(line + 5, ':');
-          if (endlang)
-            {
-             int langsize = endlang - (line + 5);
-              keylen = endlang - line - 1;
-             if (langsize > 5)
-               langsize = 5;
-              strncpy(line_lang, line + 5, langsize);
-              line_lang[langsize] = 0;
-            }
-        }
-      tag = tag_from_string(line);
-
-      if (indelta)
-       {
-         /* Example:
-           =Dlt: subversion 1.6.16 1.3.1 i586
-           =Dsq: subversion 1.6.15 4.2 i586 d57b3fc86e7a2f73796e8e35b96fa86212c910
-           =Cks: SHA1 14a8410cf741856a5d70d89dab62984dba6a1ca7
-           =Loc: 1 subversion-1.6.15_1.6.16-4.2_1.3.1.i586.delta.rpm
-           =Siz: 81558
-          */
-         switch (tag)
-           {
-           case CTAG('=', 'D', 's', 'q'):
-             {
-               Id evr;
-               if (split(line + 5, sp, 5) != 5)
-                 continue;
-               repodata_set_id(data, handle, DELTA_SEQ_NAME, pool_str2id(pool, sp[0], 1));
-               evr = toevr(pool, &pd, sp[1], sp[2]);
-               repodata_set_id(data, handle, DELTA_SEQ_EVR, evr);
-               /* repodata_set_id(data, handle, DELTA_SEQ_ARCH, pool_str2id(pool, sp[3], 1)); */
-               repodata_set_str(data, handle, DELTA_SEQ_NUM, sp[4]);
-               repodata_set_id(data, handle, DELTA_BASE_EVR, evr);
-               continue;
-             }
-           case CTAG('=', 'C', 'k', 's'):
-             set_checksum(&pd, data, handle, DELTA_CHECKSUM, line + 6);
-             continue;
-           case CTAG('=', 'L', 'o', 'c'):
-             {
-               int i = split(line + 6, sp, 3);
-               if (i != 2 && i != 3)
-                 {
-                   pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line);
-                   continue;
-                 }
-               repodata_set_deltalocation(data, handle, atoi(sp[0]), i == 3 ? sp[2] : 0, sp[1]);
-               continue;
-             }
-           case CTAG('=', 'S', 'i', 'z'):
-             if (split(line + 6, sp, 3) == 2)
-               repodata_set_num(data, handle, DELTA_DOWNLOADSIZE, strtoull(sp[0], 0, 10));
-             continue;
-           case CTAG('=', 'P', 'k', 'g'):
-           case CTAG('=', 'P', 'a', 't'):
-           case CTAG('=', 'D', 'l', 't'):
-             handle = 0;
-             indelta = 0;
-             break;
-           default:
-             pool_debug(pool, SOLV_ERROR, "susetags: unknown line: %d: %s\n", pd.lineno, line);
-             continue;
-           }
-       }
-
-      /*
-       * start of (next) package or pattern or delta
-       *
-       * =Pkg: <name> <version> <release> <architecture>
-       * (=Pat: ...)
-       */
-      if (tag == CTAG('=', 'D', 'l', 't'))
-       {
-         if (s)
-           finish_solvable(&pd, s, freshens);
-         s = 0;
-         pd.kind = 0;
-          if (split(line + 5, sp, 5) != 4)
-           {
-             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
-             break;
-           }
-         handle = repodata_new_handle(data);
-         repodata_set_id(data, handle, DELTA_PACKAGE_NAME, pool_str2id(pool, sp[0], 1));
-         repodata_set_id(data, handle, DELTA_PACKAGE_EVR, toevr(pool, &pd, sp[1], sp[2]));
-         repodata_set_id(data, handle, DELTA_PACKAGE_ARCH, pool_str2id(pool, sp[3], 1));
-         repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DELTAINFO, handle);
-         indelta = 1;
-         continue;
-       }
-      if (tag == CTAG('=', 'P', 'k', 'g')
-          || tag == CTAG('=', 'P', 'a', 't'))
-       {
-         /* If we have an old solvable, complete it by filling in some
-            default stuff.  */
-         if (s)
-           finish_solvable(&pd, s, freshens);
-
-         /*
-          * define kind
-          */
-
-         pd.kind = 0;
-         if (line[3] == 't')
-           pd.kind = "pattern";
-
-         /*
-          * parse nevra
-          */
-
-          if (split(line + 5, sp, 5) != 4)
-           {
-             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
-             break;
-           }
-         s = 0;
-          freshens = 0;
-
-         if (joinhash)
-           {
-             /* data join operation. find solvable matching name/arch/evr and
-               * add data to it */
-             Id name, evr, arch;
-             /* we don't use the create flag here as a simple pre-check for existance */
-             if (pd.kind)
-               name = pool_str2id(pool, join2(&pd.jd, pd.kind, ":", sp[0]), 0);
-             else
-               name = pool_str2id(pool, sp[0], 0);
-             evr = toevr(pool, &pd, sp[1], sp[2]);
-             arch = pool_str2id(pool, sp[3], 0);
-             if (name && arch)
-               {
-                 Id start = (flags & REPO_EXTEND_SOLVABLES) ? 0 : first_new_pkg;
-                 if (repo->start + last_found_pack + 1 >= start && repo->start + last_found_pack + 1 < repo->end)
-                   {
-                     s = pool->solvables + repo->start + last_found_pack + 1;
-                     if (s->repo != repo || s->name != name || s->evr != evr || s->arch != arch)
-                       s = 0;
-                   }
-                 if (!s)
-                   s = joinhash_lookup(repo, joinhash, joinhashm, name, evr, arch, start);
-               }
-             /* do not create new packages in EXTEND_SOLVABLES mode */
-             if (!s && (flags & REPO_EXTEND_SOLVABLES) != 0)
-               continue;
-             /* fallthrough to package creation */
-           }
-         if (!s)
-           {
-             /* normal operation. create a new solvable. */
-             s = pool_id2solvable(pool, repo_add_solvable(repo));
-             if (pd.kind)
-               s->name = pool_str2id(pool, join2(&pd.jd, pd.kind, ":", sp[0]), 1);
-             else
-               s->name = pool_str2id(pool, sp[0], 1);
-             s->evr = toevr(pool, &pd, sp[1], sp[2]);
-             s->arch = pool_str2id(pool, sp[3], 1);
-             s->vendor = defvendor;
-             if (!first_new_pkg)
-               first_new_pkg = s - pool->solvables;
-             createdpkgs = 1;
-           }
-         last_found_pack = (s - pool->solvables) - repo->start;
-         if (data)
-           handle = s - pool->solvables;
-       }
-
-      /* If we have no current solvable to add to, ignore all further lines
-         for it.  Probably invalid input data in the second set of
-        solvables.  */
-      if (indesc >= 2 && !s)
-        {
-#if 0
-         pool_debug(pool, SOLV_ERROR, "susetags: huh %d: %s?\n", pd.lineno, line);
-#endif
-          continue;
-       }
-      switch (tag)
-        {
-         case CTAG('=', 'P', 'r', 'v'):                                        /* provides */
-           if (line[6] == '/')
-             {
-               /* probably a filelist entry. stash it away for now */
-               int l = strlen(line + 6) + 1;
-               if (pd.nfilelist + l > pd.afilelist)
-                 {
-                   pd.afilelist = pd.nfilelist + l + 512;
-                   pd.filelist = solv_realloc(pd.filelist, pd.afilelist);
-                 }
-               memcpy(pd.filelist + pd.nfilelist, line + 6, l);
-               pd.nfilelist += l;
-               break;
-             }
-           if (pd.nfilelist)
-             {
-               int l;
-               for (l = 0; l < pd.nfilelist; l += strlen(pd.filelist + l) + 1)
-                 s->provides = repo_addid_dep(pd.repo, s->provides, pool_str2id(pool, pd.filelist + l, 1), 0);
-               pd.nfilelist = 0;
-             }
-           s->provides = adddep(pool, &pd, s->provides, line, 0, pd.kind);
-           continue;
-         case CTAG('=', 'R', 'e', 'q'):                                        /* requires */
-           s->requires = adddep(pool, &pd, s->requires, line, -SOLVABLE_PREREQMARKER, pd.kind);
-           continue;
-          case CTAG('=', 'P', 'r', 'q'):                                        /* pre-requires / packages required */
-           if (pd.kind)
-             {
-               s->requires = adddep(pool, &pd, s->requires, line, 0, 0);           /* patterns: a required package */
-             }
-           else
-             s->requires = adddep(pool, &pd, s->requires, line, SOLVABLE_PREREQMARKER, 0); /* package: pre-requires */
-           continue;
-         case CTAG('=', 'O', 'b', 's'):                                        /* obsoletes */
-           s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'C', 'o', 'n'):                                        /* conflicts */
-           s->conflicts = adddep(pool, &pd, s->conflicts, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'R', 'e', 'c'):                                        /* recommends */
-           s->recommends = adddep(pool, &pd, s->recommends, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'S', 'u', 'p'):                                        /* supplements */
-           s->supplements = adddep(pool, &pd, s->supplements, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'E', 'n', 'h'):                                        /* enhances */
-           s->enhances = adddep(pool, &pd, s->enhances, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'S', 'u', 'g'):                                        /* suggests */
-           s->suggests = adddep(pool, &pd, s->suggests, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'F', 'r', 'e'):                                        /* freshens */
-           freshens = adddep(pool, &pd, freshens, line, 0, pd.kind);
-           continue;
-          case CTAG('=', 'P', 'r', 'c'):                                        /* packages recommended */
-           s->recommends = adddep(pool, &pd, s->recommends, line, 0, 0);
-           continue;
-          case CTAG('=', 'P', 's', 'g'):                                        /* packages suggested */
-           s->suggests = adddep(pool, &pd, s->suggests, line, 0, 0);
-           continue;
-          case CTAG('=', 'P', 'c', 'n'):                                        /* pattern: package conflicts */
-           s->conflicts = adddep(pool, &pd, s->conflicts, line, 0, 0);
-           continue;
-         case CTAG('=', 'P', 'o', 'b'):                                        /* pattern: package obsoletes */
-           s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, 0);
-           continue;
-          case CTAG('=', 'P', 'f', 'r'):                                        /* pattern: package freshens */
-           freshens = adddep(pool, &pd, freshens, line, 0, 0);
-           continue;
-          case CTAG('=', 'P', 's', 'p'):                                        /* pattern: package supplements */
-           s->supplements = adddep(pool, &pd, s->supplements, line, 0, 0);
-           continue;
-          case CTAG('=', 'P', 'e', 'n'):                                        /* pattern: package enhances */
-           s->enhances = adddep(pool, &pd, s->enhances, line, 0, 0);
-           continue;
-          case CTAG('=', 'V', 'e', 'r'):                                        /* - version - */
-           last_found_pack = 0;
-           handle = 0;
-           indesc++;
-           if (createdpkgs)
-             {
-               solv_free(joinhash);
-               joinhash = joinhash_init(repo, &joinhashm);
-               createdpkgs = 0;
-             }
-           continue;
-          case CTAG('=', 'V', 'n', 'd'):                                        /* vendor */
-            s->vendor = pool_str2id(pool, line + 6, 1);
-            continue;
-
-        /* From here it's the attribute tags.  */
-          case CTAG('=', 'G', 'r', 'p'):
-           repodata_set_poolstr(data, handle, SOLVABLE_GROUP, line + 6);
-           continue;
-          case CTAG('=', 'L', 'i', 'c'):
-           repodata_set_poolstr(data, handle, SOLVABLE_LICENSE, line + 6);
-           continue;
-          case CTAG('=', 'L', 'o', 'c'):
-           {
-             int i = split(line + 6, sp, 3);
-             if (i != 2 && i != 3)
-               {
-                 pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line);
-                 continue;
-               }
-             repodata_set_location(data, handle, atoi(sp[0]), i == 3 ? sp[2] : pool_id2str(pool, s->arch), sp[1]);
-           }
-           continue;
-          case CTAG('=', 'S', 'r', 'c'):
-           add_source(&pd, line + 6, s, handle);
-           continue;
-          case CTAG('=', 'S', 'i', 'z'):
-           if (split(line + 6, sp, 3) == 2)
-             {
-               repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(sp[0], 0, 10));
-               repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, strtoull(sp[1], 0, 10));
-             }
-           continue;
-          case CTAG('=', 'T', 'i', 'm'):
-           {
-             unsigned int t = atoi(line + 6);
-             if (t)
-               repodata_set_num(data, handle, SOLVABLE_BUILDTIME, t);
-           }
-           continue;
-          case CTAG('=', 'K', 'w', 'd'):
-           repodata_add_poolstr_array(data, handle, SOLVABLE_KEYWORDS, line + 6);
-           continue;
-          case CTAG('=', 'A', 'u', 't'):
-           repodata_set_str(data, handle, SOLVABLE_AUTHORS, line + 6);
-           continue;
-          case CTAG('=', 'S', 'u', 'm'):
-            repodata_set_str(data, handle, langtag(&pd, SOLVABLE_SUMMARY, line_lang), line + 3 + keylen);
-            continue;
-          case CTAG('=', 'D', 'e', 's'):
-           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_DESCRIPTION, line_lang), line + 3 + keylen);
-           continue;
-          case CTAG('=', 'E', 'u', 'l'):
-           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_EULA, line_lang), line + 6);
-           continue;
-          case CTAG('=', 'I', 'n', 's'):
-           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_MESSAGEINS, line_lang), line + 6);
-           continue;
-          case CTAG('=', 'D', 'e', 'l'):
-           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_MESSAGEDEL, line_lang), line + 6);
-           continue;
-          case CTAG('=', 'V', 'i', 's'):
-           {
-             /* Accept numbers and textual bools.  */
-             int k;
-             k = atoi(line + 6);
-             if (k || !strcasecmp(line + 6, "true"))
-               repodata_set_void(data, handle, SOLVABLE_ISVISIBLE);
-           }
-           continue;
-          case CTAG('=', 'S', 'h', 'r'):
-           {
-             Id name, evr, arch;
-             if (split(line + 6, sp, 5) != 4)
-               {
-                 pd.ret = pool_error(pool, -1, "susetags: line %d: bad =Shr line '%s'\n", pd.lineno, line);
-                 continue;
-               }
-             name = pool_str2id(pool, sp[0], 1);
-             evr = toevr(pool, &pd, sp[1], sp[2]);
-             arch = pool_str2id(pool, sp[3], 1);
-             if (last_found_pack >= pd.nshare)
-               {
-                 pd.share_with = solv_realloc2(pd.share_with, last_found_pack + 256, sizeof(*pd.share_with));
-                 memset(pd.share_with + pd.nshare, 0, (last_found_pack + 256 - pd.nshare) * sizeof(*pd.share_with));
-                 pd.nshare = last_found_pack + 256;
-               }
-             pd.share_with[last_found_pack].name = name;
-             pd.share_with[last_found_pack].evr = evr;
-             pd.share_with[last_found_pack].arch = arch;
-             if ((flags & SUSETAGS_RECORD_SHARES) != 0)
-               {
-                 if (s->name == name)
-                   repodata_set_void(data, handle, SUSETAGS_SHARE_NAME);
-                 else
-                   repodata_set_id(data, handle, SUSETAGS_SHARE_NAME, name);
-                 if (s->evr == evr)
-                   repodata_set_void(data, handle, SUSETAGS_SHARE_EVR);
-                 else
-                   repodata_set_id(data, handle, SUSETAGS_SHARE_EVR, evr);
-                 if (s->arch == arch)
-                   repodata_set_void(data, handle, SUSETAGS_SHARE_ARCH);
-                 else
-                   repodata_set_id(data, handle, SUSETAGS_SHARE_ARCH, arch);
-               }
-             continue;
-           }
-         case CTAG('=', 'D', 'i', 'r'):
-           add_dirline(&pd, line + 6);
-           continue;
-         case CTAG('=', 'C', 'a', 't'):
-           repodata_set_poolstr(data, handle, langtag(&pd, SOLVABLE_CATEGORY, line_lang), line + 3 + keylen);
-           break;
-         case CTAG('=', 'O', 'r', 'd'):
-           /* Order is a string not a number, so we can retroactively insert
-              new patterns in the middle, i.e. 1 < 15 < 2.  */
-           repodata_set_str(data, handle, SOLVABLE_ORDER, line + 6);
-           break;
-         case CTAG('=', 'I', 'c', 'o'):
-           repodata_set_str(data, handle, SOLVABLE_ICON, line + 6);
-           break;
-         case CTAG('=', 'E', 'x', 't'):
-           repodata_add_poolstr_array(data, handle, SOLVABLE_EXTENDS, join2(&pd.jd, "pattern", ":", line + 6));
-           break;
-         case CTAG('=', 'I', 'n', 'c'):
-           repodata_add_poolstr_array(data, handle, SOLVABLE_INCLUDES, join2(&pd.jd, "pattern", ":", line + 6));
-           break;
-         case CTAG('=', 'C', 'k', 's'):
-           set_checksum(&pd, data, handle, SOLVABLE_CHECKSUM, line + 6);
-           break;
-         case CTAG('=', 'L', 'a', 'n'):
-           pd.language = solv_free(pd.language);
-           memset(pd.langcache, 0, sizeof(pd.langcache));
-           if (line[6])
-             pd.language = solv_strdup(line + 6);
-           break;
-
-         case CTAG('=', 'F', 'l', 's'):
-           {
-             char *p = strrchr(line + 6, '/');
-             Id did;
-             /* strip trailing slash */
-             if (p && p != line + 6 && !p[1])
-               {
-                 *p = 0;
-                 p = strrchr(line + 6, '/');
-               }
-             if (p)
-               {
-                 *p++ = 0;
-                 did = repodata_str2dir(data, line + 6, 1);
-               }
-             else
-               {
-                 p = line + 6;
-                 did = 0;
-               }
-             if (!did)
-               did = repodata_str2dir(data, "/", 1);
-             repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, p);
-             break;
-           }
-         case CTAG('=', 'H', 'd', 'r'):
-           /* rpm header range */
-           if (split(line + 6, sp, 3) == 2)
-             {
-               /* we ignore the start value */
-               unsigned int end = (unsigned int)atoi(sp[1]);
-               if (end)
-                 repodata_set_num(data, handle, SOLVABLE_HEADEREND, end);
-             }
-           break;
-
-         case CTAG('=', 'P', 'a', 't'):
-         case CTAG('=', 'P', 'k', 'g'):
-           break;
-
-         default:
-#if 0
-           pool_debug(pool, SOLV_WARN, "susetags: unknown line: %d: %s\n", pd.lineno, line);
-#endif
-           break;
-       }
-
-    }
-
-  if (s)
-    finish_solvable(&pd, s, freshens);
-  solv_free(pd.filelist);
-
-  /* Shared attributes
-   *  (e.g. multiple binaries built from same source)
-   */
-  if (pd.nshare)
-    {
-      int i, last_found;
-      Map keyidmap;
-
-      map_init(&keyidmap, data->nkeys);
-      for (i = 1; i < data->nkeys; i++)
-       {
-         Id keyname = data->keys[i].name;
-         if (keyname == SOLVABLE_INSTALLSIZE || keyname == SOLVABLE_DISKUSAGE || keyname == SOLVABLE_FILELIST)
-           continue;
-         if (keyname == SOLVABLE_MEDIADIR || keyname == SOLVABLE_MEDIAFILE || keyname == SOLVABLE_MEDIANR)
-           continue;
-         if (keyname == SOLVABLE_DOWNLOADSIZE || keyname == SOLVABLE_CHECKSUM)
-           continue;
-         if (keyname == SOLVABLE_SOURCENAME || keyname == SOLVABLE_SOURCEARCH || keyname == SOLVABLE_SOURCEEVR)
-           continue;
-         if (keyname == SOLVABLE_PKGID || keyname == SOLVABLE_HDRID || keyname == SOLVABLE_LEADSIGID)
-           continue;
-         if (keyname == SUSETAGS_SHARE_NAME || keyname == SUSETAGS_SHARE_EVR || keyname == SUSETAGS_SHARE_ARCH)
-           continue;
-         MAPSET(&keyidmap, i);
-       }
-      last_found = 0;
-      for (i = 0; i < pd.nshare; i++)
-       {
-         unsigned int n, nn;
-         Solvable *found = 0;
-          if (!pd.share_with[i].name)
-           continue;
-         for (n = repo->start, nn = repo->start + last_found; n < repo->end; n++, nn++)
-           {
-             if (nn >= repo->end)
-               nn = repo->start;
-             found = pool->solvables + nn;
-             if (found->repo == repo
-                 && found->name == pd.share_with[i].name
-                 && found->evr == pd.share_with[i].evr
-                 && found->arch == pd.share_with[i].arch)
-               {
-                 last_found = nn - repo->start;
-                 break;
-               }
-           }
-         if (n != repo->end)
-           repodata_merge_some_attrs(data, repo->start + i, repo->start + last_found, &keyidmap, 0);
-        }
-      free(pd.share_with);
-      map_free(&keyidmap);
-    }
-
-  solv_free(joinhash);
-  repodata_free_dircache(data);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-
-  solv_free(pd.language);
-  solv_free(line);
-  join_freemem(&pd.jd);
-  return pd.ret;
-}
diff --git a/libsolv-0.6.15/ext/repo_susetags.h b/libsolv-0.6.15/ext/repo_susetags.h
deleted file mode 100644 (file)
index de110c3..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/* read susetags file <fp> into <repo>
- * if <attrname> given, write attributes as '<attrname>.attr'
- */
-
-#define SUSETAGS_EXTEND                        (1 << 9)
-#define SUSETAGS_RECORD_SHARES         (1 << 10)
-
-extern int repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int flags);
diff --git a/libsolv-0.6.15/ext/repo_updateinfoxml.c b/libsolv-0.6.15/ext/repo_updateinfoxml.c
deleted file mode 100644 (file)
index 6af74f2..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-#define _XOPEN_SOURCE /* glibc2 needs this */
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <expat.h>
-#include <time.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_updateinfoxml.h"
-#define DISABLE_SPLIT
-#include "tools_util.h"
-
-/*
- * <updates>
- *   <update from="rel-eng@fedoraproject.org" status="stable" type="security" version="1.4">
- *     <id>FEDORA-2007-4594</id>
- *     <title>imlib-1.9.15-6.fc8</title>
- *     <severity>Important</severity>
- *     <release>Fedora 8</release>
- *     <rights>Copyright 2007 Company Inc</rights>
- *     <issued date="2007-12-28 16:42:30"/>
- *     <updated date="2008-03-14 12:00:00"/>
- *     <references>
- *       <reference href="https://bugzilla.redhat.com/show_bug.cgi?id=426091" id="426091" title="CVE-2007-3568 imlib: infinite loop DoS using crafted BMP image" type="bugzilla"/>
- *     </references>
- *     <description>This update includes a fix for a denial-of-service issue (CVE-2007-3568) whereby an attacker who could get an imlib-using user to view a  specially-crafted BMP image could cause the user's CPU to go into an infinite loop.</description>
- *     <pkglist>
- *       <collection short="F8">
- *         <name>Fedora 8</name>
- *         <package arch="ppc64" name="imlib-debuginfo" release="6.fc8" src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm" version="1.9.15">
- *           <filename>imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm</filename>
- *           <reboot_suggested>True</reboot_suggested>
- *         </package>
- *       </collection>
- *     </pkglist>
- *   </update>
- * </updates>
-*/
-
-enum state {
-  STATE_START,
-  STATE_UPDATES,
-  STATE_UPDATE,
-  STATE_ID,
-  STATE_TITLE,
-  STATE_RELEASE,
-  STATE_ISSUED,
-  STATE_UPDATED,
-  STATE_MESSAGE,
-  STATE_REFERENCES,
-  STATE_REFERENCE,
-  STATE_DESCRIPTION,
-  STATE_PKGLIST,
-  STATE_COLLECTION,
-  STATE_NAME,
-  STATE_PACKAGE,
-  STATE_FILENAME,
-  STATE_REBOOT,
-  STATE_RESTART,
-  STATE_RELOGIN,
-  STATE_RIGHTS,
-  STATE_SEVERITY,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
-  { STATE_START,       "updates",         STATE_UPDATES,     0 },
-  { STATE_START,       "update",          STATE_UPDATE,      0 },
-  { STATE_UPDATES,     "update",          STATE_UPDATE,      0 },
-  { STATE_UPDATE,      "id",              STATE_ID,          1 },
-  { STATE_UPDATE,      "title",           STATE_TITLE,       1 },
-  { STATE_UPDATE,      "severity",        STATE_SEVERITY,    1 },
-  { STATE_UPDATE,      "rights",          STATE_RIGHTS,      1 },
-  { STATE_UPDATE,      "release",         STATE_RELEASE,     1 },
-  { STATE_UPDATE,      "issued",          STATE_ISSUED,      0 },
-  { STATE_UPDATE,      "updated",         STATE_UPDATED,     0 },
-  { STATE_UPDATE,      "description",     STATE_DESCRIPTION, 1 },
-  { STATE_UPDATE,      "message",         STATE_MESSAGE    , 1 },
-  { STATE_UPDATE,      "references",      STATE_REFERENCES,  0 },
-  { STATE_UPDATE,      "pkglist",         STATE_PKGLIST,     0 },
-  { STATE_REFERENCES,  "reference",       STATE_REFERENCE,   0 },
-  { STATE_PKGLIST,     "collection",      STATE_COLLECTION,  0 },
-  { STATE_COLLECTION,  "name",            STATE_NAME,        1 },
-  { STATE_COLLECTION,  "package",         STATE_PACKAGE,     0 },
-  { STATE_PACKAGE,     "filename",        STATE_FILENAME,    1 },
-  { STATE_PACKAGE,     "reboot_suggested",STATE_REBOOT,      1 },
-  { STATE_PACKAGE,     "restart_suggested",STATE_RESTART,    1 },
-  { STATE_PACKAGE,     "relogin_suggested",STATE_RELOGIN,    1 },
-  { NUMSTATES }
-};
-
-struct parsedata {
-  int ret;
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-  Id handle;
-  Solvable *solvable;
-  time_t buildtime;
-  Id collhandle;
-  struct joindata jd;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-};
-
-/*
- * Convert date strings ("1287746075" or "2010-10-22 13:14:35")
- * to timestamp.
- */
-static time_t
-datestr2timestamp(const char *date)
-{
-  const char *p;
-  struct tm tm;
-
-  if (!date || !*date)
-    return 0;
-  for (p = date; *p >= '0' && *p <= '9'; p++)
-    ;
-  if (!*p)
-    return atoi(date);
-  memset(&tm, 0, sizeof(tm));
-  if (!strptime(date, "%F%T", &tm))
-    return 0;
-  return timegm(&tm);
-}
-
-/*
- * create evr (as Id) from 'epoch', 'version' and 'release' attributes
- */
-static Id
-makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
-{
-  const char *e, *v, *r, *v2;
-  char *c;
-  int l;
-
-  e = v = r = 0;
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, "epoch"))
-       e = atts[1];
-      else if (!strcmp(*atts, "version"))
-       v = atts[1];
-      else if (!strcmp(*atts, "release"))
-       r = atts[1];
-    }
-  if (e && (!*e || !strcmp(e, "0")))
-    e = 0;
-  if (v && !e)
-    {
-      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
-        ;
-      if (v2 > v && *v2 == ':')
-       e = "0";
-    }
-  l = 1;
-  if (e)
-    l += strlen(e) + 1;
-  if (v)
-    l += strlen(v);
-  if (r)
-    l += strlen(r) + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content;
-  if (e)
-    {
-      strcpy(c, e);
-      c += strlen(c);
-      *c++ = ':';
-    }
-  if (v)
-    {
-      strcpy(c, v);
-      c += strlen(c);
-    }
-  if (r)
-    {
-      *c++ = '-';
-      strcpy(c, r);
-      c += strlen(c);
-    }
-  *c = 0;
-  if (!*pd->content)
-    return 0;
-#if 0
-  fprintf(stderr, "evr: %s\n", pd->content);
-#endif
-  return pool_str2id(pool, pd->content, 1);
-}
-
-
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *solvable = pd->solvable;
-  struct stateswitch *sw;
-  /*const char *str; */
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])
-    return;
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_START:
-      break;
-    case STATE_UPDATES:
-      break;
-      /*
-       * <update from="rel-eng@fedoraproject.org"
-       *         status="stable"
-       *         type="bugfix" (enhancement, security)
-       *         version="1.4">
-       */
-    case STATE_UPDATE:
-      {
-       const char *from = 0, *type = 0, *version = 0;
-       for (; *atts; atts += 2)
-         {
-           if (!strcmp(*atts, "from"))
-             from = atts[1];
-           else if (!strcmp(*atts, "type"))
-             type = atts[1];
-           else if (!strcmp(*atts, "version"))
-             version = atts[1];
-         }
-       solvable = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-       pd->handle = pd->solvable - pool->solvables;
-
-       solvable->vendor = pool_str2id(pool, from, 1);
-       solvable->evr = pool_str2id(pool, version, 1);
-       solvable->arch = ARCH_NOARCH;
-       if (type)
-         repodata_set_str(pd->data, pd->handle, SOLVABLE_PATCHCATEGORY, type);
-        pd->buildtime = (time_t)0;
-      }
-      break;
-      /* <id>FEDORA-2007-4594</id> */
-    case STATE_ID:
-      break;
-      /* <title>imlib-1.9.15-6.fc8</title> */
-    case STATE_TITLE:
-      break;
-      /* <release>Fedora 8</release> */
-    case STATE_RELEASE:
-      break;
-      /*  <issued date="2008-03-21 21:36:55"/>
-      */
-    case STATE_ISSUED:
-    case STATE_UPDATED:
-      {
-       const char *date = 0;
-       for (; *atts; atts += 2)
-         {
-           if (!strcmp(*atts, "date"))
-             date = atts[1];
-         }
-       if (date)
-         {
-           time_t t = datestr2timestamp(date);
-           if (t && t > pd->buildtime)
-              pd->buildtime = t;
-         }
-      }
-      break;
-    case STATE_REFERENCES:
-      break;
-      /*  <reference href="https://bugzilla.redhat.com/show_bug.cgi?id=330471"
-       *             id="330471"
-       *             title="LDAP schema file missing for dhcpd"
-       *             type="bugzilla"/>
-       */
-    case STATE_REFERENCE:
-      {
-        const char *href = 0, *id = 0, *title = 0, *type = 0;
-       Id refhandle;
-       for (; *atts; atts += 2)
-         {
-           if (!strcmp(*atts, "href"))
-             href = atts[1];
-           else if (!strcmp(*atts, "id"))
-             id = atts[1];
-           else if (!strcmp(*atts, "title"))
-             title = atts[1];
-           else if (!strcmp(*atts, "type"))
-             type = atts[1];
-         }
-       refhandle = repodata_new_handle(pd->data);
-       if (href)
-         repodata_set_str(pd->data, refhandle, UPDATE_REFERENCE_HREF, href);
-       if (id)
-         repodata_set_str(pd->data, refhandle, UPDATE_REFERENCE_ID, id);
-       if (title)
-         repodata_set_str(pd->data, refhandle, UPDATE_REFERENCE_TITLE, title);
-       if (type)
-         repodata_set_poolstr(pd->data, refhandle, UPDATE_REFERENCE_TYPE, type);
-       repodata_add_flexarray(pd->data, pd->handle, UPDATE_REFERENCE, refhandle);
-      }
-      break;
-      /* <description>This update ...</description> */
-    case STATE_DESCRIPTION:
-      break;
-      /* <message type="confirm">This update ...</message> */
-    case STATE_MESSAGE:
-      break;
-    case STATE_PKGLIST:
-      break;
-      /* <collection short="F8" */
-    case STATE_COLLECTION:
-      break;
-      /* <name>Fedora 8</name> */
-    case STATE_NAME:
-      break;
-      /*   <package arch="ppc64" name="imlib-debuginfo" release="6.fc8"
-       *            src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm"
-       *            version="1.9.15">
-       *
-       *
-       * -> patch.conflicts: {name} < {version}.{release}
-       */
-    case STATE_PACKAGE:
-      {
-       const char *arch = 0, *name = 0;
-       Id evr = makeevr_atts(pool, pd, atts); /* parse "epoch", "version", "release" */
-       Id n, a = 0;
-       Id rel_id;
-
-       for (; *atts; atts += 2)
-         {
-           if (!strcmp(*atts, "arch"))
-             arch = atts[1];
-           else if (!strcmp(*atts, "name"))
-             name = atts[1];
-         }
-       /* generated Id for name */
-       n = pool_str2id(pool, name, 1);
-       rel_id = n;
-       if (arch)
-         {
-           /*  generate Id for arch and combine with name */
-           a = pool_str2id(pool, arch, 1);
-           rel_id = pool_rel2id(pool, n, a, REL_ARCH, 1);
-         }
-       rel_id = pool_rel2id(pool, rel_id, evr, REL_LT, 1);
-       solvable->conflicts = repo_addid_dep(pd->repo, solvable->conflicts, rel_id, 0);
-
-        /* who needs the collection anyway? */
-        pd->collhandle = repodata_new_handle(pd->data);
-       repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_NAME, n);
-       repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_EVR, evr);
-       if (a)
-         repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
-        break;
-      }
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
-    case STATE_FILENAME:
-      break;
-      /* <reboot_suggested>True</reboot_suggested> */
-    case STATE_REBOOT:
-      break;
-      /* <restart_suggested>True</restart_suggested> */
-    case STATE_RESTART:
-      break;
-      /* <relogin_suggested>True</relogin_suggested> */
-    case STATE_RELOGIN:
-      break;
-    default:
-      break;
-    }
-  return;
-}
-
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  Repo *repo = pd->repo;
-
-#if 0
-      fprintf(stderr, "end: %s\n", name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-  switch (pd->state)
-    {
-    case STATE_START:
-      break;
-    case STATE_UPDATES:
-      break;
-    case STATE_UPDATE:
-      s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-      if (pd->buildtime)
-       {
-         repodata_set_num(pd->data, pd->handle, SOLVABLE_BUILDTIME, pd->buildtime);
-         pd->buildtime = (time_t)0;
-       }
-      break;
-    case STATE_ID:
-      s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", pd->content), 1);
-      break;
-      /* <title>imlib-1.9.15-6.fc8</title> */
-    case STATE_TITLE:
-      while (pd->lcontent > 0 && pd->content[pd->lcontent - 1] == '\n')
-        pd->content[--pd->lcontent] = 0;
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, pd->content);
-      break;
-    case STATE_SEVERITY:
-      repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, pd->content);
-      break;
-    case STATE_RIGHTS:
-      repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, pd->content);
-      break;
-      /*
-       * <release>Fedora 8</release>
-       */
-    case STATE_RELEASE:
-      break;
-    case STATE_ISSUED:
-      break;
-    case STATE_REFERENCES:
-      break;
-    case STATE_REFERENCE:
-      break;
-      /*
-       * <description>This update ...</description>
-       */
-    case STATE_DESCRIPTION:
-      repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, pd->content);
-      break;
-      /*
-       * <message>Warning! ...</message>
-       */
-    case STATE_MESSAGE:
-      repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, pd->content);
-      break;
-    case STATE_PKGLIST:
-      break;
-    case STATE_COLLECTION:
-      break;
-    case STATE_NAME:
-      break;
-    case STATE_PACKAGE:
-      repodata_add_flexarray(pd->data, pd->handle, UPDATE_COLLECTION, pd->collhandle);
-      pd->collhandle = 0;
-      break;
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
-    case STATE_FILENAME:
-      repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, pd->content);
-      break;
-      /* <reboot_suggested>True</reboot_suggested> */
-    case STATE_REBOOT:
-      if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
-       {
-         /* FIXME: this is per-package, the global flag should be computed at runtime */
-         repodata_set_void(pd->data, pd->handle, UPDATE_REBOOT);
-         repodata_set_void(pd->data, pd->collhandle, UPDATE_REBOOT);
-       }
-      break;
-      /* <restart_suggested>True</restart_suggested> */
-    case STATE_RESTART:
-      if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
-       {
-         /* FIXME: this is per-package, the global flag should be computed at runtime */
-         repodata_set_void(pd->data, pd->handle, UPDATE_RESTART);
-         repodata_set_void(pd->data, pd->collhandle, UPDATE_RESTART);
-       }
-      break;
-      /* <relogin_suggested>True</relogin_suggested> */
-    case STATE_RELOGIN:
-      if (pd->content[0] == 'T' || pd->content[0] == 't'|| pd->content[0] == '1')
-       {
-         /* FIXME: this is per-package, the global flag should be computed at runtime */
-         repodata_set_void(pd->data, pd->handle, UPDATE_RELOGIN);
-         repodata_set_void(pd->data, pd->collhandle, UPDATE_RELOGIN);
-       }
-      break;
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-
-  if (!pd->docontent)
-    {
-#if 0
-      fprintf(stderr, "Content: [%d]'%.*s'\n", pd->state, len, s);
-#endif
-      return;
-    }
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-
-#define BUFF_SIZE 8192
-
-int
-repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  struct parsedata pd;
-  char buf[BUFF_SIZE];
-  int i, l;
-  struct stateswitch *sw;
-  Repodata *data;
-  XML_Parser parser;
-
-  data = repo_add_repodata(repo, flags);
-
-  memset(&pd, 0, sizeof(pd));
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-  pd.pool = pool;
-  pd.repo = repo;
-  pd.data = data;
-
-  pd.content = malloc(256);
-  pd.acontent = 256;
-  pd.lcontent = 0;
-  parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, &pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         break;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-  free(pd.content);
-  join_freemem(&pd.jd);
-
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return pd.ret;
-}
-
diff --git a/libsolv-0.6.15/ext/repo_updateinfoxml.h b/libsolv-0.6.15/ext/repo_updateinfoxml.h
deleted file mode 100644 (file)
index bd0a61b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.6.15/ext/repo_zyppdb.c b/libsolv-0.6.15/ext/repo_zyppdb.c
deleted file mode 100644 (file)
index 5200c29..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * repo_zyppdb.c
- *
- * Parses legacy /var/lib/zypp/db/products/... files.
- * They are old (pre Code11) product descriptions. See bnc#429177
- *
- *
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <dirent.h>
-#include <expat.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#define DISABLE_SPLIT
-#include "tools_util.h"
-#include "repo_zyppdb.h"
-
-
-enum state {
-  STATE_START,
-  STATE_PRODUCT,
-  STATE_NAME,
-  STATE_VERSION,
-  STATE_ARCH,
-  STATE_SUMMARY,
-  STATE_VENDOR,
-  STATE_INSTALLTIME,
-  NUMSTATES
-};
-
-struct stateswitch {
-  enum state from;
-  char *ename;
-  enum state to;
-  int docontent;
-};
-
-/* !! must be sorted by first column !! */
-static struct stateswitch stateswitches[] = {
-  { STATE_START,     "product",       STATE_PRODUCT,       0 },
-  { STATE_PRODUCT,   "name",          STATE_NAME,          1 },
-  { STATE_PRODUCT,   "version",       STATE_VERSION,       0 },
-  { STATE_PRODUCT,   "arch",          STATE_ARCH,          1 },
-  { STATE_PRODUCT,   "summary",       STATE_SUMMARY,       1 },
-  { STATE_PRODUCT,   "install-time",  STATE_INSTALLTIME,   1 },
-  { STATE_PRODUCT,   "vendor",        STATE_VENDOR,        1 },
-  { NUMSTATES }
-};
-
-struct parsedata {
-  int depth;
-  enum state state;
-  int statedepth;
-  char *content;
-  int lcontent;
-  int acontent;
-  int docontent;
-  Pool *pool;
-  Repo *repo;
-  Repodata *data;
-
-  struct stateswitch *swtab[NUMSTATES];
-  enum state sbtab[NUMSTATES];
-  struct joindata jd;
-
-  const char *tmplang;
-
-  Solvable *solvable;
-  Id handle;
-};
-
-
-/*
- * find_attr
- * find value for xml attribute
- * I: txt, name of attribute
- * I: atts, list of key/value attributes
- * O: pointer to value of matching key, or NULL
- *
- */
-
-static inline const char *
-find_attr(const char *txt, const char **atts)
-{
-  for (; *atts; atts += 2)
-    {
-      if (!strcmp(*atts, txt))
-        return atts[1];
-    }
-  return 0;
-}
-
-
-/*
- * XML callback: startElement
- */
-
-static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
-  struct parsedata *pd = userData;
-  Pool *pool = pd->pool;
-  Solvable *s = pd->solvable;
-  struct stateswitch *sw;
-
-#if 0
-  fprintf(stderr, "start: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth++;
-      return;
-    }
-
-  pd->depth++;
-  if (!pd->swtab[pd->state])   /* no statetable -> no substates */
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
-    if (!strcmp(sw->ename, name))
-      break;
-
-  if (sw->from != pd->state)
-    {
-#if 0
-      fprintf(stderr, "into unknown: %s (from: %d)\n", name, pd->state);
-#endif
-      return;
-    }
-  pd->state = sw->to;
-  pd->docontent = sw->docontent;
-  pd->statedepth = pd->depth;
-  pd->lcontent = 0;
-  *pd->content = 0;
-
-  switch(pd->state)
-    {
-    case STATE_PRODUCT:
-      {
-       /* parse 'type' */
-       const char *type = find_attr("type", atts);
-       s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
-       pd->handle = s - pool->solvables;
-       if (type)
-         repodata_set_str(pd->data, pd->handle, PRODUCT_TYPE, type);
-      }
-      break;
-    case STATE_VERSION:
-      {
-       const char *ver = find_attr("ver", atts);
-       const char *rel = find_attr("rel", atts);
-       /* const char *epoch = find_attr("epoch", atts); ignored */
-       s->evr = makeevr(pd->pool, join2(&pd->jd, ver, "-", rel));
-      }
-      break;
-      /* <summary lang="xy">... */
-    case STATE_SUMMARY:
-      pd->tmplang = join_dup(&pd->jd, find_attr("lang", atts));
-      break;
-    default:
-      break;
-    }
-}
-
-
-static void XMLCALL
-endElement(void *userData, const char *name)
-{
-  struct parsedata *pd = userData;
-  Solvable *s = pd->solvable;
-
-#if 0
-  fprintf(stderr, "end: [%d]%s\n", pd->state, name);
-#endif
-  if (pd->depth != pd->statedepth)
-    {
-      pd->depth--;
-#if 0
-      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
-#endif
-      return;
-    }
-
-  pd->depth--;
-  pd->statedepth--;
-
-  switch (pd->state)
-    {
-    case STATE_PRODUCT:
-      if (!s->arch)
-       s->arch = ARCH_NOARCH;
-      if (!s->evr)
-       s->evr = ID_EMPTY;
-      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
-      pd->solvable = 0;
-      break;
-    case STATE_NAME:
-      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", pd->content), 1);
-      break;
-    case STATE_ARCH:
-      s->arch = pool_str2id(pd->pool, pd->content, 1);
-      break;
-    case STATE_SUMMARY:
-      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), pd->content);
-      break;
-    case STATE_VENDOR:
-      s->vendor = pool_str2id(pd->pool, pd->content, 1);
-      break;
-    case STATE_INSTALLTIME:
-      repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(pd->content));
-    default:
-      break;
-    }
-
-  pd->state = pd->sbtab[pd->state];
-  pd->docontent = 0;
-
-#if 0
-  fprintf(stderr, "end: [%s] -> %d\n", name, pd->state);
-#endif
-}
-
-
-static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
-  struct parsedata *pd = userData;
-  int l;
-  char *c;
-  if (!pd->docontent)
-    return;
-  l = pd->lcontent + len + 1;
-  if (l > pd->acontent)
-    {
-      pd->content = realloc(pd->content, l + 256);
-      pd->acontent = l + 256;
-    }
-  c = pd->content + pd->lcontent;
-  pd->lcontent += len;
-  while (len-- > 0)
-    *c++ = *s++;
-  *c = 0;
-}
-
-#define BUFF_SIZE 8192
-
-
-/*
- * add single product to repo
- *
- */
-
-static void
-add_zyppdb_product(struct parsedata *pd, FILE *fp)
-{
-  char buf[BUFF_SIZE];
-  int l;
-
-  XML_Parser parser = XML_ParserCreate(NULL);
-  XML_SetUserData(parser, pd);
-  XML_SetElementHandler(parser, startElement, endElement);
-  XML_SetCharacterDataHandler(parser, characterData);
-
-  for (;;)
-    {
-      l = fread(buf, 1, sizeof(buf), fp);
-      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
-       {
-         pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
-         if (pd->solvable)
-           {
-             repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
-             pd->solvable = 0;
-           }
-         return;
-       }
-      if (l == 0)
-       break;
-    }
-  XML_ParserFree(parser);
-}
-
-
-/*
- * read all installed products
- *
- * parse each one as a product
- */
-
-int
-repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
-{
-  int i;
-  struct parsedata pd;
-  struct stateswitch *sw;
-  struct dirent *entry;
-  char *fullpath;
-  DIR *dir;
-  FILE *fp;
-  Repodata *data;
-
-  data = repo_add_repodata(repo, flags);
-  memset(&pd, 0, sizeof(pd));
-  pd.repo = repo;
-  pd.pool = repo->pool;
-  pd.data = data;
-
-  pd.content = malloc(256);
-  pd.acontent = 256;
-
-  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
-    {
-      if (!pd.swtab[sw->from])
-        pd.swtab[sw->from] = sw;
-      pd.sbtab[sw->to] = sw->from;
-    }
-
-  if (flags & REPO_USE_ROOTDIR)
-    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
-  dir = opendir(dirpath);
-  if (dir)
-    {
-      while ((entry = readdir(dir)))
-       {
-         if (strlen(entry->d_name) < 3)
-           continue;   /* skip '.' and '..' */
-         fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
-         if ((fp = fopen(fullpath, "r")) == 0)
-           {
-             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
-             continue;
-           }
-         add_zyppdb_product(&pd, fp);
-         fclose(fp);
-       }
-    }
-  closedir(dir);
-
-  free(pd.content);
-  join_freemem(&pd.jd);
-  if (flags & REPO_USE_ROOTDIR)
-    solv_free((char *)dirpath);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/ext/repo_zyppdb.h b/libsolv-0.6.15/ext/repo_zyppdb.h
deleted file mode 100644 (file)
index c3c7f39..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags);
diff --git a/libsolv-0.6.15/ext/solv_pgpvrfy.c b/libsolv-0.6.15/ext/solv_pgpvrfy.c
deleted file mode 100644 (file)
index 9bc256c..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Copyright (c) 2013, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/* simple and slow rsa/dsa verification code. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "util.h"
-#include "solv_pgpvrfy.h"
-
-typedef unsigned int mp_t;
-typedef unsigned long long mp2_t;
-#define MP_T_BYTES 4
-
-#define MP_T_BITS (MP_T_BYTES * 8)
-
-static inline void
-mpzero(int len, mp_t *target)
-{
-  memset(target, 0, MP_T_BYTES * len);
-}
-
-static inline mp_t *
-mpnew(int len)
-{
-  return solv_calloc(len, MP_T_BYTES);
-}
-
-static inline void
-mpcpy(int len, mp_t *target, mp_t *source)
-{
-  memcpy(target, source, len * MP_T_BYTES);
-}
-
-#if 0
-static void mpdump(int l, mp_t *a, char *s)
-{
-  int i;
-  if (s)
-    fprintf(stderr, "%s", s);
-  for (i = l - 1; i >= 0; i--)
-    fprintf(stderr, "%0*x", MP_T_BYTES * 2, a[i]);
-  fprintf(stderr, "\n");
-}
-#endif
-
-/* target[len] = x, target = target % mod
- * assumes that target < (mod << MP_T_BITS)! */
-static void
-mpdomod(int len, mp_t *target, mp2_t x, mp_t *mod)
-{
-  int i, j;
-  for (i = len - 1; i >= 0; i--)
-    {
-      x = (x << MP_T_BITS) | target[i];
-      target[i] = 0;
-      if (mod[i])
-       break;
-    }
-  if (i < 0)
-    return;
-  while (x >= 2 * (mp2_t)mod[i])
-    {
-      /* reduce */
-      mp2_t z = x / ((mp2_t)mod[i] + 1);
-      mp2_t n = 0;
-      if ((z >> MP_T_BITS) != 0)
-       z = (mp2_t)1 << MP_T_BITS;      /* just in case... */
-      for (j = 0; j < i; j++)
-       {
-         mp_t n2;
-         n += mod[j] * z;
-         n2 = (mp_t)n;
-         n >>= MP_T_BITS;
-         if (n2 > target[j])
-           n++;
-         target[j] -= n2;
-       }
-      n += mod[j] * z;
-      x -= n;
-    }
-  target[i] = x;
-  if (x >= mod[i])
-    {
-      mp_t n;
-      if (x == mod[i])
-       {
-         for (j = i - 1; j >= 0; j--)
-           if (target[j] < mod[j])
-             return;
-           else if (target[j] > mod[j])
-             break;
-       }
-      /* target >= mod, subtract mod */
-      n = 0;
-      for (j = 0; j <= i; j++)
-       {
-         mp2_t n2 = mod[j] + n;
-         n = n2 > target[j] ? 1 : 0;
-         target[j] -= (mp_t)n2;
-       }
-    }
-}
-
-/* target += src * m */
-static void
-mpmult_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod)
-{
-  int i;
-  mp2_t x = 0;
-  for (i = 0; i < len; i++)
-    {
-      x += src[i] * m + target[i];
-      target[i] = x;
-      x >>= MP_T_BITS;
-    }
-  mpdomod(len, target, x, mod);
-}
-
-/* target = target << MP_T_BITS */
-static void
-mpshift(int len, mp_t *target, mp_t *mod)
-{
-  mp_t x;
-  if (len <= 0)
-    return;
-  x = target[len - 1];
-  if (len > 1)
-    memmove(target + 1, target, (len - 1) * MP_T_BYTES);
-  target[0] = 0;
-  mpdomod(len, target, x, mod);
-}
-
-/* target += m1 * m2 */
-static void
-mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t *mod)
-{
-  int i, j;
-  for (j = m2len - 1; j >= 0; j--)
-    if (m2[j])
-      break;
-  if (j < 0)
-    return;
-  mpcpy(len, tmp, m1);
-  for (i = 0; i < j; i++)
-    {
-      if (m2[i])
-        mpmult_add_int(len, target, tmp, m2[i], mod);
-      mpshift(len, tmp, mod);
-    }
-  if (m2[i])
-    mpmult_add_int(len, target, tmp, m2[i], mod);
-}
-
-/* target = target * m */
-static void
-mpmult_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp1, mp_t *tmp2, mp_t *mod)
-{
-  mpzero(len, tmp1);
-  mpmult_add(len, tmp1, target, len, m, tmp2, mod);
-  mpcpy(len, target, tmp1);
-}
-
-/* target = target ^ 16 * b ^ e */
-static void
-mppow_int(int len, mp_t *target, mp_t *t, mp_t *mod, int e)
-{
-  mp_t *t2 = t + len * 16;
-  mpmult_inplace(len, target, target, t, t2, mod);
-  mpmult_inplace(len, target, target, t, t2, mod);
-  mpmult_inplace(len, target, target, t, t2, mod);
-  mpmult_inplace(len, target, target, t, t2, mod);
-  if (e)
-    mpmult_inplace(len, target, t + len * e, t, t2, mod);
-}
-
-/* target = b ^ e (b has to be < mod) */
-static void
-mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod)
-{
-  int i, j;
-  mp_t *t;
-  mpzero(len, target);
-  target[0] = 1;
-  for (i = elen - 1; i >= 0; i--)
-    if (e[i])
-      break;
-  if (i < 0)
-    return;
-  t = mpnew(len * 17);
-  mpcpy(len, t + len, b);
-  for (j = 2; j < 16; j++)
-    mpmult_add(len, t + len * j, b, len, t + len * j - len, t + len * 16, mod);
-  for (; i >= 0; i--)
-    {
-#if MP_T_BYTES == 4
-      mppow_int(len, target, t, mod, (e[i] >> 28) & 0x0f);
-      mppow_int(len, target, t, mod, (e[i] >> 24) & 0x0f);
-      mppow_int(len, target, t, mod, (e[i] >> 20) & 0x0f);
-      mppow_int(len, target, t, mod, (e[i] >> 16) & 0x0f);
-      mppow_int(len, target, t, mod, (e[i] >> 12) & 0x0f);
-      mppow_int(len, target, t, mod, (e[i] >>  8) & 0x0f);
-      mppow_int(len, target, t, mod, (e[i] >>  4) & 0x0f);
-      mppow_int(len, target, t, mod,  e[i]        & 0x0f);
-#elif MP_T_BYTES == 1
-      mppow_int(len, target, t, mod, (e[i] >>  4) & 0x0f);
-      mppow_int(len, target, t, mod,  e[i]        & 0x0f);
-#endif
-    }
-  free(t);
-}
-
-/* target = m1 * m2 (m1 has to be < mod) */
-static void
-mpmult(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod)
-{
-  mp_t *tmp = mpnew(len);
-  mpzero(len, target);
-  mpmult_add(len, target, m1, m2len, m2, tmp, mod);
-  free(tmp);
-}
-
-static int
-mpisless(int len, mp_t *a, mp_t *b)
-{
-  int i;
-  for (i = len - 1; i >= 0; i--)
-    if (a[i] < b[i])
-      return 1;
-    else if (a[i] > b[i])
-      return 0;
-  return 0;
-}
-
-static int
-mpiszero(int len, mp_t *a)
-{
-  int i;
-  for (i = 0; i < len; i++)
-    if (a[i])
-      return 0;
-  return 1;
-}
-
-static void
-mpdec(int len, mp_t *a)
-{
-  int i;
-  for (i = 0; i < len; i++)
-    if (a[i]--)
-      return;
-    else
-      a[i] = -(mp_t)1;
-}
-
-static int
-mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int hl, mp_t *h)
-{
-  mp_t *w;
-  mp_t *tmp;
-  mp_t *u1, *u2;
-  mp_t *gu1, *yu2;
-#if 0
-  mpdump(pl, p, "p = ");
-  mpdump(ql, q, "q = ");
-  mpdump(pl, g, "g = ");
-  mpdump(pl, y, "y = ");
-  mpdump(ql, r, "r = ");
-  mpdump(ql, s, "s = ");
-  mpdump(hl, h, "h = ");
-#endif
-  if (pl < ql || !mpisless(pl, g, p) || !mpisless(pl, y, p))
-    return 0;                          /* hmm, bad pubkey? */
-  if (!mpisless(ql, r, q) || mpiszero(ql, r))
-    return 0;
-  if (!mpisless(ql, s, q) || mpiszero(ql, s))
-    return 0;
-  tmp = mpnew(pl);                     /* note pl */
-  mpcpy(ql, tmp, q);                   /* tmp = q */
-  mpdec(ql, tmp);                      /* tmp-- */
-  mpdec(ql, tmp);                      /* tmp-- */
-  w = mpnew(ql);
-  mppow(ql, w, s, ql, tmp, q);         /* w = s ^ tmp (s ^ -1) */
-  u1 = mpnew(pl);                      /* note pl */
-  /* order is important here: h can be >= q */
-  mpmult(ql, u1, w, hl, h, q);         /* u1 = w * h */
-  u2 = mpnew(ql);                      /* u2 = 0 */
-  mpmult(ql, u2, w, ql, r, q);         /* u2 = w * r */
-  free(w);
-  gu1 = mpnew(pl);
-  yu2 = mpnew(pl);
-  mppow(pl, gu1, g, ql, u1, p);                /* gu1 = g ^ u1 */
-  mppow(pl, yu2, y, ql, u2, p);                /* yu2 = y ^ u2 */
-  mpmult(pl, u1, gu1, pl, yu2, p);     /* u1 = gu1 * yu2 */
-  free(gu1);
-  free(yu2);
-  mpzero(ql, u2);
-  u2[0] = 1;                           /* u2 = 1 */
-  mpmult(ql, tmp, u2, pl, u1, q);      /* tmp = u2 * u1 */
-  free(u1);
-  free(u2);
-#if 0
-  mpdump(ql, tmp, "res = ");
-#endif
-  if (memcmp(tmp, r, ql * MP_T_BYTES) != 0)
-    {
-      free(tmp);
-      return 0;
-    }
-  free(tmp);
-  return 1;
-}
-
-static int
-mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c)
-{
-  mp_t *tmp;
-#if 0
-  mpdump(nl, n, "n = ");
-  mpdump(el, e, "e = ");
-  mpdump(nl, m, "m = ");
-  mpdump(nl, c, "c = ");
-#endif
-  if (!mpisless(nl, m, n))
-    return 0;
-  if (!mpisless(nl, c, n))
-    return 0;
-  tmp = mpnew(nl);
-  mppow(nl, tmp, m, el, e, n);         /* tmp = m ^ e */
-#if 0
-  mpdump(nl, tmp, "res = ");
-#endif
-  if (memcmp(tmp, c, nl * MP_T_BYTES) != 0)
-    {
-      free(tmp);
-      return 0;
-    }
-  free(tmp);
-  return 1;
-}
-
-/* create mp with size tbits from data with size dbits */
-static mp_t *
-mpbuild(const unsigned char *d, int dbits, int tbits, int *mplp)
-{
-  int l = (tbits + MP_T_BITS - 1) / MP_T_BITS;
-  int dl, i;
-
-  mp_t *out = mpnew(l ? l : 1);
-  if (mplp)
-    *mplp = l;
-  dl = (dbits + 7) / 8;
-  d += dl;
-  if (dbits > tbits)
-    dl = (tbits + 7) / 8;
-  for (i = 0; dl > 0; dl--, i++)
-    {
-      int x = *--d;
-      out[i / MP_T_BYTES] |= x << (8 * (i % MP_T_BYTES));
-    }
-  return out;
-}
-
-static const unsigned char *
-findmpi(const unsigned char **mpip, int *mpilp, int maxbits, int *outlen)
-{
-  int mpil = *mpilp;
-  const unsigned char *mpi = *mpip;
-  int bits, l;
-
-  *outlen = 0;
-  if (mpil < 2)
-    return 0;
-  bits = mpi[0] << 8 | mpi[1];
-  l = 2 + (bits + 7) / 8;
-  if (bits > maxbits || mpil < l || (bits && !mpi[2]))
-    {
-      *mpilp = 0;
-      return 0;
-    }
-  *outlen = bits;
-  *mpilp = mpil - l;
-  *mpip = mpi + l;
-  return mpi + 2;
-}
-
-int
-solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int sigl)
-{
-  int hashl;
-  unsigned char *oid = 0;
-  const unsigned char *mpi;
-  int mpil;
-  int res = 0;
-
-  if (!pub || !sig || publ < 1 || sigl < 2)
-    return 0;
-  if (pub[0] != sig[0])
-    return 0;          /* key algo mismatch */
-  switch(sig[1])
-    {
-    case 1:
-      hashl = 16;      /* MD5 */
-      oid = (unsigned char *)"\022\060\040\060\014\006\010\052\206\110\206\367\015\002\005\005\000\004\020";
-      break;
-    case 2:
-      hashl = 20;      /* SHA-1 */
-      oid = (unsigned char *)"\017\060\041\060\011\006\005\053\016\003\002\032\005\000\004\024";
-      break;
-    case 8:
-      hashl = 32;      /* SHA-256 */
-      oid = (unsigned char *)"\023\060\061\060\015\006\011\140\206\110\001\145\003\004\002\001\005\000\004\040";
-      break;
-    case 9:
-      hashl = 48;      /* SHA-384 */
-      oid = (unsigned char *)"\023\060\101\060\015\006\011\140\206\110\001\145\003\004\002\002\005\000\004\060";
-      break;
-    case 10:
-      hashl = 64;      /* SHA-512 */
-      oid = (unsigned char *)"\023\060\121\060\015\006\011\140\206\110\001\145\003\004\002\003\005\000\004\100";
-      break;
-    case 11:
-      hashl = 28;      /* SHA-224 */
-      oid = (unsigned char *)"\023\060\061\060\015\006\011\140\206\110\001\145\003\004\002\004\005\000\004\034";
-      break;
-    default:
-      return 0;                /* unsupported hash algo */
-    }
-  if (sigl < 2 + hashl)
-    return 0;
-  switch (pub[0])
-    {
-    case 1:            /* RSA */
-      {
-       const unsigned char *n, *e, *m;
-       unsigned char *c;
-       int nlen, elen, mlen, clen;
-       mp_t *nx, *ex, *mx, *cx;
-       int nxl, exl;
-
-        mpi = pub + 1;
-        mpil = publ - 1;
-       n = findmpi(&mpi, &mpil, 8192, &nlen);
-       e = findmpi(&mpi, &mpil, 1024, &elen);
-        mpi = sig + 2 + hashl;
-        mpil = sigl - (2 + hashl);
-       m = findmpi(&mpi, &mpil, nlen, &mlen);
-        if (!n || !e || !m || !nlen || !elen)
-         return 0;
-       /* build padding block */
-       clen = (nlen - 1) / 8;
-       if (hashl + *oid + 2 > clen)
-         return 0;
-       c = solv_malloc(clen);
-       memset(c, 0xff, clen);
-       c[0] = 1;
-       memcpy(c + clen - hashl, sig + 2, hashl);
-       memcpy(c + clen - hashl - *oid, oid + 1, *oid);
-       c[clen - hashl - *oid - 1] = 0;
-       clen = clen * 8 - 7;    /* always <= nlen */
-       nx = mpbuild(n, nlen, nlen, &nxl);
-       ex = mpbuild(e, elen, elen, &exl);
-       mx = mpbuild(m, mlen, nlen, 0);
-       cx = mpbuild(c, clen, nlen, 0);
-       free(c);
-       res = mprsa(nxl, nx, exl, ex, mx, cx);
-       free(nx);
-       free(ex);
-       free(mx);
-       free(cx);
-       break;
-      }
-    case 17:           /* DSA */
-      {
-       const unsigned char *p, *q, *g, *y, *r, *s;
-       int plen, qlen, glen, ylen, rlen, slen, hlen;
-       mp_t *px, *qx, *gx, *yx, *rx, *sx, *hx;
-       int pxl, qxl, hxl;
-
-        mpi = pub + 1;
-        mpil = publ - 1;
-       p = findmpi(&mpi, &mpil, 8192, &plen);
-       q = findmpi(&mpi, &mpil, 1024, &qlen);
-       g = findmpi(&mpi, &mpil, plen, &glen);
-       y = findmpi(&mpi, &mpil, plen, &ylen);
-        mpi = sig + 2 + hashl;
-        mpil = sigl - (2 + hashl);
-       r = findmpi(&mpi, &mpil, qlen, &rlen);
-       s = findmpi(&mpi, &mpil, qlen, &slen);
-        if (!p || !q || !g || !y || !r || !s || !plen || !qlen)
-         return 0;
-       hlen = (qlen + 7) & ~7;
-       if (hlen > hashl * 8)
-         return 0;
-       px = mpbuild(p, plen, plen, &pxl);
-       qx = mpbuild(q, qlen, qlen, &qxl);
-       gx = mpbuild(g, glen, plen, 0);
-       yx = mpbuild(y, ylen, plen, 0);
-       rx = mpbuild(r, rlen, qlen, 0);
-       sx = mpbuild(s, slen, qlen, 0);
-       hx = mpbuild(sig + 2, hlen, hlen, &hxl);
-        res = mpdsa(pxl, px, qxl, qx, gx, yx, rx, sx, hxl, hx);
-       free(px);
-       free(qx);
-       free(gx);
-       free(yx);
-       free(rx);
-       free(sx);
-       free(hx);
-       break;
-      }
-    default:
-      return 0;                /* unsupported pubkey algo */
-    }
-  return res;
-}
-
diff --git a/libsolv-0.6.15/ext/solv_pgpvrfy.h b/libsolv-0.6.15/ext/solv_pgpvrfy.h
deleted file mode 100644 (file)
index a623e85..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (c) 2013, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-extern int solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int sigl);
-
diff --git a/libsolv-0.6.15/ext/solv_xfopen.c b/libsolv-0.6.15/ext/solv_xfopen.c
deleted file mode 100644 (file)
index b0421bf..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * Copyright (c) 2011, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-#include <fcntl.h>
-
-#include "solv_xfopen.h"
-#include "util.h"
-
-
-/* Evil hack for Haiku: fopencookie() is implemented internally, but not
-   exported by a header. */
-#ifdef __HAIKU__
-
-typedef struct {
-       ssize_t (*read)(void*, char*, size_t);
-       ssize_t (*write)(void*, const char*, size_t);
-       int (*seek)(off_t*, int);
-       int (*close)(void*);
-} cookie_io_functions_t;
-
-
-FILE *fopencookie(void*, const char*, cookie_io_functions_t);
-
-#endif /* __HAIKU__ */
-
-
-static FILE *cookieopen(void *cookie, const char *mode,
-       ssize_t (*cread)(void *, char *, size_t),
-       ssize_t (*cwrite)(void *, const char *, size_t),
-       int (*cclose)(void *))
-{
-#ifdef HAVE_FUNOPEN
-  if (!cookie)
-    return 0;
-  return funopen(cookie,
-      (int (*)(void *, char *, int))(*mode == 'r' ? cread : NULL),             /* readfn */
-      (int (*)(void *, const char *, int))(*mode == 'w' ? cwrite : NULL),      /* writefn */
-      (fpos_t (*)(void *, fpos_t, int))NULL,                                   /* seekfn */
-      cclose
-      );
-#elif defined(HAVE_FOPENCOOKIE)
-  cookie_io_functions_t cio;
-
-  if (!cookie)
-    return 0;
-  memset(&cio, 0, sizeof(cio));
-  if (*mode == 'r')
-    cio.read = cread;
-  else if (*mode == 'w')
-    cio.write = cwrite;
-  cio.close = cclose;
-  return  fopencookie(cookie, *mode == 'w' ? "w" : "r", cio);
-#else
-# error Need to implement custom I/O
-#endif
-}
-
-
-/* gzip compression */
-
-static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
-{
-  return gzread((gzFile)cookie, buf, nbytes);
-}
-
-static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
-{
-  return gzwrite((gzFile)cookie, buf, nbytes);
-}
-
-static int cookie_gzclose(void *cookie)
-{
-  return gzclose((gzFile)cookie);
-}
-
-static inline FILE *mygzfopen(const char *fn, const char *mode)
-{
-  gzFile gzf = gzopen(fn, mode);
-  return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
-}
-
-static inline FILE *mygzfdopen(int fd, const char *mode)
-{
-  gzFile gzf = gzdopen(fd, mode);
-  return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
-}
-
-#ifdef ENABLE_BZIP2_COMPRESSION
-
-#include <bzlib.h>
-
-/* bzip2 compression */
-
-static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
-{
-  return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
-}
-
-static ssize_t cookie_bzwrite(void *cookie, const char *buf, size_t nbytes)
-{
-  return BZ2_bzwrite((BZFILE *)cookie, (char *)buf, nbytes);
-}
-
-static int cookie_bzclose(void *cookie)
-{
-  BZ2_bzclose((BZFILE *)cookie);
-  return 0;
-}
-
-static inline FILE *mybzfopen(const char *fn, const char *mode)
-{
-  BZFILE *bzf = BZ2_bzopen(fn, mode);
-  return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
-}
-
-static inline FILE *mybzfdopen(int fd, const char *mode)
-{
-  BZFILE *bzf = BZ2_bzdopen(fd, mode);
-  return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
-}
-
-#endif
-
-
-#ifdef ENABLE_LZMA_COMPRESSION
-
-#include <lzma.h>
-
-/* lzma code written by me in 2008 for rpm's rpmio.c */
-
-typedef struct lzfile {
-  unsigned char buf[1 << 15];
-  lzma_stream strm;
-  FILE *file;
-  int encoding;
-  int eof;
-} LZFILE;
-
-static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
-{
-  lzma_options_lzma options;
-  lzma_lzma_preset(&options, level);
-  return lzma_alone_encoder(strm, &options);
-}
-
-static lzma_stream stream_init = LZMA_STREAM_INIT;
-
-static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
-{
-  int level = 7;
-  int encoding = 0;
-  FILE *fp;
-  LZFILE *lzfile;
-  lzma_ret ret;
-
-  if (!path && fd < 0)
-    return 0;
-  for (; *mode; mode++)
-    {
-      if (*mode == 'w')
-       encoding = 1;
-      else if (*mode == 'r')
-       encoding = 0;
-      else if (*mode >= '1' && *mode <= '9')
-       level = *mode - '0';
-    }
-  if (fd != -1)
-    fp = fdopen(fd, encoding ? "w" : "r");
-  else
-    fp = fopen(path, encoding ? "w" : "r");
-  if (!fp)
-    return 0;
-  lzfile = calloc(1, sizeof(*lzfile));
-  if (!lzfile)
-    {
-      fclose(fp);
-      return 0;
-    }
-  lzfile->file = fp;
-  lzfile->encoding = encoding;
-  lzfile->eof = 0;
-  lzfile->strm = stream_init;
-  if (encoding)
-    {
-      if (isxz)
-       ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
-      else
-       ret = setup_alone_encoder(&lzfile->strm, level);
-    }
-  else
-    ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
-  if (ret != LZMA_OK)
-    {
-      fclose(fp);
-      free(lzfile);
-      return 0;
-    }
-  return lzfile;
-}
-
-static int lzclose(void *cookie)
-{
-  LZFILE *lzfile = cookie;
-  lzma_ret ret;
-  size_t n;
-  int rc;
-
-  if (!lzfile)
-    return -1;
-  if (lzfile->encoding)
-    {
-      for (;;)
-       {
-         lzfile->strm.avail_out = sizeof(lzfile->buf);
-         lzfile->strm.next_out = lzfile->buf;
-         ret = lzma_code(&lzfile->strm, LZMA_FINISH);
-         if (ret != LZMA_OK && ret != LZMA_STREAM_END)
-           return -1;
-         n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
-         if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
-           return -1;
-         if (ret == LZMA_STREAM_END)
-           break;
-       }
-    }
-  lzma_end(&lzfile->strm);
-  rc = fclose(lzfile->file);
-  free(lzfile);
-  return rc;
-}
-
-static ssize_t lzread(void *cookie, char *buf, size_t len)
-{
-  LZFILE *lzfile = cookie;
-  lzma_ret ret;
-  int eof = 0;
-
-  if (!lzfile || lzfile->encoding)
-    return -1;
-  if (lzfile->eof)
-    return 0;
-  lzfile->strm.next_out = (unsigned char *)buf;
-  lzfile->strm.avail_out = len;
-  for (;;)
-    {
-      if (!lzfile->strm.avail_in)
-       {
-         lzfile->strm.next_in = lzfile->buf;
-         lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
-         if (!lzfile->strm.avail_in)
-           eof = 1;
-       }
-      ret = lzma_code(&lzfile->strm, LZMA_RUN);
-      if (ret == LZMA_STREAM_END)
-       {
-         lzfile->eof = 1;
-         return len - lzfile->strm.avail_out;
-       }
-      if (ret != LZMA_OK)
-       return -1;
-      if (!lzfile->strm.avail_out)
-       return len;
-      if (eof)
-       return -1;
-    }
-}
-
-static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
-{
-  LZFILE *lzfile = cookie;
-  lzma_ret ret;
-  size_t n;
-  if (!lzfile || !lzfile->encoding)
-    return -1;
-  if (!len)
-    return 0;
-  lzfile->strm.next_in = (unsigned char *)buf;
-  lzfile->strm.avail_in = len;
-  for (;;)
-    {
-      lzfile->strm.next_out = lzfile->buf;
-      lzfile->strm.avail_out = sizeof(lzfile->buf);
-      ret = lzma_code(&lzfile->strm, LZMA_RUN);
-      if (ret != LZMA_OK)
-       return -1;
-      n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
-      if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
-       return -1;
-      if (!lzfile->strm.avail_in)
-       return len;
-    }
-}
-
-static inline FILE *myxzfopen(const char *fn, const char *mode)
-{
-  LZFILE *lzf = lzopen(fn, mode, -1, 1);
-  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
-}
-
-static inline FILE *myxzfdopen(int fd, const char *mode)
-{
-  LZFILE *lzf = lzopen(0, mode, fd, 1);
-  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
-}
-
-static inline FILE *mylzfopen(const char *fn, const char *mode)
-{
-  LZFILE *lzf = lzopen(fn, mode, -1, 0);
-  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
-}
-
-static inline FILE *mylzfdopen(int fd, const char *mode)
-{
-  LZFILE *lzf = lzopen(0, mode, fd, 0);
-  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
-}
-
-#endif /* ENABLE_LZMA_COMPRESSION */
-
-
-FILE *
-solv_xfopen(const char *fn, const char *mode)
-{
-  char *suf;
-
-  if (!fn)
-    return 0;
-  if (!mode)
-    mode = "r";
-  suf = strrchr(fn, '.');
-  if (suf && !strcmp(suf, ".gz"))
-    return mygzfopen(fn, mode);
-#ifdef ENABLE_LZMA_COMPRESSION
-  if (suf && !strcmp(suf, ".xz"))
-    return myxzfopen(fn, mode);
-  if (suf && !strcmp(suf, ".lzma"))
-    return mylzfopen(fn, mode);
-#else
-  if (suf && !strcmp(suf, ".xz"))
-    return 0;
-  if (suf && !strcmp(suf, ".lzma"))
-    return 0;
-#endif
-#ifdef ENABLE_BZIP2_COMPRESSION
-  if (suf && !strcmp(suf, ".bz2"))
-    return mybzfopen(fn, mode);
-#else
-  if (suf && !strcmp(suf, ".bz2"))
-    return 0;
-#endif
-  return fopen(fn, mode);
-}
-
-FILE *
-solv_xfopen_fd(const char *fn, int fd, const char *mode)
-{
-  const char *simplemode = mode;
-  char *suf;
-
-  suf = fn ? strrchr(fn, '.') : 0;
-  if (!mode)
-    {
-      int fl = fcntl(fd, F_GETFL, 0);
-      if (fl == -1)
-       return 0;
-      fl &= O_RDONLY|O_WRONLY|O_RDWR;
-      if (fl == O_WRONLY)
-       mode = simplemode = "w";
-      else if (fl == O_RDWR)
-       {
-         mode = "r+";
-         simplemode = "r";
-       }
-      else
-       mode = simplemode = "r";
-    }
-  if (suf && !strcmp(suf, ".gz"))
-    return mygzfdopen(fd, simplemode);
-#ifdef ENABLE_LZMA_COMPRESSION
-  if (suf && !strcmp(suf, ".xz"))
-    return myxzfdopen(fd, simplemode);
-  if (suf && !strcmp(suf, ".lzma"))
-    return mylzfdopen(fd, simplemode);
-#else
-  if (suf && !strcmp(suf, ".xz"))
-    return 0;
-  if (suf && !strcmp(suf, ".lzma"))
-    return 0;
-#endif
-#ifdef ENABLE_BZIP2_COMPRESSION
-  if (suf && !strcmp(suf, ".bz2"))
-    return mybzfdopen(fd, simplemode);
-#else
-  if (suf && !strcmp(suf, ".bz2"))
-    return 0;
-#endif
-  return fdopen(fd, mode);
-}
-
-int
-solv_xfopen_iscompressed(const char *fn)
-{
-  const char *suf = fn ? strrchr(fn, '.') : 0;
-  if (!suf)
-    return 0;
-  if (!strcmp(suf, ".gz"))
-    return 1;
-  if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma"))
-#ifdef ENABLE_LZMA_COMPRESSION
-    return 1;
-#else
-    return -1;
-#endif
-  if (!strcmp(suf, ".bz2"))
-#ifdef ENABLE_BZIP2_COMPRESSION
-    return 1;
-#else
-    return -1;
-#endif
-  return 0;
-}
-
-struct bufcookie {
-  char **bufp;
-  size_t *buflp;
-  char *freemem;
-  size_t bufl_int;
-};
-
-static ssize_t cookie_bufread(void *cookie, char *buf, size_t nbytes)
-{
-  struct bufcookie *bc = cookie;
-  size_t n = *bc->buflp > nbytes ? nbytes : *bc->buflp;
-  if (n)
-    {
-      memcpy(buf, *bc->bufp, n);
-      *bc->bufp += n;
-      *bc->buflp -= n;
-    }
-  return n;
-}
-
-static ssize_t cookie_bufwrite(void *cookie, const char *buf, size_t nbytes)
-{
-  struct bufcookie *bc = cookie;
-  int n = nbytes > 0x40000000 ? 0x40000000 : nbytes;
-  if (n)
-    {
-      *bc->bufp = solv_extend(*bc->bufp, *bc->buflp, n + 1, 1, 4095);
-      memcpy(*bc->bufp, buf, n);
-      (*bc->bufp)[n] = 0;      /* zero-terminate */
-      *bc->buflp += n;
-    }
-  return n;
-}
-
-static int cookie_bufclose(void *cookie)
-{
-  struct bufcookie *bc = cookie;
-  if (bc->freemem)
-    solv_free(bc->freemem);
-  solv_free(bc);
-  return 0;
-}
-
-FILE *
-solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode)
-{
-  struct bufcookie *bc;
-  FILE *fp;
-  if (*mode != 'r' && *mode != 'w')
-    return 0;
-  bc = solv_calloc(1, sizeof(*bc));
-  bc->freemem = 0;
-  bc->bufp = bufp;
-  if (!buflp)
-    {
-      bc->bufl_int = *mode == 'w' ? 0 : strlen(*bufp);
-      buflp = &bc->bufl_int;
-    }
-  bc->buflp = buflp;
-  if (*mode == 'w')
-    {
-      *bc->bufp = solv_extend(0, 0, 1, 1, 4095);       /* always zero-terminate */
-      (*bc->bufp)[0] = 0;
-      *bc->buflp = 0;
-    }
-  fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose);
-  if (!strcmp(mode, "rf"))     /* auto-free */
-    bc->freemem = *bufp;
-  if (!fp)
-    {
-      if (*mode == 'w')
-       *bc->bufp = solv_free(*bc->bufp);
-      cookie_bufclose(bc);
-    }
-  return fp;
-}
diff --git a/libsolv-0.6.15/ext/solv_xfopen.h b/libsolv-0.6.15/ext/solv_xfopen.h
deleted file mode 100644 (file)
index aa8740e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2009-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef SOLV_XFOPEN_H
-#define SOLV_XFOPEN_H
-
-extern FILE *solv_xfopen(const char *fn, const char *mode);
-extern FILE *solv_xfopen_fd(const char *fn, int fd, const char *mode);
-extern FILE *solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode);
-extern int   solv_xfopen_iscompressed(const char *fn);
-
-#endif
diff --git a/libsolv-0.6.15/ext/testcase.c b/libsolv-0.6.15/ext/testcase.c
deleted file mode 100644 (file)
index b9fddef..0000000
+++ /dev/null
@@ -1,2773 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "poolarch.h"
-#include "poolvendor.h"
-#include "repo.h"
-#include "repo_solv.h"
-#include "solver.h"
-#include "solverdebug.h"
-#include "chksum.h"
-#include "testcase.h"
-#include "selection.h"
-#include "solv_xfopen.h"
-
-#define DISABLE_JOIN2
-#include "tools_util.h"
-
-static struct job2str {
-  Id job;
-  const char *str;
-} job2str[] = {
-  { SOLVER_NOOP,           "noop" },
-  { SOLVER_INSTALL,        "install" },
-  { SOLVER_ERASE,          "erase" },
-  { SOLVER_UPDATE,         "update" },
-  { SOLVER_WEAKENDEPS,     "weakendeps" },
-  { SOLVER_MULTIVERSION,   "multiversion" },
-  { SOLVER_MULTIVERSION,   "noobsoletes" },    /* old name */
-  { SOLVER_LOCK,           "lock" },
-  { SOLVER_DISTUPGRADE,    "distupgrade" },
-  { SOLVER_VERIFY,         "verify" },
-  { SOLVER_DROP_ORPHANED,  "droporphaned" },
-  { SOLVER_USERINSTALLED,  "userinstalled" },
-  { SOLVER_ALLOWUNINSTALL, "allowuninstall" },
-  { 0, 0 }
-};
-
-static struct jobflags2str {
-  Id flag;
-  const char *str;
-} jobflags2str[] = {
-  { SOLVER_WEAK,      "weak" },
-  { SOLVER_ESSENTIAL, "essential" },
-  { SOLVER_CLEANDEPS, "cleandeps" },
-  { SOLVER_ORUPDATE,  "orupdate" },
-  { SOLVER_FORCEBEST, "forcebest" },
-  { SOLVER_TARGETED,  "targeted" },
-  { SOLVER_NOTBYUSER, "notbyuser" },
-  { SOLVER_SETEV,     "setev" },
-  { SOLVER_SETEVR,    "setevr" },
-  { SOLVER_SETARCH,   "setarch" },
-  { SOLVER_SETVENDOR, "setvendor" },
-  { SOLVER_SETREPO,   "setrepo" },
-  { SOLVER_NOAUTOSET, "noautoset" },
-  { 0, 0 }
-};
-
-static struct resultflags2str {
-  Id flag;
-  const char *str;
-} resultflags2str[] = {
-  { TESTCASE_RESULT_TRANSACTION,       "transaction" },
-  { TESTCASE_RESULT_PROBLEMS,          "problems" },
-  { TESTCASE_RESULT_ORPHANED,          "orphaned" },
-  { TESTCASE_RESULT_RECOMMENDED,       "recommended" },
-  { TESTCASE_RESULT_UNNEEDED,          "unneeded" },
-  { TESTCASE_RESULT_ALTERNATIVES,      "alternatives" },
-  { TESTCASE_RESULT_RULES,             "rules" },
-  { TESTCASE_RESULT_GENID,             "genid" },
-  { 0, 0 }
-};
-
-static struct solverflags2str {
-  Id flag;
-  const char *str;
-  int def;
-} solverflags2str[] = {
-  { SOLVER_FLAG_ALLOW_DOWNGRADE,            "allowdowngrade", 0 },
-  { SOLVER_FLAG_ALLOW_NAMECHANGE,           "allownamechange", 1 },
-  { SOLVER_FLAG_ALLOW_ARCHCHANGE,           "allowarchchange", 0 },
-  { SOLVER_FLAG_ALLOW_VENDORCHANGE,         "allowvendorchange", 0 },
-  { SOLVER_FLAG_ALLOW_UNINSTALL,            "allowuninstall", 0 },
-  { SOLVER_FLAG_NO_UPDATEPROVIDE,           "noupdateprovide", 0 },
-  { SOLVER_FLAG_SPLITPROVIDES,              "splitprovides", 0 },
-  { SOLVER_FLAG_IGNORE_RECOMMENDED,         "ignorerecommended", 0 },
-  { SOLVER_FLAG_ADD_ALREADY_RECOMMENDED,    "addalreadyrecommended", 0 },
-  { SOLVER_FLAG_NO_INFARCHCHECK,            "noinfarchcheck", 0 },
-  { SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES,    "keepexplicitobsoletes", 0 },
-  { SOLVER_FLAG_BEST_OBEY_POLICY,           "bestobeypolicy", 0 },
-  { SOLVER_FLAG_NO_AUTOTARGET,              "noautotarget", 0 },
-  { SOLVER_FLAG_DUP_ALLOW_DOWNGRADE,        "dupallowdowngrade", 1 },
-  { SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE,       "dupallowarchchange", 1 },
-  { SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE,     "dupallowvendorchange", 1 },
-  { SOLVER_FLAG_DUP_ALLOW_NAMECHANGE,       "dupallownamechange", 1 },
-  { SOLVER_FLAG_KEEP_ORPHANS,               "keeporphans", 0 },
-  { SOLVER_FLAG_BREAK_ORPHANS,              "breakorphans", 0 },
-  { SOLVER_FLAG_FOCUS_INSTALLED,            "focusinstalled", 0 },
-  { SOLVER_FLAG_YUM_OBSOLETES,              "yumobsoletes", 0 },
-  { SOLVER_FLAG_NEED_UPDATEPROVIDE,         "needupdateprovide", 0 },
-  { 0, 0, 0 }
-};
-
-static struct poolflags2str {
-  Id flag;
-  const char *str;
-  int def;
-} poolflags2str[] = {
-  { POOL_FLAG_PROMOTEEPOCH,                 "promoteepoch", 0 },
-  { POOL_FLAG_FORBIDSELFCONFLICTS,          "forbidselfconflicts", 0 },
-  { POOL_FLAG_OBSOLETEUSESPROVIDES,         "obsoleteusesprovides", 0 },
-  { POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES, "implicitobsoleteusesprovides", 0 },
-  { POOL_FLAG_OBSOLETEUSESCOLORS,           "obsoleteusescolors", 0 },
-  { POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS,   "implicitobsoleteusescolors", 0 },
-  { POOL_FLAG_NOINSTALLEDOBSOLETES,         "noinstalledobsoletes", 0 },
-  { POOL_FLAG_HAVEDISTEPOCH,                "havedistepoch", 0 },
-  { POOL_FLAG_NOOBSOLETESMULTIVERSION,      "noobsoletesmultiversion", 0 },
-  { POOL_FLAG_ADDFILEPROVIDESFILTERED,      "addfileprovidesfiltered", 0 },
-  { POOL_FLAG_NOWHATPROVIDESAUX,            "nowhatprovidesaux", 0 },
-  { 0, 0, 0 }
-};
-
-static struct disttype2str {
-  Id type;
-  const char *str;
-} disttype2str[] = {
-  { DISTTYPE_RPM,  "rpm" },
-  { DISTTYPE_DEB,  "deb" },
-  { DISTTYPE_ARCH, "arch" },
-  { DISTTYPE_HAIKU, "haiku" },
-  { 0, 0 }
-};
-
-static struct selflags2str {
-  Id flag;
-  const char *str;
-} selflags2str[] = {
-  { SELECTION_NAME, "name" },
-  { SELECTION_PROVIDES, "provides" },
-  { SELECTION_FILELIST, "filelist" },
-  { SELECTION_CANON, "canon" },
-  { SELECTION_DOTARCH, "dotarch" },
-  { SELECTION_REL, "rel" },
-  { SELECTION_INSTALLED_ONLY, "installedonly" },
-  { SELECTION_GLOB, "glob" },
-  { SELECTION_FLAT, "flat" },
-  { SELECTION_NOCASE, "nocase" },
-  { SELECTION_SOURCE_ONLY, "sourceonly" },
-  { SELECTION_WITH_SOURCE, "withsource" },
-  { 0, 0 }
-};
-
-static const char *features[] = {
-#ifdef ENABLE_LINKED_PKGS
-  "linked_packages",
-#endif
-#ifdef ENABLE_COMPLEX_DEPS
-  "complex_deps",
-#endif
-  0
-};
-
-typedef struct strqueue {
-  char **str;
-  int nstr;
-} Strqueue;
-
-#define STRQUEUE_BLOCK 63
-
-static void
-strqueue_init(Strqueue *q)
-{
-  q->str = 0;
-  q->nstr = 0;
-}
-
-static void
-strqueue_free(Strqueue *q)
-{
-  int i;
-  for (i = 0; i < q->nstr; i++)
-    solv_free(q->str[i]);
-  q->str = solv_free(q->str);
-  q->nstr = 0;
-}
-
-static void
-strqueue_push(Strqueue *q, const char *s)
-{
-  q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK);
-  q->str[q->nstr++] = solv_strdup(s);
-}
-
-static void
-strqueue_pushjoin(Strqueue *q, const char *s1, const char *s2, const char *s3)
-{
-  q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK);
-  q->str[q->nstr++] = solv_dupjoin(s1, s2, s3);
-}
-
-static int
-strqueue_sort_cmp(const void *ap, const void *bp, void *dp)
-{
-  const char *a = *(const char **)ap;
-  const char *b = *(const char **)bp;
-  return strcmp(a ? a : "", b ? b : "");
-}
-
-static void
-strqueue_sort(Strqueue *q)
-{
-  if (q->nstr > 1)
-    solv_sort(q->str, q->nstr, sizeof(*q->str), strqueue_sort_cmp, 0);
-}
-
-static void
-strqueue_sort_u(Strqueue *q)
-{
-  int i, j;
-  strqueue_sort(q);
-  for (i = j = 0; i < q->nstr; i++)
-    if (!j || strqueue_sort_cmp(q->str + i, q->str + j - 1, 0) != 0)
-      q->str[j++] = q->str[i];
-  q->nstr = j;
-}
-
-static char *
-strqueue_join(Strqueue *q)
-{
-  int i, l = 0;
-  char *r, *rp;
-  for (i = 0; i < q->nstr; i++)
-    if (q->str[i])
-      l += strlen(q->str[i]) + 1;
-  l++; /* trailing \0 */
-  r = solv_malloc(l);
-  rp = r;
-  for (i = 0; i < q->nstr; i++)
-    if (q->str[i])
-      {
-        strcpy(rp, q->str[i]);
-        rp += strlen(rp);
-       *rp++ = '\n';
-      }
-  *rp = 0;
-  return r;
-}
-
-static void
-strqueue_split(Strqueue *q, const char *s)
-{
-  const char *p;
-  if (!s)
-    return;
-  while ((p = strchr(s, '\n')) != 0)
-    {
-      q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK);
-      q->str[q->nstr] = solv_malloc(p - s + 1);
-      if (p > s)
-       memcpy(q->str[q->nstr], s, p - s);
-      q->str[q->nstr][p - s] = 0;
-      q->nstr++;
-      s = p + 1;
-    }
-  if (*s)
-    strqueue_push(q, s);
-}
-
-static void
-strqueue_diff(Strqueue *sq1, Strqueue *sq2, Strqueue *osq)
-{
-  int i = 0, j = 0;
-  while (i < sq1->nstr && j < sq2->nstr)
-    {
-      int r = strqueue_sort_cmp(sq1->str + i, sq2->str + j, 0);
-      if (!r)
-       i++, j++;
-      else if (r < 0)
-       strqueue_pushjoin(osq, "-", sq1->str[i++], 0);
-      else
-       strqueue_pushjoin(osq, "+", sq2->str[j++], 0);
-    }
-  while (i < sq1->nstr)
-    strqueue_pushjoin(osq, "-", sq1->str[i++], 0);
-  while (j < sq2->nstr)
-    strqueue_pushjoin(osq, "+", sq2->str[j++], 0);
-}
-
-
-static const char *
-testcase_id2str(Pool *pool, Id id, int isname)
-{
-  const char *s = pool_id2str(pool, id);
-  const char *ss;
-  char *s2, *s2p;
-  int bad = 0, paren = 0, parenbad = 0;
-
-  if (id == 0)
-    return "<NULL>";
-  if (id == 1)
-    return "\\00";
-  if (strchr("[(<=>!", *s))
-    bad++;
-  if (!strncmp(s, "namespace:", 10))
-    bad++;
-  for (ss = s + bad; *ss; ss++)
-    {
-      if (*ss == ' ' || *ss == '\\' || *(unsigned char *)ss < 32 || *ss == '(' || *ss == ')')
-        bad++;
-      if (*ss == '(')
-       paren = paren == 0 ? 1 : -1;
-      else if (*ss == ')')
-       {
-         paren = paren == 1 ? 0 : -1;
-         if (!paren)
-           parenbad += 2;
-       }
-    }
-  if (isname && ss - s > 4 && !strcmp(ss - 4, ":any"))
-    bad++;
-  if (!paren && !(bad - parenbad))
-    return s;
-
-  /* we need escaping! */
-  s2 = s2p = pool_alloctmpspace(pool, strlen(s) + bad * 2 + 1);
-  if (!strncmp(s, "namespace:", 10))
-    {
-      strcpy(s2p, "namespace\\3a");
-      s2p += 12;
-      s += 10;
-    }
-  ss = s;
-  for (; *ss; ss++)
-    {
-      *s2p++ = *ss;
-      if ((ss == s && strchr("[(<=>!", *s)) || *ss == ' ' || *ss == '\\' || *(unsigned char *)ss < 32 || *ss == '(' || *ss == ')')
-       {
-         s2p[-1] = '\\';
-         solv_bin2hex((unsigned char *)ss, 1, s2p);
-         s2p += 2;
-       }
-    }
-  *s2p = 0;
-  if (isname && s2p - s2 > 4 && !strcmp(s2p - 4, ":any"))
-    strcpy(s2p - 4, "\\3aany");
-  return s2;
-}
-
-struct oplist {
-  Id flags;
-  const char *opname;
-} oplist[] = {
-  { REL_EQ, "=" },
-  { REL_GT | REL_LT | REL_EQ, "<=>" },
-  { REL_LT | REL_EQ, "<=" },
-  { REL_GT | REL_EQ, ">=" },
-  { REL_GT, ">" },
-  { REL_GT | REL_LT, "<>" },
-  { REL_AND,   "&" },
-  { REL_OR ,   "|" },
-  { REL_WITH , "+" },
-  { REL_NAMESPACE , "<NAMESPACE>" },
-  { REL_ARCH,       "." },
-  { REL_MULTIARCH,  "<MULTIARCH>" },
-  { REL_FILECONFLICT,  "<FILECONFLICT>" },
-  { REL_COND,  "<IF>" },
-  { REL_COMPAT,  "compat >=" },
-  { REL_KIND,  "<KIND>" },
-  { REL_ELSE, "<ELSE>" },
-  { REL_LT, "<" },
-  { 0, 0 }
-};
-
-static const char *
-testcase_dep2str_complex(Pool *pool, Id id, int addparens)
-{
-  Reldep *rd;
-  char *s;
-  const char *s2;
-  int needparens;
-  struct oplist *op;
-
-  if (!ISRELDEP(id))
-    return testcase_id2str(pool, id, 1);
-  rd = GETRELDEP(pool, id);
-
-  /* check for special shortcuts */
-  if (rd->flags == REL_NAMESPACE && !ISRELDEP(rd->name) && !strncmp(pool_id2str(pool, rd->name), "namespace:", 10))
-    {
-      const char *ns = pool_id2str(pool, rd->name);
-      int nslen = strlen(ns);
-      /* special namespace formatting */
-      const char *evrs = testcase_dep2str_complex(pool, rd->evr, 0);
-      s = pool_tmpappend(pool, evrs, ns, "()");
-      memmove(s + nslen + 1, s, strlen(s) - nslen - 2);
-      memcpy(s, ns, nslen);
-      s[nslen] = '(';
-      return s;
-    }
-  if (rd->flags == REL_MULTIARCH && !ISRELDEP(rd->name) && rd->evr == ARCH_ANY)
-    {
-      /* special :any suffix */
-      const char *ns = testcase_id2str(pool, rd->name, 1);
-      return pool_tmpappend(pool, ns, ":any", 0);
-    }
-
-  needparens = 0;
-  if (ISRELDEP(rd->name))
-    {
-      Reldep *rd2 = GETRELDEP(pool, rd->name);
-      needparens = 1;
-      if (rd->flags > 7 && rd->flags != REL_COMPAT && rd2->flags && rd2->flags <= 7)
-       needparens = 0;
-    }
-  s = (char *)testcase_dep2str_complex(pool, rd->name, needparens);
-
-  if (addparens)
-    {
-      s = pool_tmpappend(pool, s, "(", 0);
-      memmove(s + 1, s, strlen(s + 1));
-      s[0] = '(';
-    }
-  for (op = oplist; op->flags; op++)
-    if (rd->flags == op->flags)
-      break;
-  if (op->flags)
-    {
-      s = pool_tmpappend(pool, s, " ", op->opname);
-      s = pool_tmpappend(pool, s, " ", 0);
-    }
-  else
-    {
-      char buf[64];
-      sprintf(buf, " <%u> ", rd->flags);
-      s = pool_tmpappend(pool, s, buf, 0);
-    }
-
-  needparens = 0;
-  if (ISRELDEP(rd->evr))
-    {
-      Reldep *rd2 = GETRELDEP(pool, rd->evr);
-      needparens = 1;
-      if (rd->flags > 7 && rd2->flags && rd2->flags <= 7)
-       needparens = 0;
-      if (rd->flags == REL_AND && rd2->flags == REL_AND)
-       needparens = 0; /* chain */
-      if (rd->flags == REL_OR && rd2->flags == REL_OR)
-       needparens = 0; /* chain */
-      if (rd->flags > 0 && rd->flags < 8 && rd2->flags == REL_COMPAT)
-       needparens = 0; /* chain */
-    }
-  if (!ISRELDEP(rd->evr))
-    s2 = testcase_id2str(pool, rd->evr, 0);
-  else
-    s2 = testcase_dep2str_complex(pool, rd->evr, needparens);
-  if (addparens)
-    s = pool_tmpappend(pool, s, s2, ")");
-  else
-    s = pool_tmpappend(pool, s, s2, 0);
-  pool_freetmpspace(pool, s2);
-  return s;
-}
-
-const char *
-testcase_dep2str(Pool *pool, Id id)
-{
-  return testcase_dep2str_complex(pool, id, 0);
-}
-
-
-/* Convert a simple string. Also handle the :any suffix */
-static Id
-testcase_str2dep_simple(Pool *pool, const char **sp, int isname)
-{
-  int haveesc = 0;
-  int paren = 0;
-  int isany = 0;
-  Id id;
-  const char *s;
-  for (s = *sp; *s; s++)
-    {
-      if (*s == '\\')
-       haveesc++;
-      if (*s == ' ' || *(unsigned char *)s < 32)
-       break;
-      if (*s == '(')
-       paren++;
-      if (*s == ')' && paren-- <= 0)
-       break;
-    }
-  if (isname && s - *sp > 4 && !strncmp(s - 4, ":any", 4))
-    {
-      isany = 1;
-      s -= 4;
-    }
-  if (!haveesc)
-    {
-      if (s - *sp == 6 && !strncmp(*sp, "<NULL>", 6))
-       id = 0;
-      else
-        id = pool_strn2id(pool, *sp, s - *sp, 1);
-    }
-  else if (s - *sp == 3 && !strncmp(*sp, "\\00", 3))
-    id = 1;
-  else
-    {
-      char buf[128], *bp, *bp2;
-      const char *sp2;
-      bp = s - *sp >= 128 ? solv_malloc(s - *sp + 1) : buf;
-      for (bp2 = bp, sp2 = *sp; sp2 < s;)
-       {
-         *bp2++ = *sp2++;
-         if (bp2[-1] == '\\')
-           solv_hex2bin(&sp2, (unsigned char *)bp2 - 1, 1);
-       }
-      *bp2 = 0;
-      id = pool_str2id(pool, bp, 1);
-      if (bp != buf)
-       solv_free(bp);
-    }
-  if (isany)
-    {
-      id = pool_rel2id(pool, id, ARCH_ANY, REL_MULTIARCH, 1);
-      s += 4;
-    }
-  *sp = s;
-  return id;
-}
-
-
-static Id
-testcase_str2dep_complex(Pool *pool, const char **sp, int relop)
-{
-  const char *s = *sp;
-  Id flags, id, id2, namespaceid = 0;
-  struct oplist *op;
-
-  while (*s == ' ' || *s == '\t')
-    s++;
-  if (!strncmp(s, "namespace:", 10))
-    {
-      /* special namespace hack */
-      const char *s2;
-      for (s2 = s + 10; *s2 && *s2 != '('; s2++)
-       ;
-      if (*s2 == '(')
-       {
-         namespaceid = pool_strn2id(pool, s, s2 - s, 1);
-         s = s2;
-       }
-    }
-  if (*s == '(')
-    {
-      s++;
-      id = testcase_str2dep_complex(pool, &s, 0);
-      if (!s || *s != ')')
-       {
-         *sp = 0;
-         return 0;
-       }
-      s++;
-    }
-  else
-    id = testcase_str2dep_simple(pool, &s, relop ? 0 : 1);
-  if (namespaceid)
-    id = pool_rel2id(pool, namespaceid, id, REL_NAMESPACE, 1);
-    
-  for (;;)
-    {
-      while (*s == ' ' || *s == '\t')
-       s++;
-      if (!*s || *s == ')' || (relop && strncmp(s, "compat >= ", 10) != 0))
-       {
-         *sp = s;
-         return id;
-       }
-
-      /* we have an op! Find the end */
-      flags = -1;
-      if (s[0] == '<' && (s[1] >= '0' && s[1] <= '9'))
-       {
-         const char *s2;
-         for (s2 = s + 1; *s2 >= '0' && *s2 <= '9'; s2++)
-           ;
-         if (*s2 == '>')
-           {
-             flags = strtoul(s + 1, 0, 10);
-             s = s2 + 1;
-           }
-       }
-      if (flags == -1)
-       {
-         for (op = oplist; op->flags; op++)
-           if (!strncmp(s, op->opname, strlen(op->opname)))
-             break;
-         if (!op->flags)
-           {
-             *sp = 0;
-             return 0;
-           }
-         flags = op->flags;
-         s += strlen(op->opname);
-       }
-      id2 = testcase_str2dep_complex(pool, &s, flags > 0 && flags < 8);
-      if (!s)
-       {
-         *sp = 0;
-         return 0;
-       }
-      id = pool_rel2id(pool, id, id2, flags, 1);
-    }
-}
-
-Id
-testcase_str2dep(Pool *pool, const char *s)
-{
-  Id id = testcase_str2dep_complex(pool, &s, 0);
-  return s && !*s ? id : 0;
-}
-
-/**********************************************************/
-
-const char *
-testcase_repoid2str(Pool *pool, Id repoid)
-{
-  Repo *repo = pool_id2repo(pool, repoid);
-  if (repo->name)
-    {
-      char *r = pool_tmpjoin(pool, repo->name, 0, 0);
-      char *rp;
-      for (rp = r; *rp; rp++)
-       if (*rp == ' ' || *rp == '\t')
-         *rp = '_';
-      return r;
-    }
-  else
-    {
-      char buf[20];
-      sprintf(buf, "#%d", repoid);
-      return pool_tmpjoin(pool, buf, 0, 0);
-    }
-}
-
-const char *
-testcase_solvid2str(Pool *pool, Id p)
-{
-  Solvable *s = pool->solvables + p;
-  const char *n, *e, *a;
-  char *str, buf[20];
-
-  if (p == SYSTEMSOLVABLE)
-    return "@SYSTEM";
-  n = pool_id2str(pool, s->name);
-  e = pool_id2str(pool, s->evr);
-  a = pool_id2str(pool, s->arch);
-  str = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
-  sprintf(str, "%s-%s.%s", n, e, a);
-  if (!s->repo)
-    return pool_tmpappend(pool, str, "@", 0);
-  if (s->repo->name)
-    {
-      int l = strlen(str);
-      char *str2 = pool_tmpappend(pool, str, "@", s->repo->name);
-      for (; str2[l]; l++)
-       if (str2[l] == ' ' || str2[l] == '\t')
-         str2[l] = '_';
-      return str2;
-    }
-  sprintf(buf, "@#%d", s->repo->repoid);
-  return pool_tmpappend(pool, str, buf, 0);
-}
-
-Repo *
-testcase_str2repo(Pool *pool, const char *str)
-{
-  int repoid;
-  Repo *repo = 0;
-  if (str[0] == '#' && (str[1] >= '0' && str[1] <= '9'))
-    {
-      int j;
-      repoid = 0;
-      for (j = 1; str[j] >= '0' && str[j] <= '9'; j++)
-       repoid = repoid * 10 + (str[j] - '0');
-      if (!str[j] && repoid > 0 && repoid < pool->nrepos)
-       repo = pool_id2repo(pool, repoid);
-    }
-  if (!repo)
-    {
-      FOR_REPOS(repoid, repo)
-       {
-         int i, l;
-         if (!repo->name)
-           continue;
-         l = strlen(repo->name);
-         for (i = 0; i < l; i++)
-           {
-             int c = repo->name[i];
-             if (c == ' ' || c == '\t')
-               c = '_';
-             if (c != str[i])
-               break;
-           }
-         if (i == l && !str[l])
-           break;
-       }
-      if (repoid >= pool->nrepos)
-       repo = 0;
-    }
-  return repo;
-}
-
-Id
-testcase_str2solvid(Pool *pool, const char *str)
-{
-  int i, l = strlen(str);
-  int repostart;
-  Repo *repo;
-  Id arch;
-
-  if (!l)
-    return 0;
-  if (*str == '@' && !strcmp(str, "@SYSTEM"))
-    return SYSTEMSOLVABLE;
-  repo = 0;
-  for (i = l - 1; i >= 0; i--)
-    if (str[i] == '@' && (repo = testcase_str2repo(pool, str + i + 1)) != 0)
-      break;
-  if (i < 0)
-    i = l;
-  repostart = i;
-  /* now find the arch (if present) */
-  arch = 0;
-  for (i = repostart - 1; i > 0; i--)
-    if (str[i] == '.')
-      {
-       arch = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
-       if (arch)
-         repostart = i;
-       break;
-      }
-  /* now find the name */
-  for (i = repostart - 1; i > 0; i--)
-    {
-      if (str[i] == '-')
-       {
-         Id nid, evrid, p, pp;
-         nid = pool_strn2id(pool, str, i, 0);
-         if (!nid)
-           continue;
-         evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
-         if (!evrid)
-           continue;
-         FOR_PROVIDES(p, pp, nid)
-           {
-             Solvable *s = pool->solvables + p;
-             if (s->name != nid || s->evr != evrid)
-               continue;
-             if (repo && s->repo != repo)
-               continue;
-             if (arch && s->arch != arch)
-               continue;
-             return p;
-           }
-       }
-    }
-  return 0;
-}
-
-const char *
-testcase_job2str(Pool *pool, Id how, Id what)
-{
-  char *ret;
-  const char *jobstr;
-  const char *selstr;
-  const char *pkgstr;
-  int i, o;
-  Id select = how & SOLVER_SELECTMASK;
-
-  for (i = 0; job2str[i].str; i++)
-    if ((how & SOLVER_JOBMASK) == job2str[i].job)
-      break;
-  jobstr = job2str[i].str ? job2str[i].str : "unknown";
-  if (select == SOLVER_SOLVABLE)
-    {
-      selstr = " pkg ";
-      pkgstr = testcase_solvid2str(pool, what);
-    }
-  else if (select == SOLVER_SOLVABLE_NAME)
-    {
-      selstr = " name ";
-      pkgstr = testcase_dep2str(pool, what);
-    }
-  else if (select == SOLVER_SOLVABLE_PROVIDES)
-    {
-      selstr = " provides ";
-      pkgstr = testcase_dep2str(pool, what);
-    }
-  else if (select == SOLVER_SOLVABLE_ONE_OF)
-    {
-      Id p;
-      selstr = " oneof ";
-      pkgstr = 0;
-      while ((p = pool->whatprovidesdata[what++]) != 0)
-       {
-         const char *s = testcase_solvid2str(pool, p);
-         if (pkgstr)
-           {
-             pkgstr = pool_tmpappend(pool, pkgstr, " ", s);
-             pool_freetmpspace(pool, s);
-           }
-         else
-           pkgstr = s;
-       }
-      if (!pkgstr)
-       pkgstr = "nothing";
-    }
-  else if (select == SOLVER_SOLVABLE_REPO)
-    {
-      Repo *repo = pool_id2repo(pool, what);
-      selstr = " repo ";
-      if (!repo->name)
-       {
-          char buf[20];
-         sprintf(buf, "#%d", repo->repoid);
-         pkgstr = pool_tmpjoin(pool, buf, 0, 0);
-       }
-      else
-        pkgstr = pool_tmpjoin(pool, repo->name, 0, 0);
-    }
-  else if (select == SOLVER_SOLVABLE_ALL)
-    {
-      selstr = " all ";
-      pkgstr = "packages";
-    }
-  else
-    {
-      selstr = " unknown ";
-      pkgstr = "unknown";
-    }
-  ret = pool_tmpjoin(pool, jobstr, selstr, pkgstr);
-  o = strlen(ret);
-  ret = pool_tmpappend(pool, ret, " ", 0);
-  for (i = 0; jobflags2str[i].str; i++)
-    if ((how & jobflags2str[i].flag) != 0)
-      ret = pool_tmpappend(pool, ret, ",", jobflags2str[i].str);
-  if (!ret[o + 1])
-    ret[o] = 0;
-  else
-    {
-      ret[o + 1] = '[';
-      ret = pool_tmpappend(pool, ret, "]", 0);
-    }
-  return ret;
-}
-
-static int
-str2selflags(Pool *pool, char *s)      /* modifies the string! */
-{
-  int i, selflags = 0;
-  while (s)
-    {
-      char *se = strchr(s, ',');
-      if (se)
-       *se++ = 0;
-      for (i = 0; selflags2str[i].str; i++)
-       if (!strcmp(s, selflags2str[i].str))
-         {
-           selflags |= selflags2str[i].flag;
-           break;
-         }
-      if (!selflags2str[i].str)
-       pool_debug(pool, SOLV_ERROR, "str2job: unknown selection flag '%s'\n", s);
-      s = se;
-    }
-  return selflags;
-}
-
-static int
-str2jobflags(Pool *pool, char *s)      /* modifies the string */
-{
-  int i, jobflags = 0;
-  while (s)
-    {
-      char *se = strchr(s, ',');
-      if (se)
-       *se++ = 0;
-      for (i = 0; jobflags2str[i].str; i++)
-       if (!strcmp(s, jobflags2str[i].str))
-         {
-           jobflags |= jobflags2str[i].flag;
-           break;
-         }
-      if (!jobflags2str[i].str)
-       pool_debug(pool, SOLV_ERROR, "str2job: unknown job flag '%s'\n", s);
-      s = se;
-    }
-  return jobflags;
-}
-
-Id
-testcase_str2job(Pool *pool, const char *str, Id *whatp)
-{
-  int i;
-  Id job;
-  Id what;
-  char *s;
-  char **pieces = 0;
-  int npieces = 0;
-
-  *whatp = 0;
-  /* so we can patch it */
-  s = pool_tmpjoin(pool, str, 0, 0);
-  /* split it in pieces */
-  for (;;)
-    {
-      while (*s == ' ' || *s == '\t')
-       s++;
-      if (!*s)
-       break;
-      pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
-      pieces[npieces++] = s;
-      while (*s && *s != ' ' && *s != '\t')
-       s++;
-      if (*s)
-       *s++ = 0;
-    }
-  if (npieces < 3)
-    {
-      pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
-      solv_free(pieces);
-      return -1;
-    }
-
-  for (i = 0; job2str[i].str; i++)
-    if (!strcmp(pieces[0], job2str[i].str))
-      break;
-  if (!job2str[i].str)
-    {
-      pool_debug(pool, SOLV_ERROR, "str2job: unknown job '%s'\n", str);
-      solv_free(pieces);
-      return -1;
-    }
-  job = job2str[i].job;
-  what = 0;
-  if (npieces > 3)
-    {
-      char *flags = pieces[npieces - 1];
-      if (*flags == '[' && flags[strlen(flags) - 1] == ']')
-       {
-         npieces--;
-         flags++;
-         flags[strlen(flags) - 1] = 0;
-         job |= str2jobflags(pool, flags);
-       }
-    }
-  if (!strcmp(pieces[1], "pkg"))
-    {
-      if (npieces != 3)
-       {
-         pool_debug(pool, SOLV_ERROR, "str2job: bad pkg selector in '%s'\n", str);
-         solv_free(pieces);
-         return -1;
-       }
-      job |= SOLVER_SOLVABLE;
-      what = testcase_str2solvid(pool, pieces[2]);
-      if (!what)
-       {
-         pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[2]);
-         solv_free(pieces);
-         return -1;
-       }
-    }
-  else if (!strcmp(pieces[1], "name") || !strcmp(pieces[1], "provides"))
-    {
-      /* join em again for dep2str... */
-      char *sp;
-      for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
-       if (*sp == 0)
-         *sp = ' ';
-      what = 0;
-      if (pieces[1][0] == 'p' && strncmp(pieces[2], "namespace:", 10) == 0)
-       {
-         char *spe = strchr(pieces[2], '(');
-         int l = strlen(pieces[2]);
-         if (spe && pieces[2][l - 1] == ')')
-           {
-             /* special namespace provides */
-             if (strcmp(spe, "(<NULL>)") != 0)
-               {
-                 pieces[2][l - 1] = 0;
-                 what = testcase_str2dep(pool, spe + 1);
-                 pieces[2][l - 1] = ')';
-               }
-             what = pool_rel2id(pool, pool_strn2id(pool, pieces[2], spe - pieces[2], 1), what, REL_NAMESPACE, 1);
-           }
-       }
-      if (!what)
-        what = testcase_str2dep(pool, pieces[2]);
-      if (pieces[1][0] == 'n')
-       job |= SOLVER_SOLVABLE_NAME;
-      else
-       job |= SOLVER_SOLVABLE_PROVIDES;
-    }
-  else if (!strcmp(pieces[1], "oneof"))
-    {
-      Queue q;
-      job |= SOLVER_SOLVABLE_ONE_OF;
-      queue_init(&q);
-      if (npieces > 3 && strcmp(pieces[2], "nothing") != 0)
-       {
-         for (i = 2; i < npieces; i++)
-           {
-             Id p = testcase_str2solvid(pool, pieces[i]);
-             if (!p)
-               {
-                 pool_debug(pool, SOLV_ERROR, "str2job: unknown package '%s'\n", pieces[i]);
-                 queue_free(&q);
-                 solv_free(pieces);
-                 return -1;
-               }
-             queue_push(&q, p);
-           }
-       }
-      what = pool_queuetowhatprovides(pool, &q);
-      queue_free(&q);
-    }
-  else if (!strcmp(pieces[1], "repo"))
-    {
-      Repo *repo;
-      if (npieces != 3)
-       {
-         pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
-         solv_free(pieces);
-         return -1;
-       }
-      repo = testcase_str2repo(pool, pieces[2]);
-      if (!repo)
-       {
-         pool_debug(pool, SOLV_ERROR, "str2job: unknown repo '%s'\n", pieces[2]);
-         solv_free(pieces);
-         return -1;
-       }
-      job |= SOLVER_SOLVABLE_REPO;
-      what = repo->repoid;
-    }
-  else if (!strcmp(pieces[1], "all"))
-    {
-      if (npieces != 3 && strcmp(pieces[2], "packages") != 0)
-       {
-         pool_debug(pool, SOLV_ERROR, "str2job: bad line '%s'\n", str);
-         solv_free(pieces);
-         return -1;
-       }
-      job |= SOLVER_SOLVABLE_ALL;
-      what = 0;
-    }
-  else
-    {
-      pool_debug(pool, SOLV_ERROR, "str2job: unknown selection in '%s'\n", str);
-      solv_free(pieces);
-      return -1;
-    }
-  *whatp = what;
-  solv_free(pieces);
-  return job;
-}
-
-int
-addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue)
-{
-  Id job;
-  int i, r;
-  int selflags;
-  Queue sel;
-
-  for (i = 0; job2str[i].str; i++)
-    if (!strcmp(pieces[0], job2str[i].str))
-      break;
-  if (!job2str[i].str)
-    {
-      pool_debug(pool, SOLV_ERROR, "selstr2job: unknown job '%s'\n", pieces[0]);
-      return -1;
-    }
-  job = job2str[i].job;
-  if (npieces > 3)
-    {
-      char *flags = pieces[npieces - 1];
-      if (*flags == '[' && flags[strlen(flags) - 1] == ']')
-       {
-         npieces--;
-         flags++;
-         flags[strlen(flags) - 1] = 0;
-         job |= str2jobflags(pool, flags);
-       }
-    }
-  if (npieces < 4)
-    {
-      pool_debug(pool, SOLV_ERROR, "selstr2job: no selection flags\n");
-      return -1;
-    }
-  selflags = str2selflags(pool, pieces[3]);
-  queue_init(&sel);
-  r = selection_make(pool, &sel, pieces[2], selflags);
-  for (i = 0; i < sel.count; i += 2)
-    queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]);
-  queue_free(&sel);
-  return r;
-}
-
-static void
-writedeps(Repo *repo, FILE *fp, const char *tag, Id key, Solvable *s, Offset off)
-{
-  Pool *pool = repo->pool;
-  Id id, *dp;
-  int tagwritten = 0;
-  const char *idstr;
-
-  if (!off)
-    return;
-  dp = repo->idarraydata + off;
-  while ((id = *dp++) != 0)
-    {
-      if (key == SOLVABLE_REQUIRES && id == SOLVABLE_PREREQMARKER)
-       {
-         if (tagwritten)
-           fprintf(fp, "-%s\n", tag);
-         tagwritten = 0;
-         tag = "Prq:";
-         continue;
-       }
-      if (key == SOLVABLE_PROVIDES && id == SOLVABLE_FILEMARKER)
-       continue;
-      idstr = testcase_dep2str(pool, id);
-      if (!tagwritten)
-       {
-         fprintf(fp, "+%s\n", tag);
-         tagwritten = 1;
-       }
-      fprintf(fp, "%s\n", idstr);
-    }
-  if (tagwritten)
-    fprintf(fp, "-%s\n", tag);
-}
-
-static void
-writefilelist(Repo *repo, FILE *fp, const char *tag, Solvable *s)
-{
-  Pool *pool = repo->pool;
-  int tagwritten = 0;
-  Dataiterator di;
-
-  dataiterator_init(&di, pool, repo, s - pool->solvables, SOLVABLE_FILELIST, 0, 0);
-  while (dataiterator_step(&di))
-    {
-      const char *s = repodata_dir2str(di.data, di.kv.id, di.kv.str);
-      if (!tagwritten)
-       {
-         fprintf(fp, "+%s\n", tag);
-         tagwritten = 1;
-       }
-      fprintf(fp, "%s\n", s);
-    }
-  if (tagwritten)
-    fprintf(fp, "-%s\n", tag);
-  dataiterator_free(&di);
-}
-
-int
-testcase_write_testtags(Repo *repo, FILE *fp)
-{
-  Pool *pool = repo->pool;
-  Solvable *s;
-  Id p;
-  const char *name;
-  const char *evr;
-  const char *arch;
-  const char *release;
-  const char *tmp;
-  unsigned int ti;
-
-  fprintf(fp, "=Ver: 3.0\n");
-  FOR_REPO_SOLVABLES(repo, p, s)
-    {
-      name = pool_id2str(pool, s->name);
-      evr = pool_id2str(pool, s->evr);
-      arch = pool_id2str(pool, s->arch);
-      release = strrchr(evr, '-');
-      if (!release)
-       release = evr + strlen(evr);
-      fprintf(fp, "=Pkg: %s %.*s %s %s\n", name, (int)(release - evr), evr, *release && release[1] ? release + 1 : "-", arch);
-      tmp = solvable_lookup_str(s, SOLVABLE_SUMMARY);
-      if (tmp)
-        fprintf(fp, "=Sum: %s\n", tmp);
-      writedeps(repo, fp, "Req:", SOLVABLE_REQUIRES, s, s->requires);
-      writedeps(repo, fp, "Prv:", SOLVABLE_PROVIDES, s, s->provides);
-      writedeps(repo, fp, "Obs:", SOLVABLE_OBSOLETES, s, s->obsoletes);
-      writedeps(repo, fp, "Con:", SOLVABLE_CONFLICTS, s, s->conflicts);
-      writedeps(repo, fp, "Rec:", SOLVABLE_RECOMMENDS, s, s->recommends);
-      writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements);
-      writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests);
-      writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances);
-      if (s->vendor)
-       fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor));
-      ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
-      if (ti)
-       fprintf(fp, "=Tim: %u\n", ti);
-      writefilelist(repo, fp, "Fls:", s);
-    }
-  return 0;
-}
-
-static inline Offset
-adddep(Repo *repo, Offset olddeps, char *str, Id marker)
-{
-  Id id = *str == '/' ? pool_str2id(repo->pool, str, 1) : testcase_str2dep(repo->pool, str);
-  return repo_addid_dep(repo, olddeps, id, marker);
-}
-
-static void
-finish_v2_solvable(Pool *pool, Repodata *data, Solvable *s, char *filelist, int nfilelist)
-{
-  if (nfilelist)
-    {
-      int l;
-      Id did;
-      for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1)
-       {
-         char *p = strrchr(filelist + l, '/');
-         if (!p)
-           continue;
-         *p++ = 0;
-         did = repodata_str2dir(data, filelist + l, 1);
-         p[-1] = '/';
-         if (!did)
-           did = repodata_str2dir(data, "/", 1);
-         repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p);
-       }
-    }
-  s->supplements = repo_fix_supplements(s->repo, s->provides, s->supplements, 0);
-  s->conflicts = repo_fix_conflicts(s->repo, s->conflicts);
-}
-
-/* stripped down version of susetags parser used for testcases */
-int
-testcase_add_testtags(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  char *line, *linep;
-  int aline;
-  int tag;
-  Repodata *data;
-  Solvable *s;
-  char *sp[5];
-  unsigned int t;
-  int intag;
-  char *filelist = 0;
-  int afilelist = 0;
-  int nfilelist = 0;
-  int tagsversion = 0;
-  int addselfprovides = 1;     /* for compat reasons */
-
-  data = repo_add_repodata(repo, flags);
-  s = 0;
-  intag = 0;
-
-  aline = 1024;
-  line = solv_malloc(aline);
-  linep = line;
-  for (;;)
-    {
-      if (linep - line + 16 > aline)
-       {
-         aline = linep - line;
-         line = solv_realloc(line, aline + 512);
-         linep = line + aline;
-         aline += 512;
-       }
-      if (!fgets(linep, aline - (linep - line), fp))
-       break;
-      linep += strlen(linep);
-      if (linep == line || linep[-1] != '\n')
-       continue;
-      linep[-1] = 0;
-      linep = line + intag;
-      if (intag)
-       {
-         if (line[intag] == '-' && !strncmp(line + 1, line + intag + 1, intag - 2))
-           {
-             intag = 0;
-             linep = line;
-             continue;
-           }
-       }
-      else if (line[0] == '+' && line[1] && line[1] != ':')
-       {
-         char *tagend = strchr(line, ':');
-         if (!tagend)
-           continue;
-         line[0] = '=';
-         tagend[1] = ' ';
-         intag = tagend + 2 - line;
-         linep = line + intag;
-         continue;
-       }
-      if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':')
-       continue;
-      tag = line[1] << 16 | line[2] << 8 | line[3];
-      switch(tag)
-        {
-       case 'V' << 16 | 'e' << 8 | 'r':
-         tagsversion = atoi(line + 6);
-         addselfprovides = tagsversion < 3 || strstr(line + 6, "addselfprovides") != 0;
-         break;
-       case 'P' << 16 | 'k' << 8 | 'g':
-         if (s)
-           {
-             if (tagsversion == 2)
-               finish_v2_solvable(pool, data, s, filelist, nfilelist);
-             if (addselfprovides && s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-               s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-           }
-         nfilelist = 0;
-         if (split(line + 5, sp, 5) != 4)
-           break;
-         s = pool_id2solvable(pool, repo_add_solvable(repo));
-         s->name = pool_str2id(pool, sp[0], 1);
-         /* join back version and release */
-         if (sp[2] && !(sp[2][0] == '-' && !sp[2][1]))
-           sp[2][-1] = '-';
-         s->evr = makeevr(pool, sp[1]);
-         s->arch = pool_str2id(pool, sp[3], 1);
-         break;
-       case 'S' << 16 | 'u' << 8 | 'm':
-         repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6);
-         break;
-       case 'V' << 16 | 'n' << 8 | 'd':
-         s->vendor = pool_str2id(pool, line + 6, 1);
-         break;
-       case 'T' << 16 | 'i' << 8 | 'm':
-         t = atoi(line + 6);
-         if (t)
-           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
-         break;
-       case 'R' << 16 | 'e' << 8 | 'q':
-         s->requires = adddep(repo, s->requires, line + 6, -SOLVABLE_PREREQMARKER);
-         break;
-       case 'P' << 16 | 'r' << 8 | 'q':
-         s->requires = adddep(repo, s->requires, line + 6, SOLVABLE_PREREQMARKER);
-         break;
-       case 'P' << 16 | 'r' << 8 | 'v':
-         /* version 2 had the file list at the end of the provides */
-         if (tagsversion == 2)
-           {
-             if (line[6] == '/')
-               {
-                 int l = strlen(line + 6) + 1;
-                 if (nfilelist + l > afilelist)
-                   {
-                     afilelist = nfilelist + l + 512;
-                     filelist = solv_realloc(filelist, afilelist);
-                   }
-                 memcpy(filelist + nfilelist, line + 6, l);
-                 nfilelist += l;
-                 break;
-               }
-             if (nfilelist)
-               {
-                 int l;
-                 for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1)
-                   s->provides = repo_addid_dep(repo, s->provides, pool_str2id(pool, filelist + l, 1), 0);
-                 nfilelist = 0;
-               }
-           }
-         s->provides = adddep(repo, s->provides, line + 6, 0);
-         break;
-       case 'F' << 16 | 'l' << 8 | 's':
-         {
-           char *p = strrchr(line + 6, '/');
-           Id did;
-           if (!p)
-             break;
-           *p++ = 0;
-           did = repodata_str2dir(data, line + 6, 1);
-           if (!did)
-             did = repodata_str2dir(data, "/", 1);
-           repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p);
-           break;
-         }
-       case 'O' << 16 | 'b' << 8 | 's':
-         s->obsoletes = adddep(repo, s->obsoletes, line + 6, 0);
-         break;
-       case 'C' << 16 | 'o' << 8 | 'n':
-         s->conflicts = adddep(repo, s->conflicts, line + 6, 0);
-         break;
-       case 'R' << 16 | 'e' << 8 | 'c':
-         s->recommends = adddep(repo, s->recommends, line + 6, 0);
-         break;
-       case 'S' << 16 | 'u' << 8 | 'p':
-         s->supplements = adddep(repo, s->supplements, line + 6, 0);
-         break;
-       case 'S' << 16 | 'u' << 8 | 'g':
-         s->suggests = adddep(repo, s->suggests, line + 6, 0);
-         break;
-       case 'E' << 16 | 'n' << 8 | 'h':
-         s->enhances = adddep(repo, s->enhances, line + 6, 0);
-         break;
-        default:
-         break;
-        }
-    }
-  if (s)
-    {
-      if (tagsversion == 2)
-       finish_v2_solvable(pool, data, s, filelist, nfilelist);
-      if (addselfprovides && s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-        s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-    }
-  solv_free(line);
-  solv_free(filelist);
-  repodata_free_dircache(data);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return 0;
-}
-
-const char *
-testcase_getpoolflags(Pool *pool)
-{
-  const char *str = 0;
-  int i, v;
-  for (i = 0; poolflags2str[i].str; i++)
-    {
-      v = pool_get_flag(pool, poolflags2str[i].flag);
-      if (v == poolflags2str[i].def)
-       continue;
-      str = pool_tmpappend(pool, str, v ? " " : " !", poolflags2str[i].str);
-    }
-  return str ? str + 1 : "";
-}
-
-int
-testcase_setpoolflags(Pool *pool, const char *str)
-{
-  const char *p = str, *s;
-  int i, v;
-  for (;;)
-    {
-      while (*p == ' ' || *p == '\t' || *p == ',')
-       p++;
-      v = 1;
-      if (*p == '!')
-       {
-         p++;
-         v = 0;
-       }
-      if (!*p)
-       break;
-      s = p;
-      while (*p && *p != ' ' && *p != '\t' && *p != ',')
-       p++;
-      for (i = 0; poolflags2str[i].str; i++)
-       if (!strncmp(poolflags2str[i].str, s, p - s) && poolflags2str[i].str[p - s] == 0)
-         break;
-      if (!poolflags2str[i].str)
-       {
-         pool_debug(pool, SOLV_ERROR, "setpoolflags: unknown flag '%.*s'\n", (int)(p - s), s);
-         return 0;
-       }
-      pool_set_flag(pool, poolflags2str[i].flag, v);
-    }
-  return 1;
-}
-
-void
-testcase_resetpoolflags(Pool *pool)
-{
-  int i;
-  for (i = 0; poolflags2str[i].str; i++)
-    pool_set_flag(pool, poolflags2str[i].flag, poolflags2str[i].def);
-}
-
-const char *
-testcase_getsolverflags(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  const char *str = 0;
-  int i, v;
-  for (i = 0; solverflags2str[i].str; i++)
-    {
-      v = solver_get_flag(solv, solverflags2str[i].flag);
-      if (v == solverflags2str[i].def)
-       continue;
-      str = pool_tmpappend(pool, str, v ? " " : " !", solverflags2str[i].str);
-    }
-  return str ? str + 1 : "";
-}
-
-int
-testcase_setsolverflags(Solver *solv, const char *str)
-{
-  const char *p = str, *s;
-  int i, v;
-  for (;;)
-    {
-      while (*p == ' ' || *p == '\t' || *p == ',')
-       p++;
-      v = 1;
-      if (*p == '!')
-       {
-         p++;
-         v = 0;
-       }
-      if (!*p)
-       break;
-      s = p;
-      while (*p && *p != ' ' && *p != '\t' && *p != ',')
-       p++;
-      for (i = 0; solverflags2str[i].str; i++)
-       if (!strncmp(solverflags2str[i].str, s, p - s) && solverflags2str[i].str[p - s] == 0)
-         break;
-      if (!solverflags2str[i].str)
-       {
-         pool_debug(solv->pool, SOLV_ERROR, "setsolverflags: unknown flag '%.*s'\n", (int)(p - s), s);
-         return 0;
-       }
-      solver_set_flag(solv, solverflags2str[i].flag, v);
-    }
-  return 1;
-}
-
-void
-testcase_resetsolverflags(Solver *solv)
-{
-  int i;
-  for (i = 0; solverflags2str[i].str; i++)
-    solver_set_flag(solv, solverflags2str[i].flag, solverflags2str[i].def);
-}
-
-static const char *
-testcase_ruleid(Solver *solv, Id rid)
-{
-  Strqueue sq;
-  Queue q;
-  int i;
-  Chksum *chk;
-  const unsigned char *md5;
-  int md5l;
-  const char *s;
-
-  queue_init(&q);
-  strqueue_init(&sq);
-  solver_ruleliterals(solv, rid, &q);
-  for (i = 0; i < q.count; i++)
-    {
-      Id p = q.elements[i];
-      s = testcase_solvid2str(solv->pool, p > 0 ? p : -p);
-      if (p < 0)
-       s = pool_tmpjoin(solv->pool, "!", s, 0);
-      strqueue_push(&sq, s);
-    }
-  queue_free(&q);
-  strqueue_sort_u(&sq);
-  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
-  for (i = 0; i < sq.nstr; i++)
-    solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1);
-  md5 = solv_chksum_get(chk, &md5l);
-  s = pool_bin2hex(solv->pool, md5, md5l);
-  chk = solv_chksum_free(chk, 0);
-  strqueue_free(&sq);
-  return s;
-}
-
-static const char *
-testcase_problemid(Solver *solv, Id problem)
-{
-  Strqueue sq;
-  Queue q;
-  Chksum *chk;
-  const unsigned char *md5;
-  int i, md5l;
-  const char *s;
-
-  /* we build a hash of all rules that define the problem */
-  queue_init(&q);
-  strqueue_init(&sq);
-  solver_findallproblemrules(solv, problem, &q);
-  for (i = 0; i < q.count; i++)
-    strqueue_push(&sq, testcase_ruleid(solv, q.elements[i]));
-  queue_free(&q);
-  strqueue_sort_u(&sq);
-  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
-  for (i = 0; i < sq.nstr; i++)
-    solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1);
-  md5 = solv_chksum_get(chk, &md5l);
-  s = pool_bin2hex(solv->pool, md5, 4);
-  chk = solv_chksum_free(chk, 0);
-  strqueue_free(&sq);
-  return s;
-}
-
-static const char *
-testcase_solutionid(Solver *solv, Id problem, Id solution)
-{
-  Id intid;
-  Chksum *chk;
-  const unsigned char *md5;
-  int md5l;
-  const char *s;
-
-  intid = solver_solutionelement_internalid(solv, problem, solution);
-  /* internal stuff! handle with care! */
-  if (intid < 0)
-    {
-      /* it's a job */
-      s = testcase_job2str(solv->pool, solv->job.elements[-intid - 1], solv->job.elements[-intid]);
-    }
-  else
-    {
-      /* it's a rule */
-      s = testcase_ruleid(solv, intid);
-    }
-  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
-  solv_chksum_add(chk, s, strlen(s) + 1);
-  md5 = solv_chksum_get(chk, &md5l);
-  s = pool_bin2hex(solv->pool, md5, 4);
-  chk = solv_chksum_free(chk, 0);
-  return s;
-}
-
-static const char *
-testcase_alternativeid(Solver *solv, int type, Id id, Id from)
-{
-  const char *s;
-  Pool *pool = solv->pool;
-  Chksum *chk;
-  const unsigned char *md5;
-  int md5l;
-  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
-  if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
-    {
-      s = testcase_solvid2str(pool, from);
-      solv_chksum_add(chk, s, strlen(s) + 1);
-      s = testcase_dep2str(pool, id);
-      solv_chksum_add(chk, s, strlen(s) + 1);
-    }
-  else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
-    {
-      s = testcase_ruleid(solv, id);
-      solv_chksum_add(chk, s, strlen(s) + 1);
-    }
-  md5 = solv_chksum_get(chk, &md5l);
-  s = pool_bin2hex(pool, md5, 4);
-  chk = solv_chksum_free(chk, 0);
-  return s;
-}
-
-static struct class2str {
-  Id class;
-  const char *str;
-} class2str[] = {
-  { SOLVER_TRANSACTION_ERASE,          "erase" },
-  { SOLVER_TRANSACTION_INSTALL,        "install" },
-  { SOLVER_TRANSACTION_REINSTALLED,    "reinstall" },
-  { SOLVER_TRANSACTION_DOWNGRADED,     "downgrade" },
-  { SOLVER_TRANSACTION_CHANGED,        "change" },
-  { SOLVER_TRANSACTION_UPGRADED,       "upgrade" },
-  { SOLVER_TRANSACTION_OBSOLETED,      "obsolete" },
-  { SOLVER_TRANSACTION_MULTIINSTALL,   "multiinstall" },
-  { SOLVER_TRANSACTION_MULTIREINSTALL, "multireinstall" },
-  { 0, 0 }
-};
-
-static int
-dump_genid(Pool *pool, Strqueue *sq, Id id, int cnt)
-{
-  struct oplist *op;
-  char cntbuf[20];
-  const char *s;
-
-  if (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      for (op = oplist; op->flags; op++)
-       if (rd->flags == op->flags)
-         break;
-      cnt = dump_genid(pool, sq, rd->name, cnt);
-      cnt = dump_genid(pool, sq, rd->evr, cnt);
-      sprintf(cntbuf, "genid %2d: genid ", cnt++);
-      s = pool_tmpjoin(pool, cntbuf, "op ", op->flags ? op->opname : "unknown");
-    }
-  else
-    {
-      sprintf(cntbuf, "genid %2d: genid ", cnt++);
-      s = pool_tmpjoin(pool, cntbuf, id ? "lit " : "null", id ? pool_id2str(pool, id) : 0);
-    }
-  strqueue_push(sq, s);
-  return cnt;
-}
-
-char *
-testcase_solverresult(Solver *solv, int resultflags)
-{
-  Pool *pool = solv->pool;
-  int i, j;
-  Id p, op;
-  const char *s;
-  char *result;
-  Strqueue sq;
-
-  strqueue_init(&sq);
-  if ((resultflags & TESTCASE_RESULT_TRANSACTION) != 0)
-    {
-      Transaction *trans = solver_create_transaction(solv);
-      Queue q;
-
-      queue_init(&q);
-      for (i = 0; class2str[i].str; i++)
-       {
-         queue_empty(&q);
-         transaction_classify_pkgs(trans, SOLVER_TRANSACTION_KEEP_PSEUDO, class2str[i].class, 0, 0, &q);
-         for (j = 0; j < q.count; j++)
-           {
-             p = q.elements[j];
-             op = 0;
-             if (pool->installed && pool->solvables[p].repo == pool->installed)
-               op = transaction_obs_pkg(trans, p);
-             s = pool_tmpjoin(pool, class2str[i].str, " ", testcase_solvid2str(pool, p));
-             if (op)
-               s = pool_tmpjoin(pool, s, " ", testcase_solvid2str(pool, op));
-             strqueue_push(&sq, s);
-           }
-       }
-      queue_free(&q);
-      transaction_free(trans);
-    }
-  if ((resultflags & TESTCASE_RESULT_PROBLEMS) != 0)
-    {
-      char *probprefix, *solprefix;
-      int problem, solution, element;
-      int pcnt, scnt;
-
-      pcnt = solver_problem_count(solv);
-      for (problem = 1; problem <= pcnt; problem++)
-       {
-         Id rid, from, to, dep;
-         SolverRuleinfo rinfo;
-         rid = solver_findproblemrule(solv, problem);
-         s = testcase_problemid(solv, problem);
-         probprefix = solv_dupjoin("problem ", s, 0);
-         rinfo = solver_ruleinfo(solv, rid, &from, &to, &dep);
-         s = pool_tmpjoin(pool, probprefix, " info ", solver_problemruleinfo2str(solv, rinfo, from, to, dep));
-         strqueue_push(&sq, s);
-         scnt = solver_solution_count(solv, problem);
-         for (solution = 1; solution <= scnt; solution++)
-           {
-             s = testcase_solutionid(solv, problem, solution);
-             solprefix = solv_dupjoin(probprefix, " solution ", s);
-             element = 0;
-             while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &op)) != 0)
-               {
-                 if (p == SOLVER_SOLUTION_JOB)
-                   s = pool_tmpjoin(pool, solprefix, " deljob ", testcase_job2str(pool, solv->job.elements[op - 1], solv->job.elements[op]));
-                 else if (p > 0 && op == 0)
-                   s = pool_tmpjoin(pool, solprefix, " erase ", testcase_solvid2str(pool, p));
-                 else if (p > 0 && op > 0)
-                   {
-                     s = pool_tmpjoin(pool, solprefix, " replace ", testcase_solvid2str(pool, p));
-                     s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, op));
-                   }
-                 else if (p < 0 && op > 0)
-                   s = pool_tmpjoin(pool, solprefix, " allow ", testcase_solvid2str(pool, op));
-                 else
-                   s = pool_tmpjoin(pool, solprefix, " unknown", 0);
-                 strqueue_push(&sq, s);
-               }
-             solv_free(solprefix);
-           }
-         solv_free(probprefix);
-       }
-    }
-
-  if ((resultflags & TESTCASE_RESULT_ORPHANED) != 0)
-    {
-      Queue q;
-
-      queue_init(&q);
-      solver_get_orphaned(solv, &q);
-      for (i = 0; i < q.count; i++)
-       {
-         s = pool_tmpjoin(pool, "orphaned ", testcase_solvid2str(pool, q.elements[i]), 0);
-         strqueue_push(&sq, s);
-       }
-      queue_free(&q);
-    }
-
-  if ((resultflags & TESTCASE_RESULT_RECOMMENDED) != 0)
-    {
-      Queue qr, qs;
-
-      queue_init(&qr);
-      queue_init(&qs);
-      solver_get_recommendations(solv, &qr, &qs, 0);
-      for (i = 0; i < qr.count; i++)
-       {
-         s = pool_tmpjoin(pool, "recommended ", testcase_solvid2str(pool, qr.elements[i]), 0);
-         strqueue_push(&sq, s);
-       }
-      for (i = 0; i < qs.count; i++)
-       {
-         s = pool_tmpjoin(pool, "suggested ", testcase_solvid2str(pool, qs.elements[i]), 0);
-         strqueue_push(&sq, s);
-       }
-      queue_free(&qr);
-      queue_free(&qs);
-    }
-
-  if ((resultflags & TESTCASE_RESULT_UNNEEDED) != 0)
-    {
-      Queue q, qf;
-
-      queue_init(&q);
-      queue_init(&qf);
-      solver_get_unneeded(solv, &q, 0);
-      solver_get_unneeded(solv, &qf, 1);
-      for (i = j = 0; i < q.count; i++)
-       {
-         /* we rely on qf containing a subset of q in the same order */
-         if (j < qf.count && q.elements[i] == qf.elements[j])
-           {
-             s = pool_tmpjoin(pool, "unneeded_filtered ", testcase_solvid2str(pool, q.elements[i]), 0);
-             j++;
-           }
-         else
-           s = pool_tmpjoin(pool, "unneeded ", testcase_solvid2str(pool, q.elements[i]), 0);
-         strqueue_push(&sq, s);
-       }
-      queue_free(&q);
-      queue_free(&qf);
-    }
-  if ((resultflags & TESTCASE_RESULT_ALTERNATIVES) != 0)
-    {
-      char *altprefix;
-      Queue q, rq;
-      int cnt;
-      Id alternative;
-      queue_init(&q);
-      queue_init(&rq);
-      cnt = solver_alternatives_count(solv);
-      for (alternative = 1; alternative <= cnt; alternative++)
-       {
-         Id id, from, chosen;
-         char num[20];
-         int type = solver_get_alternative(solv, alternative, &id, &from, &chosen, &q, 0);
-         altprefix = solv_dupjoin("alternative ", testcase_alternativeid(solv, type, id, from), " ");
-         strcpy(num, " 0 ");
-         if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
-           {
-             char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, from));
-             s = pool_tmpappend(pool, s, " recommends ", testcase_dep2str(pool, id));
-             strqueue_push(&sq, s);
-           }
-         else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
-           {
-             /* map choice rules back to pkg rules */
-             if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
-               id = solver_rule2pkgrule(solv, id);
-             solver_allruleinfos(solv, id, &rq);
-             for (i = 0; i < rq.count; i += 4)
-               {
-                 int rtype = rq.elements[i];
-                 if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
-                   {
-                     const char *js = testcase_job2str(pool, rq.elements[i + 2], rq.elements[i + 3]);
-                     char *s = pool_tmpjoin(pool, altprefix, num, " job ");
-                     s = pool_tmpappend(pool, s, js, 0);
-                     strqueue_push(&sq, s);
-                   }
-                 else if (rtype == SOLVER_RULE_PKG_REQUIRES)
-                   {
-                     char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, rq.elements[i + 1]));
-                     s = pool_tmpappend(pool, s, " requires ", testcase_dep2str(pool, rq.elements[i + 3]));
-                     strqueue_push(&sq, s);
-                   }
-               }
-           }
-         for (i = 0; i < q.count; i++)
-           {
-             Id p = q.elements[i];
-             if (i >= 9)
-               num[0] = '0' + (i + 1) / 10;
-             num[1] = '0' + (i + 1) % 10;
-             if (-p == chosen)
-               s = pool_tmpjoin(pool, altprefix, num, "+ ");
-             else if (p < 0)
-               s = pool_tmpjoin(pool, altprefix, num, "- ");
-             else if (p >= 0)
-               s = pool_tmpjoin(pool, altprefix, num, "  ");
-             s = pool_tmpappend(pool, s,  testcase_solvid2str(pool, p < 0 ? -p : p), 0);
-             strqueue_push(&sq, s);
-           }
-         solv_free(altprefix);
-       }
-      queue_free(&q);
-      queue_free(&rq);
-    }
-  if ((resultflags & TESTCASE_RESULT_RULES) != 0)
-    {
-      /* dump all rules */
-      Id rid;
-      SolverRuleinfo rclass;
-      Queue q;
-      int i;
-
-      queue_init(&q);
-      for (rid = 1; (rclass = solver_ruleclass(solv, rid)) != SOLVER_RULE_UNKNOWN; rid++)
-       {
-         char *prefix;
-         switch (rclass)
-           {
-           case SOLVER_RULE_PKG:
-             prefix = "pkg ";
-             break;
-           case SOLVER_RULE_UPDATE:
-             prefix = "update ";
-             break;
-           case SOLVER_RULE_FEATURE:
-             prefix = "feature ";
-             break;
-           case SOLVER_RULE_JOB:
-             prefix = "job ";
-             break;
-           case SOLVER_RULE_DISTUPGRADE:
-             prefix = "distupgrade ";
-             break;
-           case SOLVER_RULE_INFARCH:
-             prefix = "infarch ";
-             break;
-           case SOLVER_RULE_CHOICE:
-             prefix = "choice ";
-             break;
-           case SOLVER_RULE_LEARNT:
-             prefix = "learnt ";
-             break;
-           case SOLVER_RULE_BEST:
-             prefix = "best ";
-             break;
-           case SOLVER_RULE_YUMOBS:
-             prefix = "yumobs ";
-             break;
-           default:
-             prefix = "unknown ";
-             break;
-           }
-         prefix = solv_dupjoin("rule ", prefix, testcase_ruleid(solv, rid));
-         solver_ruleliterals(solv, rid, &q);
-         if (rclass == SOLVER_RULE_FEATURE && q.count == 1 && q.elements[0] == -SYSTEMSOLVABLE)
-           continue;
-         for (i = 0; i < q.count; i++)
-           {
-             Id p = q.elements[i];
-             const char *s;
-             if (p < 0)
-               s = pool_tmpjoin(pool, prefix, " -", testcase_solvid2str(pool, -p));
-             else
-               s = pool_tmpjoin(pool, prefix, "  ", testcase_solvid2str(pool, p));
-             strqueue_push(&sq, s);
-           }
-         solv_free(prefix);
-       }
-      queue_free(&q);
-    }
-  if ((resultflags & TESTCASE_RESULT_GENID) != 0)
-    {
-      for (i = 0 ; i < solv->job.count; i += 2)
-       {
-         Id id, id2;
-         if (solv->job.elements[i] != (SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES))
-           continue;
-         id = solv->job.elements[i + 1];
-         s = testcase_dep2str(pool, id);
-         strqueue_push(&sq, pool_tmpjoin(pool, "genid dep ", s, 0));
-         if ((id2 = testcase_str2dep(pool, s)) != id)
-           {
-             s = pool_tmpjoin(pool, "genid roundtrip error: ", testcase_dep2str(pool, id2), 0);
-             strqueue_push(&sq, s);
-           }
-         dump_genid(pool, &sq, id, 1);
-       }
-    }
-  strqueue_sort(&sq);
-  result = strqueue_join(&sq);
-  strqueue_free(&sq);
-  return result;
-}
-
-
-int
-testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
-{
-  Pool *pool = solv->pool;
-  Repo *repo;
-  int i;
-  Id arch, repoid;
-  Id lowscore;
-  FILE *fp;
-  Strqueue sq;
-  char *cmd, *out;
-  const char *s;
-
-  if (!testcasename)
-    testcasename = "testcase.t";
-  if (!resultname)
-    resultname = "solver.result";
-
-  if (mkdir(dir, 0777) && errno != EEXIST)
-    {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not create directory '%s'\n", dir);
-      return 0;
-    }
-  strqueue_init(&sq);
-  FOR_REPOS(repoid, repo)
-    {
-      const char *name = testcase_repoid2str(pool, repoid);
-      char priobuf[50];
-      if (repo->subpriority)
-       sprintf(priobuf, "%d.%d", repo->priority, repo->subpriority);
-      else
-       sprintf(priobuf, "%d", repo->priority);
-      out = pool_tmpjoin(pool, name, ".repo", ".gz");
-      cmd = pool_tmpjoin(pool, "repo ", name, " ");
-      cmd = pool_tmpappend(pool, cmd, priobuf, " ");
-      cmd = pool_tmpappend(pool, cmd, "testtags ", out);
-      strqueue_push(&sq, cmd);
-      out = pool_tmpjoin(pool, dir, "/", out);
-      if (!(fp = solv_xfopen(out, "w")))
-       {
-         pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out);
-         strqueue_free(&sq);
-         return 0;
-       }
-      testcase_write_testtags(repo, fp);
-      if (fclose(fp))
-       {
-         pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
-         strqueue_free(&sq);
-         return 0;
-       }
-    }
-  /* hmm, this is not optimal... we currently search for the lowest score */
-  lowscore = 0;
-  arch = pool->solvables[SYSTEMSOLVABLE].arch;
-  for (i = 0; i < pool->lastarch; i++)
-    {
-      if (pool->id2arch[i] == 1 && !lowscore)
-       arch = i;
-      if (pool->id2arch[i] > 0x10000 && (!lowscore || pool->id2arch[i] < lowscore))
-       {
-         arch = i;
-         lowscore = pool->id2arch[i];
-       }
-    }
-  cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "unset", 0);
-  for (i = 0; disttype2str[i].str != 0; i++)
-    if (pool->disttype == disttype2str[i].type)
-      break;
-  pool_tmpappend(pool, cmd, " ", disttype2str[i].str ? disttype2str[i].str : "unknown");
-  if (pool->installed)
-    cmd = pool_tmpappend(pool, cmd, " ", testcase_repoid2str(pool, pool->installed->repoid));
-  strqueue_push(&sq, cmd);
-  s = testcase_getpoolflags(solv->pool);
-  if (*s)
-    {
-      cmd = pool_tmpjoin(pool, "poolflags ", s, 0);
-      strqueue_push(&sq, cmd);
-    }
-
-  if (pool->vendorclasses)
-    {
-      cmd = 0;
-      for (i = 0; pool->vendorclasses[i]; i++)
-       {
-         cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", pool->vendorclasses[i]);
-         if (!pool->vendorclasses[i + 1])
-           {
-             strqueue_push(&sq, cmd);
-             cmd = 0;
-             i++;
-           }
-       }
-    }
-
-  /* dump disabled packages (must come before the namespace/job lines) */
-  if (pool->considered)
-    {
-      Id p;
-      FOR_POOL_SOLVABLES(p)
-       if (!MAPTST(pool->considered, p))
-         {
-           cmd = pool_tmpjoin(pool, "disable pkg ", testcase_solvid2str(pool, p), 0);
-           strqueue_push(&sq, cmd);
-         }
-    }
-
-  s = testcase_getsolverflags(solv);
-  if (*s)
-    {
-      cmd = pool_tmpjoin(pool, "solverflags ", s, 0);
-      strqueue_push(&sq, cmd);
-    }
-
-  /* now dump all the ns callback values we know */
-  if (pool->nscallback)
-    {
-      Id rid;
-      int d;
-      for (rid = 1; rid < pool->nrels; rid++)
-       {
-         Reldep *rd = pool->rels + rid;
-         if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
-           continue;
-         /* evaluate all namespace ids, skip empty results */
-         d = pool_whatprovides(pool, MAKERELDEP(rid));
-         if (!d || !pool->whatprovidesdata[d])
-           continue;
-         cmd = pool_tmpjoin(pool, "namespace ", pool_id2str(pool, rd->name), "(");
-         cmd = pool_tmpappend(pool, cmd, pool_id2str(pool, rd->evr), ")");
-         for (;  pool->whatprovidesdata[d]; d++)
-           cmd = pool_tmpappend(pool, cmd, " ", testcase_solvid2str(pool, pool->whatprovidesdata[d]));
-         strqueue_push(&sq, cmd);
-       }
-    }
-
-  for (i = 0; i < solv->job.count; i += 2)
-    {
-      cmd = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]);
-      cmd = pool_tmpjoin(pool, "job ", cmd, 0);
-      strqueue_push(&sq, cmd);
-    }
-
-  if (resultflags)
-    {
-      char *result;
-      cmd = 0;
-      for (i = 0; resultflags2str[i].str; i++)
-       if ((resultflags & resultflags2str[i].flag) != 0)
-         cmd = pool_tmpappend(pool, cmd, cmd ? "," : 0, resultflags2str[i].str);
-      cmd = pool_tmpjoin(pool, "result ", cmd ? cmd : "?", 0);
-      cmd = pool_tmpappend(pool, cmd, " ", resultname);
-      strqueue_push(&sq, cmd);
-      result = testcase_solverresult(solv, resultflags);
-      if (!strcmp(resultname, "<inline>"))
-       {
-         int i;
-         Strqueue rsq;
-         strqueue_init(&rsq);
-         strqueue_split(&rsq, result);
-         for (i = 0; i < rsq.nstr; i++)
-           {
-             cmd = pool_tmpjoin(pool, "#>", rsq.str[i], 0);
-             strqueue_push(&sq, cmd);
-           }
-         strqueue_free(&rsq);
-       }
-      else
-       {
-         out = pool_tmpjoin(pool, dir, "/", resultname);
-         if (!(fp = fopen(out, "w")))
-           {
-             pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out);
-             solv_free(result);
-             strqueue_free(&sq);
-             return 0;
-           }
-         if (result && *result && fwrite(result, strlen(result), 1, fp) != 1)
-           {
-             pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
-             solv_free(result);
-             strqueue_free(&sq);
-             fclose(fp);
-             return 0;
-           }
-         if (fclose(fp))
-           {
-             pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
-             strqueue_free(&sq);
-             return 0;
-           }
-       }
-      solv_free(result);
-    }
-
-  cmd = strqueue_join(&sq);
-  out = pool_tmpjoin(pool, dir, "/", testcasename);
-  if (!(fp = fopen(out, "w")))
-    {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: could not open '%s' for writing\n", out);
-      strqueue_free(&sq);
-      return 0;
-    }
-  if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1)
-    {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
-      strqueue_free(&sq);
-      fclose(fp);
-      return 0;
-    }
-  if (fclose(fp))
-    {
-      pool_debug(solv->pool, SOLV_ERROR, "testcase_write: write error\n");
-      strqueue_free(&sq);
-      return 0;
-    }
-  solv_free(cmd);
-  strqueue_free(&sq);
-  return 1;
-}
-
-static char *
-read_inline_file(FILE *fp, char **bufp, char **bufpp, int *buflp)
-{
-  char *result = solv_malloc(1024);
-  char *rp = result;
-  int resultl = 1024;
-
-  for (;;)
-    {
-      size_t rl;
-      if (rp - result + 256 >= resultl)
-       {
-         resultl = rp - result;
-         result = solv_realloc(result, resultl + 1024);
-         rp = result + resultl;
-         resultl += 1024;
-       }
-      if (!fgets(rp, resultl - (rp - result), fp))
-       *rp = 0;
-      rl = strlen(rp);
-      if (rl && (rp == result || rp[-1] == '\n'))
-       {
-         if (rl > 1 && rp[0] == '#' && rp[1] == '>')
-           {
-             memmove(rp, rp + 2, rl - 2);
-             rl -= 2;
-           }
-         else
-           {
-             while (rl + 16 > *buflp)
-               {
-                 *bufp = solv_realloc(*bufp, *buflp + 512);
-                 *buflp += 512;
-               }
-             memmove(*bufp, rp, rl);
-             if ((*bufp)[rl - 1] == '\n')
-               {
-                 ungetc('\n', fp);
-                 rl--;
-               }
-             (*bufp)[rl] = 0;
-             (*bufpp) = *bufp + rl;
-             rl = 0;
-           }
-       }
-      if (rl <= 0)
-       {
-         *rp = 0;
-         break;
-       }
-      rp += rl;
-    }
-  return result;
-}
-
-static char *
-read_file(FILE *fp)
-{
-  char *result = solv_malloc(1024);
-  char *rp = result;
-  int resultl = 1024;
-
-  for (;;)
-    {
-      size_t rl;
-      if (rp - result + 256 >= resultl)
-       {
-         resultl = rp - result;
-         result = solv_realloc(result, resultl + 1024);
-         rp = result + resultl;
-         resultl += 1024;
-       }
-      rl = fread(rp, 1, resultl - (rp - result), fp);
-      if (rl <= 0)
-       {
-         *rp = 0;
-         break;
-       }
-      rp += rl;
-    }
-  return result;
-}
-
-static int
-str2resultflags(Pool *pool, char *s)   /* modifies the string! */
-{
-  int i, resultflags = 0;
-  while (s)
-    {
-      char *se = strchr(s, ',');
-      if (se)
-       *se++ = 0;
-      for (i = 0; resultflags2str[i].str; i++)
-       if (!strcmp(s, resultflags2str[i].str))
-         {
-           resultflags |= resultflags2str[i].flag;
-           break;
-         }
-      if (!resultflags2str[i].str)
-       pool_debug(pool, SOLV_ERROR, "result: unknown flag '%s'\n", s);
-      s = se;
-    }
-  return resultflags;
-}
-
-Solver *
-testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **resultp, int *resultflagsp)
-{
-  Solver *solv;
-  char *buf, *bufp;
-  int bufl;
-  char *testcasedir, *s;
-  int l;
-  char **pieces = 0;
-  int npieces = 0;
-  int prepared = 0;
-  int closefp = !fp;
-  int poolflagsreset = 0;
-  int missing_features = 0;
-  Id *genid = 0;
-  int ngenid = 0;
-
-  if (!fp && !(fp = fopen(testcase, "r")))
-    {
-      pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", testcase);
-      return 0;
-    }
-  testcasedir = solv_strdup(testcase);
-  if ((s = strrchr(testcasedir, '/')) != 0)
-    s[1] = 0;
-  else
-    *testcasedir = 0;
-  bufl = 1024;
-  buf = solv_malloc(bufl);
-  bufp = buf;
-  solv = 0;
-  for (;;)
-    {
-      if (bufp - buf + 16 > bufl)
-       {
-         bufl = bufp - buf;
-         buf = solv_realloc(buf, bufl + 512);
-         bufp = buf + bufl;
-          bufl += 512;
-       }
-      if (!fgets(bufp, bufl - (bufp - buf), fp))
-       break;
-      bufp = buf;
-      l = strlen(buf);
-      if (!l || buf[l - 1] != '\n')
-       {
-         bufp += l;
-         continue;
-       }
-      buf[--l] = 0;
-      s = buf;
-      while (*s && (*s == ' ' || *s == '\t'))
-       s++;
-      if (!*s || *s == '#')
-       continue;
-      npieces = 0;
-      /* split it in pieces */
-      for (;;)
-       {
-         while (*s == ' ' || *s == '\t')
-           s++;
-         if (!*s)
-           break;
-         pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
-         pieces[npieces++] = s;
-         while (*s && *s != ' ' && *s != '\t')
-           s++;
-         if (*s)
-           *s++ = 0;
-       }
-      pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
-      pieces[npieces] = 0;
-      if (!strcmp(pieces[0], "repo") && npieces >= 4)
-       {
-         Repo *repo = repo_create(pool, pieces[1]);
-         FILE *rfp;
-         int prio, subprio;
-         const char *rdata;
-
-         prepared = 0;
-          if (!poolflagsreset)
-           {
-             poolflagsreset = 1;
-             testcase_resetpoolflags(pool);    /* hmm */
-           }
-         if (sscanf(pieces[2], "%d.%d", &prio, &subprio) != 2)
-           {
-             subprio = 0;
-             prio = atoi(pieces[2]);
-           }
-          repo->priority = prio;
-          repo->subpriority = subprio;
-         if (strcmp(pieces[3], "empty") != 0)
-           {
-             const char *repotype = pool_tmpjoin(pool, pieces[3], 0, 0);       /* gets overwritten in <inline> case */
-             if (!strcmp(pieces[4], "<inline>"))
-               {
-                 char *idata = read_inline_file(fp, &buf, &bufp, &bufl);
-                 rdata = "<inline>";
-                 rfp = solv_xfopen_buf(rdata, &idata, 0, "rf");
-               }
-             else
-               {
-                 rdata = pool_tmpjoin(pool, testcasedir, pieces[4], 0);
-                 rfp = solv_xfopen(rdata, "r");
-               }
-             if (!rfp)
-               {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata);
-               }
-             else if (!strcmp(repotype, "testtags"))
-               {
-                 testcase_add_testtags(repo, rfp, 0);
-                 fclose(rfp);
-               }
-             else if (!strcmp(repotype, "solv"))
-               {
-                 repo_add_solv(repo, rfp, 0);
-                 fclose(rfp);
-               }
-#if 0
-             else if (!strcmp(repotype, "helix"))
-               {
-                 extern int repo_add_helix(Repo *repo, FILE *fp, int flags);
-                 repo_add_helix(repo, rfp, 0);
-                 fclose(rfp);
-               }
-#endif
-             else
-               {
-                 fclose(rfp);
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: unknown repo type for repo '%s'\n", repo->name);
-               }
-           }
-       }
-      else if (!strcmp(pieces[0], "system") && npieces >= 3)
-       {
-         int i;
-
-         /* must set the disttype before the arch */
-         prepared = 0;
-         if (strcmp(pieces[2], "*") != 0)
-           {
-             char *dp = pieces[2];
-             while (dp && *dp)
-               {
-                 char *dpe = strchr(dp, ',');
-                 if (dpe)
-                   *dpe = 0;
-                 for (i = 0; disttype2str[i].str != 0; i++)
-                   if (!strcmp(disttype2str[i].str, dp))
-                     break;
-                 if (dpe)
-                   *dpe++ = ',';
-                 if (disttype2str[i].str)
-                   {
-#ifdef MULTI_SEMANTICS
-                     if (pool->disttype != disttype2str[i].type)
-                       pool_setdisttype(pool, disttype2str[i].type);
-#endif
-                     if (pool->disttype == disttype2str[i].type)
-                       break;
-                   }
-                 dp = dpe;
-               }
-             if (!(dp && *dp))
-               {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: system: could not change disttype to '%s'\n", pieces[2]);
-                 missing_features = 1;
-               }
-           }
-         if (strcmp(pieces[1], "unset") == 0)
-           pool_setarch(pool, 0);
-         else if (pieces[1][0] == ':')
-           pool_setarchpolicy(pool, pieces[1] + 1);
-         else
-           pool_setarch(pool, pieces[1]);
-         if (npieces > 3)
-           {
-             Repo *repo = testcase_str2repo(pool, pieces[3]);
-             if (!repo)
-               pool_debug(pool, SOLV_ERROR, "testcase_read: system: unknown repo '%s'\n", pieces[3]);
-             else
-               pool_set_installed(pool, repo);
-           }
-       }
-      else if (!strcmp(pieces[0], "job") && npieces > 1)
-       {
-         char *sp;
-         Id how, what;
-         if (prepared <= 0)
-           {
-             pool_addfileprovides(pool);
-             pool_createwhatprovides(pool);
-             prepared = 1;
-           }
-         if (npieces >= 3 && !strcmp(pieces[2], "selection"))
-           {
-             addselectionjob(pool, pieces + 1, npieces - 1, job);
-             continue;
-           }
-         /* rejoin */
-         for (sp = pieces[1]; sp < pieces[npieces - 1]; sp++)
-           if (*sp == 0)
-             *sp = ' ';
-         how = testcase_str2job(pool, pieces[1], &what);
-         if (how >= 0 && job)
-           queue_push2(job, how, what);
-       }
-      else if (!strcmp(pieces[0], "vendorclass") && npieces > 1)
-       {
-         pool_addvendorclass(pool, (const char **)(pieces + 1));
-       }
-      else if (!strcmp(pieces[0], "namespace") && npieces > 1)
-       {
-         int i = strlen(pieces[1]);
-         s = strchr(pieces[1], '(');
-         if (!s && pieces[1][i - 1] != ')')
-           {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: bad namespace '%s'\n", pieces[1]);
-           }
-         else
-           {
-             Id name, evr, id;
-             Queue q;
-             queue_init(&q);
-             *s = 0;
-             pieces[1][i - 1] = 0;
-             name = pool_str2id(pool, pieces[1], 1);
-             evr = pool_str2id(pool, s + 1, 1);
-             *s = '(';
-             pieces[1][i - 1] = ')';
-             id = pool_rel2id(pool, name, evr, REL_NAMESPACE, 1);
-             for (i = 2; i < npieces; i++)
-               queue_push(&q, testcase_str2solvid(pool, pieces[i]));
-             /* now do the callback */
-             if (prepared <= 0)
-               {
-                 pool_addfileprovides(pool);
-                 pool_createwhatprovides(pool);
-                 prepared = 1;
-               }
-             pool->whatprovides_rel[GETRELID(id)] = pool_queuetowhatprovides(pool, &q);
-             queue_free(&q);
-           }
-       }
-      else if (!strcmp(pieces[0], "poolflags"))
-        {
-         int i;
-          if (!poolflagsreset)
-           {
-             poolflagsreset = 1;
-             testcase_resetpoolflags(pool);    /* hmm */
-           }
-         for (i = 1; i < npieces; i++)
-           testcase_setpoolflags(pool, pieces[i]);
-        }
-      else if (!strcmp(pieces[0], "solverflags") && npieces > 1)
-        {
-         int i;
-         if (!solv)
-           {
-             solv = solver_create(pool);
-             testcase_resetsolverflags(solv);
-           }
-         for (i = 1; i < npieces; i++)
-           testcase_setsolverflags(solv, pieces[i]);
-        }
-      else if (!strcmp(pieces[0], "result") && npieces > 1)
-       {
-         char *result = 0;
-         int resultflags = str2resultflags(pool, pieces[1]);
-         const char *rdata;
-         if (npieces > 2)
-           {
-             rdata = pool_tmpjoin(pool, testcasedir, pieces[2], 0);
-             if (!strcmp(pieces[2], "<inline>"))
-               result = read_inline_file(fp, &buf, &bufp, &bufl);
-             else
-               {
-                 FILE *rfp = fopen(rdata, "r");
-                 if (!rfp)
-                   pool_debug(pool, SOLV_ERROR, "testcase_read: could not open '%s'\n", rdata);
-                 else
-                   {
-                     result = read_file(rfp);
-                     fclose(rfp);
-                   }
-               }
-           }
-         if (resultp)
-           *resultp = result;
-         else
-           solv_free(result);
-         if (resultflagsp)
-           *resultflagsp = resultflags;
-       }
-      else if (!strcmp(pieces[0], "nextjob") && npieces == 1)
-       {
-         break;
-       }
-      else if (!strcmp(pieces[0], "disable") && npieces == 3)
-       {
-         Id p;
-         if (strcmp(pieces[1], "pkg"))
-           {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: bad disable type '%s'\n", pieces[1]);
-             continue;
-           }
-         if (!prepared)
-           pool_createwhatprovides(pool);
-         prepared = -1;
-         if (!pool->considered)
-           {
-             pool->considered = solv_calloc(1, sizeof(Map));
-             map_init(pool->considered, pool->nsolvables);
-             map_setall(pool->considered);
-           }
-         p = testcase_str2solvid(pool, pieces[2]);
-         if (p)
-           MAPCLR(pool->considered, p);
-         else
-           pool_debug(pool, SOLV_ERROR, "disable: unknown package '%s'\n", pieces[2]);
-       }
-      else if (!strcmp(pieces[0], "feature"))
-       {
-         int i, j;
-         for (i = 1; i < npieces; i++)
-           {
-             for (j = 0; features[j]; j++)
-               if (!strcmp(pieces[i], features[j]))
-                 break;
-             if (!features[j])
-               {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: missing feature '%s'\n", pieces[i]);
-                 missing_features++;
-               }
-           }
-         if (missing_features)
-           break;
-       }
-      else if (!strcmp(pieces[0], "genid") && npieces > 1)
-       {
-         Id id;
-         /* rejoin */
-         if (npieces > 2)
-           {
-             char *sp;
-             for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
-               if (*sp == 0)
-                 *sp = ' ';
-           }
-         genid = solv_extend(genid, ngenid, 1, sizeof(*genid), 7);
-         if (!strcmp(pieces[1], "op") && npieces > 2)
-           {
-             struct oplist *op;
-             for (op = oplist; op->flags; op++)
-               if (!strncmp(pieces[2], op->opname, strlen(op->opname)))
-                 break;
-             if (!op->flags)
-               {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown op '%s'\n", pieces[2]);
-                 break;
-               }
-             if (ngenid < 2)
-               {
-                 pool_debug(pool, SOLV_ERROR, "testcase_read: genid: out of stack\n");
-                 break;
-               }
-             ngenid -= 2;
-             id = pool_rel2id(pool, genid[ngenid] , genid[ngenid + 1], op->flags, 1);
-           }
-         else if (!strcmp(pieces[1], "lit"))
-           id = pool_str2id(pool, npieces > 2 ? pieces[2] : "", 1);
-         else if (!strcmp(pieces[1], "null"))
-           id = 0;
-         else if (!strcmp(pieces[1], "dep"))
-           id = testcase_str2dep(pool, pieces[2]);
-         else
-           {
-             pool_debug(pool, SOLV_ERROR, "testcase_read: genid: unknown command '%s'\n", pieces[1]);
-             break;
-           }
-         genid[ngenid++] = id;
-       }
-      else
-       {
-         pool_debug(pool, SOLV_ERROR, "testcase_read: cannot parse command '%s'\n", pieces[0]);
-       }
-    }
-  while (job && ngenid > 0)
-    queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, genid[--ngenid]);
-  genid = solv_free(genid);
-  buf = solv_free(buf);
-  pieces = solv_free(pieces);
-  solv_free(testcasedir);
-  if (!prepared)
-    {
-      pool_addfileprovides(pool);
-      pool_createwhatprovides(pool);
-    }
-  if (!solv)
-    {
-      solv = solver_create(pool);
-      testcase_resetsolverflags(solv);
-    }
-  if (closefp)
-    fclose(fp);
-  if (missing_features)
-    {
-      solver_free(solv);
-      solv = 0;
-      if (resultflagsp)
-       *resultflagsp = 77;     /* hack for testsolv */
-    }
-  return solv;
-}
-
-char *
-testcase_resultdiff(const char *result1, const char *result2)
-{
-  Strqueue sq1, sq2, osq;
-  char *r;
-  strqueue_init(&sq1);
-  strqueue_init(&sq2);
-  strqueue_init(&osq);
-  strqueue_split(&sq1, result1);
-  strqueue_split(&sq2, result2);
-  strqueue_sort(&sq1);
-  strqueue_sort(&sq2);
-  strqueue_diff(&sq1, &sq2, &osq);
-  r = osq.nstr ? strqueue_join(&osq) : 0;
-  strqueue_free(&sq1);
-  strqueue_free(&sq2);
-  strqueue_free(&osq);
-  return r;
-}
-
diff --git a/libsolv-0.6.15/ext/testcase.h b/libsolv-0.6.15/ext/testcase.h
deleted file mode 100644 (file)
index 4903e6c..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include "pool.h"
-#include "repo.h"
-#include "solver.h"
-
-#define TESTCASE_RESULT_TRANSACTION    (1 << 0)
-#define TESTCASE_RESULT_PROBLEMS       (1 << 1)
-#define TESTCASE_RESULT_ORPHANED       (1 << 2)
-#define TESTCASE_RESULT_RECOMMENDED    (1 << 3)
-#define TESTCASE_RESULT_UNNEEDED       (1 << 4)
-#define TESTCASE_RESULT_ALTERNATIVES   (1 << 5)
-#define TESTCASE_RESULT_RULES          (1 << 6)
-#define TESTCASE_RESULT_GENID          (1 << 7)
-
-extern Id testcase_str2dep(Pool *pool, const char *s);
-extern const char *testcase_dep2str(Pool *pool, Id id);
-extern const char *testcase_repoid2str(Pool *pool, Id repoid);
-extern const char *testcase_solvid2str(Pool *pool, Id p);
-extern Repo *testcase_str2repo(Pool *pool, const char *str);
-extern Id testcase_str2solvid(Pool *pool, const char *str);
-extern const char *testcase_job2str(Pool *pool, Id how, Id what);
-extern Id testcase_str2job(Pool *pool, const char *str, Id *whatp);
-extern int testcase_write_testtags(Repo *repo, FILE *fp);
-extern int testcase_add_testtags(Repo *repo, FILE *fp, int flags);
-extern const char *testcase_getsolverflags(Solver *solv);
-extern int testcase_setsolverflags(Solver *solv, const char *str);
-extern void testcase_resetsolverflags(Solver *solv);
-extern char *testcase_solverresult(Solver *solv, int flags);
-extern int testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname);
-extern Solver *testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **resultp, int *resultflagsp);
-extern char *testcase_resultdiff(const char *result1, const char *result2);
diff --git a/libsolv-0.6.15/ext/tools_util.h b/libsolv-0.6.15/ext/tools_util.h
deleted file mode 100644 (file)
index cc64892..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * util.h
- *
- */
-
-#ifndef LIBSOLV_TOOLS_UTIL_H
-#define LIBSOLV_TOOLS_UTIL_H
-
-static inline Id
-makeevr(Pool *pool, const char *s)
-{
-  if (!strncmp(s, "0:", 2) && s[2])
-    s += 2;
-  return pool_str2id(pool, s, 1);
-}
-
-/**
- * split a string
- */
-#ifndef DISABLE_SPLIT
-static int
-split(char *l, char **sp, int m)
-{
-  int i;
-  for (i = 0; i < m;)
-    {
-      while (*l == ' ')
-        l++;
-      if (!*l)
-        break;
-      sp[i++] = l;
-      while (*l && *l != ' ')
-        l++;
-      if (!*l)
-        break;
-      *l++ = 0;
-    }
-  return i;
-}
-#endif
-
-#ifndef DISABLE_JOIN2
-
-struct joindata {
-  char *tmp;
-  int tmpl;
-};
-
-/* this join does not depend on parsedata */
-static char *
-join2(struct joindata *jd, const char *s1, const char *s2, const char *s3)
-{
-  int l = 1;
-  char *p;
-
-  if (s1)
-    l += strlen(s1);
-  if (s2)
-    l += strlen(s2);
-  if (s3)
-    l += strlen(s3);
-  if (l > jd->tmpl)
-    {
-      jd->tmpl = l + 256;
-      jd->tmp = solv_realloc(jd->tmp, jd->tmpl);
-    }
-  p = jd->tmp;
-  if (s1)
-    {
-      strcpy(p, s1);
-      p += strlen(s1);
-    }
-  if (s2)
-    {
-      strcpy(p, s2);
-      p += strlen(s2);
-    }
-  if (s3)
-    {
-      strcpy(p, s3);
-      p += strlen(s3);
-    }
-  *p = 0;
-  return jd->tmp;
-}
-
-static inline char *
-join_dup(struct joindata *jd, const char *s)
-{
-  return s ? join2(jd, s, 0, 0) : 0;
-}
-
-static inline void
-join_freemem(struct joindata *jd)
-{
-  if (jd->tmp)
-    free(jd->tmp);
-  jd->tmp = 0;
-  jd->tmpl = 0;
-}
-
-#endif
-
-#endif /* LIBSOLV_TOOLS_UTIL_H */
diff --git a/libsolv-0.6.15/libsolv.pc.in b/libsolv-0.6.15/libsolv.pc.in
deleted file mode 100644 (file)
index c82dfc4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-libdir=@LIB_INSTALL_DIR@
-includedir=@INCLUDE_INSTALL_DIR@
-
-Name: libsolv
-Description: Library for solving packages and reading repositories
-Version: @VERSION@
-Libs: -L${libdir} -lsolvext -lsolv
-Cflags: -I${includedir}
diff --git a/libsolv-0.6.15/package/libsolv.changes b/libsolv-0.6.15/package/libsolv.changes
deleted file mode 100644 (file)
index 8714d4a..0000000
+++ /dev/null
@@ -1,1338 +0,0 @@
--------------------------------------------------------------------
-Mon Dec 14 15:48:01 CET 2015 - mls@suse.de
-
-- change product links to also look at timestamps [bnc#956443]
-- rework multiversion orphaned handling [bnc#957606]
-- support key type changes in repodata_internalize()
-- allow serialization of REPOKEY_TYPE_DELETED
-- improve appdata handling of installed packages
-- improve performance when run under xen
-- bump version to 0.6.15
-
--------------------------------------------------------------------
-Mon Oct  5 13:27:25 CEST 2015 - mls@suse.de
-
-- fix bug in recommends handling [bnc#948482]
-- also check installed packages in multiversion handling
-- fix build on Mageia
-- bump version to 0.6.14
-
--------------------------------------------------------------------
-Fri Sep 25 11:54:02 CEST 2015 - mls@suse.de
-
-- support a generic string for pattern-visible() [bnc#900769]
-- add a SOLVER_ALLOWUNINSTALL job type
-- add ordercycle introspection
-- fix mkmask handling of a zero size
-- support 'recommends' in repo_mdk.c
-- support filelist parsing in installcheck
-- bump version to 0.6.13
-
--------------------------------------------------------------------
-Tue Sep  1 13:37:11 CEST 2015 - mls@suse.de
-
-- added tcl bindings
-- improve debian ar archive handling
-- bindings: set the CLOEXEC flags in xfopen
-- bindings: support testcase writing [bnc#946752]
-- support REL_ELSE as evr of REL_COND
-- bump version to 0.6.12
-
--------------------------------------------------------------------
-Tue Jun  2 11:41:10 CEST 2015 - mls@suse.de
-
-- add forgotten sha-512 support to data_skip
-- speed up whatprovides lookup with a new helper array
-- fix dup with allowuninstall
-- improve alreadyinstalled handling of supplements
-- some code cleanup
-- bump version to 0.6.11
-
--------------------------------------------------------------------
-Sat May  2 11:44:08 UTC 2015 - mrueckert@suse.de
-
-- you really want to use rbconfig there
-
--------------------------------------------------------------------
-Wed Mar 18 11:04:34 CET 2015 - mls@suse.de
-
-- fix bug in dislike_old_versions that could lead to a segfault
-  [bnc#922352]
-- bump version to 0.6.10
-
--------------------------------------------------------------------
-Mon Mar  9 16:42:35 CET 2015 - mls@suse.de
-
-- rework splitprovides handling [bnc#921332]
-- improve package choosing code
-- new testcase dependency format
-- add alternatives introspection
-- make reorder_dq_for_jobrules also look at recommends/suggests
-- rework branch handling
-- add parser for rpm rich deps
-- bump version to 0.6.9
-
--------------------------------------------------------------------
-Wed Jan 14 08:58:46 CET 2015 - ma@suse.de
-
-- fixes to build with swig 3.0.3
-- bump version to 0.6.8
-
--------------------------------------------------------------------
-Fri Dec 19 08:59:27 CET 2014 - ma@suse.de
-
-- add product:regflavor attribute [bnc#896224]
-- bump version to 0.6.7
-
--------------------------------------------------------------------
-Tue Oct  7 14:39:23 CEST 2014 - mls@suse.de
-
-- fix bug in reorder_dq_for_jobrules leading to crashes
-  [bnc#899907]
-- rename rpm rules to pkg rules
-- add manpages for the tools
-- bump version to 0.6.6
-
--------------------------------------------------------------------
-Thu Sep 11 17:33:04 CEST 2014 - mls@suse.de
-
-- support DUCHANGES_ONLYADD flag in diskusage calculation
-  [bnc#783100]
-- add whatmatchesdep to bindings
-- support pool->considered in testcases
-- always call selection_filelist if SELECTION_FILELIST is set
-- support yum style obsolete handling for package splits
-- bump version to 0.6.5
-
--------------------------------------------------------------------
-Tue Jul  8 14:13:40 CEST 2014 - mls@suse.de
-
-- expand solver_identical fix to applications [bnc#885830]
-- fix instbuddy generation code
-- improve autominimizing implementation to also look at
-  supplements
-- bump version to 0.6.4
-
--------------------------------------------------------------------
-Fri Jun 13 08:28:12 CEST 2014 - ma@suse.de
-
-- quick fix for [bnc#881320]
-- bump version to 0.6.3
-
--------------------------------------------------------------------
-Fri Jun  6 11:37:00 CEST 2014 - ma@suse.de
-
-- Provide PRODUCT_REGISTER_TARGET for available products [bnc#881320]
-- bump version to 0.6.2
-
--------------------------------------------------------------------
-Thu Apr 17 14:47:42 CEST 2014 - mls@suse.de
-
-- support BREAK_ORPHANS and KEEP_ORPHANS solver flags
-- adapt to AppStream 0.6
-- reduce memory usage in repo_write and repodata_internalize
-- make repodata_stringify return the result string
-- bump version to 0.6.1
-
--------------------------------------------------------------------
-Mon Apr  7 15:36:07 CEST 2014 - mls@suse.de
-
-- add support for sha224/sha384/sha512
-- add userinstalled helper functions
-- improve dataiterator bindings (in an incompatible way)
-- automatically free pool in bindings
-- bump version to 0.6.0 (ABI + bindings API breakage)
-
--------------------------------------------------------------------
-Wed Mar 26 15:08:46 CET 2014 - mls@suse.de
-
-- fix handling of packages with no update/feature rule [bnc#870195]
-- fix crash when in internalize() when the schemadata gets
-  reallocated
-- fix access to uninitialized memory in repo_empty()
-- a couple of optimizations
-- support REPOKEYWORDS in content parser
-- bindings: don't let str(Datamatch) change the strings
-- fix basename optimization for STRINGEND
-- bump version to 0.5.1
-
--------------------------------------------------------------------
-Wed Feb 26 15:08:35 CET 2014 - mls@suse.de
-
-- improve appdata.xml parsing [bnc#865293]
-- repo_helix: parse application elements
-- bump version to 0.5.0
-
--------------------------------------------------------------------
-Fri Feb 21 16:23:58 CET 2014 - mls@suse.de
-
-- fix bug in solver_get_unneeded that could lead to an
-  endless loop [bnc#828764]
-- adapt to new rpm tags for weak dependencies
-- fix pseudo packages obsoleting other pseudo packages
-- optimize unfulfilled rule handling a bit
-- bump version to 0.4.5
-
--------------------------------------------------------------------
-Fri Feb 14 11:03:18 CET 2014 - mls@suse.de
-
-- always keep job/jobflags in selection_filter()
-- implement COND handling in supplements/enhances
-- improve OR handling in supplements/enhances
-- fix typo in application backlink creation
-- support PRODUCT_ENDOFLIFE
-- store repoid as flexarray
-- also translate autoproduct strings
-- bump version to 0.4.4
-
--------------------------------------------------------------------
-Mon Jan 27 17:15:41 CET 2014 - mls@suse.de
-
-- add support for autogenerated products
-- support repoid array in product definition
-- bump version to 0.4.3
-
--------------------------------------------------------------------
-Fri Jan 24 13:50:03 CET 2014 - mls@suse.de
-
-- add -X option to susetags2solv [bnc#860271]
-- fix typos in pool_job2str
-- support DISTRO in content parser
-- make addfilelist more resistant against corrupt rpms
-- encode flags into rpmdb cookie
-- add identical and evrcmp methods in bindings
-- copy checksums in repo_add_rpmdb_reffp
-- repo_autopattern: make sure that the category is valid utf8
-- fix double-free if the number of languages is reduced to zero
-- bump version to 0.4.2
-
--------------------------------------------------------------------
-Mon Dec  9 11:53:06 CET 2013 - mls@suse.de
-
-- make repo2solv.sh work when appdata support is off
-- enable appdata support for SUSE
-
--------------------------------------------------------------------
-Tue Dec  3 14:30:17 CET 2013 - mls@suse.de
-
-- support appdata parsing and auto-pattern generation in tools
-- adapt to python3
-- tweak findproblemrule heuristic for conflicts
-- add m68k/ppc64le architectures
-- plug weakrulemap memory hole
-- support debian multiarch annotation
-- support product/pattern/application links
-- bump version to 0.4.1
-
--------------------------------------------------------------------
-Tue Sep 24 11:14:25 CEST 2013 - mls@suse.de
-
-- do not add back cleandeps_updatepkgs packages [bnc#841781]
-
--------------------------------------------------------------------
-Mon Sep 23 11:31:28 CEST 2013 - mls@suse.de
-
-- added repodata_lookup_binary
-- fix pattern obsoleting real packages [bnc#834376]
-- add selection_make_matchdeps function to query dependencies
-  other than provides
-- bump version to 0.4.0
-
--------------------------------------------------------------------
-Wed Aug 21 14:39:54 CEST 2013 - mls@suse.de
-
-- add describe_decision() and unset() methods to bindings
-- do recommends pruning after selecting the highest versions
-- improve filelist handling
-- be more tolerant about bad xml: an empty epoch attribute means no epoch
-- fix another edge case will dup mode and multiversion packages [bnc#828389]
-- bring installcheck up to speed
-
--------------------------------------------------------------------
-Mon Jun 17 15:54:44 CEST 2013 - mls@suse.de
-
-- add SOLVER_RULE_JOB_UNSUPPORTED and SOLVER_RULE_JOB_UNKNOWN_PACKAGE
-  for better problem reporting
-- start with library documentation
-- adapt to obsoletes handling of new rpm versions
-
--------------------------------------------------------------------
-Wed Mar  6 16:55:57 CET 2013 - mls@suse.de
-
-- fix dataiterator returning random data in some cases
-- add changelog parser
-- fix nasty bug in selection_filter_rel
-- allow re-run of an existing solver
-- bump version to 0.3.0
-
--------------------------------------------------------------------
-Mon Jan 14 16:01:04 CET 2013 - mls@suse.de
-
-- trivial_installable: check vendor of affected package to see if
-  a patch should be ignored [bnc#736100]
-- fix trivial installable requires handling
-- bump version to 0.2.4
-
--------------------------------------------------------------------
-Tue Dec 18 19:20:19 CET 2012 - mls@suse.de
-
-- fix potential access to freed memory
-- improve find_problemrule speed
-- add support for special namespaceprovides jobs
-- bump version to 0.2.3
-
--------------------------------------------------------------------
-Wed Dec  5 14:37:39 CET 2012 - mls@suse.de
-
-- many Selection improvements
-- fix perl binding memory issue
-- improve file list matching
-- support targeted up/dup with cleandeps
-- bump version to 0.2.2
-
--------------------------------------------------------------------
-Fri Nov 23 13:57:19 CET 2012 - mls@suse.de
-
-- support targeted up/dup
-- support best rules to enforce the installation of the best package
-- implement selection class to ease package selection
-- fix obsolete handling for debian packages
-- add pool_lookup_deltalocation helper
-- bump version to 0.2.1
-
--------------------------------------------------------------------
-Thu Oct 18 16:58:10 CEST 2012 - mls@suse.de
-
-- fix susetags parser, it ignored the filelist of the last
-  solvable
-- fix encoding of large values
-- bump version to 0.2.0
-
--------------------------------------------------------------------
-Mon Jun 25 13:40:58 CEST 2012 - mls@suse.de
-
-- fix typo in repodata_merge_attrs [bnc#767510]
-
--------------------------------------------------------------------
-Wed May 30 14:46:48 CEST 2012 - mls@suse.de
-
-- fix build for older suse versions
-- fix memory corruption in unneeded calculation when there are
-  product buddies
-
--------------------------------------------------------------------
-Tue May  8 10:59:39 CEST 2012 - ma@suse.de
-
-- build with swig-2.0.6
-
--------------------------------------------------------------------
-Mon Apr 23 15:52:26 CEST 2012 - mls@suse.de
-
-- added testcase framework
-- add solver_get_unneeded() to get a list of no longer needed
-  installed packages
-- changed duprule generation to ignore uninstallable packages [bnc#750485]
-- fix memory leaks
-- speed up whatprovides generation
-- support 64bit nums, return files sizes in bytes
-- return errors instead of calling exit()
-- support tilde in rpm version comparison [bnc#466994]
-- 0.1.0
-
--------------------------------------------------------------------
-Tue Feb  7 16:33:10 CET 2012 - mls@suse.de
-
-- add findutils to the requires of libsolv-tools [bnc#743634]
-
--------------------------------------------------------------------
-Wed Feb  1 14:06:59 CET 2012 - mls@suse.de
-
-- add cleandeps support for install/update
-- check for cleandeps mistakes (untested)
-
--------------------------------------------------------------------
-Fri Jan 27 14:10:34 CET 2012 - mls@suse.de
-
-- make repo type code selection modular
-- add more solvable_ functions
-- add dependency getter/setter code to bindings
-- cleanup dup handling
-- hide more internals
-
--------------------------------------------------------------------
-Mon Oct 24 13:26:18 CEST 2011 - ma@suse.de
-
-- mls fixed package provides/obsoletes, but forgot to write
-  a changes entry.
-
--------------------------------------------------------------------
-Tue Oct 18 16:18:39 CEST 2011 - ma@suse.de
-
-- Add arch arvm7tnhl and  armv7thl
-
--------------------------------------------------------------------
-Fri Apr 29 14:35:59 CEST 2011 - mls@suse.de
-
-- bup version to 0.17.0 to make it different from 11.4
-- 0.17.0
-
--------------------------------------------------------------------
-Thu Mar 24 10:04:16 UTC 2011 - mls@suse.de
-
-- add missing else part in rpmdbid2db()
-
--------------------------------------------------------------------
-Thu Feb 24 17:44:05 CET 2011 - mls@suse.de
-
-- ignore to be dropped orhaned packages when calculating
-  candidates for recommends/supplements installation
-
--------------------------------------------------------------------
-Wed Feb  2 09:24:42 UTC 2011 - kkaempf@novell.com
-
-- Split off 'applayer' and 'bindings' as a separate package
-  to make the bindings more independant of libsatsolver
-- 0.16.4
-
--------------------------------------------------------------------
-Tue Jan 25 09:52:48 CET 2011 - ma@suse.de
-
-- Apply patch introducing armv7nhl:armv7h
-
--------------------------------------------------------------------
-Fri Oct 22 15:51:11 CEST 2010 - ma@suse.de
-
-- updateinfoxml: Correctly parse 'issued date' field.
-- 0.16.1
-
--------------------------------------------------------------------
-Thu Sep  9 17:30:36 CEST 2010 - mls@suse.de
-
-- bump version to 0.16 to make it different from code11_3 branch
-- 0.16.0
-
--------------------------------------------------------------------
-Mon Sep  6 13:50:02 UTC 2010 - dmacvicar@novell.com
-
-- ruby bindings: fix bugs regarding include path loading
-  (was hardcoded) and refactor the way the library path is defined
-  (only once in a helper)
-
--------------------------------------------------------------------
-Mon Sep  6 12:38:21 UTC 2010 - dmacvicar@novell.com
-
-- SLE10SP3 also has vendor_ruby
-
--------------------------------------------------------------------
-Wed Aug 18 14:11:08 UTC 2010 - kkaempf@novell.com
-
-- refactor ruby-satsolver, pure-Ruby extensions added
-- 0.15.1
-
--------------------------------------------------------------------
-Thu May  6 17:39:20 CEST 2010 - mls@suse.de
-
-- fix bug in cleandeps code
-- bump version to 0.15 to make it different from code11_2 branch
-- 0.15.0
-
--------------------------------------------------------------------
-Tue Mar 23 17:24:46 CET 2010 - ma@suse.de
-
-- Parse an installed products <shortsummary> tag [bnc#586303]
-
--------------------------------------------------------------------
-Mon Mar 22 18:45:42 CET 2010 - mls@suse.de
-
-- dataiterator: reset parent when jumping to a solvid [bnc#589640]
-- 0.14.17
-
--------------------------------------------------------------------
-Thu Mar 11 22:13:26 CET 2010 - ma@suse.de
-
-- parse global repository ids. [bnc#377568]
-- fix pattern parsing in repomd format. [bnc#585000]
-- 0.14.16
-
--------------------------------------------------------------------
-Thu Mar 11 12:18:23 CET 2010 - mls@suse.de
-
-- fix language code lookup for fallback languages [bnc#584644]
-- change solvable_lookup_str_lang interface a bit for libzypp
-
--------------------------------------------------------------------
-Fri Feb 19 17:31:51 CET 2010 - mls@suse.de
-
-- make dup rules work when system repo is not first [bnc#581276]
-- parse pattern visibility flag in repomd format
-- 0.14.15
-
--------------------------------------------------------------------
-Fri Jan 29 14:48:34 CET 2010 - mls@suse.de
-
-- speed up createwhatprovides when many solvables provide the same dep
-- fix choice rule creation for real (bnc#551637)
-- 0.14.14
-
--------------------------------------------------------------------
-Mon Jan 18 14:42:27 CET 2010 - mls@suse.de
-
-- set repository:toolversion to 1.0 in common_write
-- 0.14.13
-
--------------------------------------------------------------------
-Mon Dec 21 14:29:24 CET 2009 - mls@suse.de
-
-- disable update rule in noobsoletes case if installed package is to
-  be kept [bnc#564239]
-- work around rpm bug when --prefix is used [bnc#565525]
-- add support for sparc architecture [bnc#566291]
-- 0.14.12
-
--------------------------------------------------------------------
-Mon Dec  7 13:59:08 CET 2009 - ma@suse.de
-
-- Support optionally compressed product(s).xml in rpmmd metadata.
-- 0.14.11
-
--------------------------------------------------------------------
-Mon Nov  2 14:10:23 CET 2009 - mls@suse.de
-
-- look at infarch/dup rules when creating choice rules, makes dup
-  also install 32bit packages [bnc#551637]
-- 0.14.10
-
--------------------------------------------------------------------
-Wed Oct 14 16:21:32 CEST 2009 - mls@suse.de
-
-- ignore products element so that repo2solv works
-- support MULTI_SEMANTICS
-- add --withsrc option for installcheck
-- add SOLVER_DROP_ORPHANED job type
-- fix dropped package handling in removedisabledconflicts
-- 0.14.9
-
--------------------------------------------------------------------
-Thu Sep 24 10:27:42 CEST 2009 - mls@suse.de
-
-- fix bug in solvable_lookup_str_base
-
--------------------------------------------------------------------
-Wed Sep 23 11:10:08 CEST 2009 - mls@suse.de
-
-- get missing translations from other solvables [bnc#386449]
-- also look at triggers when ordering packages
-- add support for REPOKEY_TYPE_BINARY
-- 0.14.8
-
--------------------------------------------------------------------
-Wed Sep 16 10:56:44 CEST 2009 - mls@suse.de
-
-- use repomdxml to query for the location [bnc#501425]
-- fix assertion failue... again
-- fix fp leak [bnc#535468]
-- 0.14.7
-
--------------------------------------------------------------------
-Fri Sep  4 11:40:47 CEST 2009 - mls@suse.de
-
-- fix multiversion handling for real
-- fix speed regression in repo_susetags
-- close fd leak [bnc#527506]
-- remove db.h workaround
-- 0.14.6
-
--------------------------------------------------------------------
-Mon Aug 31 13:57:29 CEST 2009 - mls@suse.de
-
-- fix to build with rpm-4.7
-
--------------------------------------------------------------------
-Fri Aug 28 11:06:31 CEST 2009 - ma@suse.de
-
-- add support for SOLVER_SOLVABLE_REPO
-- 0.14.5
-
--------------------------------------------------------------------
-Thu Jul 30 12:49:38 CEST 2009 - mls@suse.de
-
-- speed up file list parsing
-- speed up addfileprovides
-- fix bugs in pubkey handling
-- fix bug in filelist handling when there are no abs paths
-- 0.14.4
-
--------------------------------------------------------------------
-Fri Jul 17 14:07:07 CEST 2009 - mls@suse.de
-
-- add satversion.h header file
-- many changes regarding the load callback
-- more dataiterator control functions
-- add transaction ordering code
-- add support for file conflict checking
-- 0.14.3
-
--------------------------------------------------------------------
-Mon Jun 22 16:01:02 CEST 2009 - mls@suse.de
-
-- create libsatsolverext.a
-- 0.14.2
-
--------------------------------------------------------------------
-Wed May  6 19:52:39 CEST 2009 - ma@suse.de
-
-- Fix to support sha256 hashes (bnc#501425)
-
--------------------------------------------------------------------
-Wed Apr  1 10:32:43 CEST 2009 - kkaempf@suse.de
-
-- 0.14.1
-  Core changes
-  - fix potential NULL deref in srcrpm handling (mls)
-  - clean up and fix suggested/recommended list creation code (mls)
-  - kill obsolete and broken patchxml support (mls)
-  - replace old solver_problemruleinfo with new solver_ruleinfo
-    function (mls)
-  - add solvable_selfprovidedep() function (mls)
-  - add noinfarchcheck solver option (mls)
-  - clone job queue to make the code more flexible (mls)
-  - rewrite policy rule disabling/re-enabling (bnc#481836) (mls)
-  - fix out-of-bounds in solver_printproblem() (mls)
-  Bindings changes
-  - provide 'Repo.attr(String)' accessor function (kkaempf)
-  - provide 'Solver.sizechange' to compute the changes of the
-    installed size after a transaction is applied (kkaempf)
-  - solver result iterators for Python (jblunck)
-  - add %newobject to track newly created objects better (kkaempf)
-  - generate rdoc documentation from swig input files (kkaempf)
-  - add a no-op Pool destructor (bnc#483252) (kkaempf)
-  - provide access to all flags and settings (kkaempf)
-
--------------------------------------------------------------------
-Wed Mar  4 14:39:00 CET 2009 - mls@suse.de
-
-- fix problem_to_solutions segfault
-- bump version to 0.14 to make it different from code11 branch
-- 0.14.0
-
--------------------------------------------------------------------
-Mon Mar  2 18:20:22 CET 2009 - mls@suse.de
-
-- add solver_trivial_installable() to fix multiversion patches [bnc#480303]
-- 0.13.5
-
--------------------------------------------------------------------
-Wed Feb 18 16:48:41 CET 2009 - ma@suse.de
-
-- Use correct namespace (e.g. pattern:) even if solvable has no name [bnc#470011]
-
--------------------------------------------------------------------
-Fri Jan 30 14:26:42 CET 2009 - mls@suse.de
-
-- fix weakmap boundary check
-- 0.13.3
-
--------------------------------------------------------------------
-Tue Jan 27 13:12:30 CET 2009 - ma@suse.de
-
-- Ignore trailing whitespace in content file parser.
-
--------------------------------------------------------------------
-Mon Jan 26 13:55:35 CET 2009 - mls@suse.de
-
-- fix segfault caused by whatprovides reallocation [bnc#468313]
-- 0.13.1
-
--------------------------------------------------------------------
-Tue Jan 20 17:12:17 CET 2009 - ma@suse.de
-
-- repo_rpmdb: Fix conversion to UTF8
-
--------------------------------------------------------------------
-Fri Dec  5 14:43:55 CET 2008 - kkaempf@suse.de
-
-- enhance bindings to provide reasons for solver decisions
-
--------------------------------------------------------------------
-Mon Dec  1 11:50:12 CET 2008 - mls@suse.de
-
-- prefer patterns again until there's a real fix [bnc#450226]
-
--------------------------------------------------------------------
-Mon Dec  1 11:13:55 CET 2008 - mls@suse.de
-
-- susetags: fix file dependency parsing [bnc#450286]
-
--------------------------------------------------------------------
-Fri Nov 28 18:29:08 CET 2008 - mls@suse.de
-
-- correct problem solving algorithm
-- 0.13.0
-
--------------------------------------------------------------------
-Fri Nov 21 16:54:44 CET 2008 - dmacvicar@suse.de
-
-- remove unused updaterepokey, replaced by repo
-  product information
-
--------------------------------------------------------------------
-Thu Nov 20 10:32:01 CET 2008 - dmacvicar@suse.de
-
-- support content, distro and updates tag properly
-- remove the unused products tag
-
--------------------------------------------------------------------
-Mon Nov 17 14:30:08 CET 2008 - ma@suse.de
-
-- Parse RELEASE tag from contentfile (bnc #444978)
-- 0.12.3
-
--------------------------------------------------------------------
-Fri Nov 14 18:00:19 CET 2008 - mls@suse.de
-
-- fix bugs in multiversion handling
-- bring perl bindings up to speed
-- 0.12.2
-
--------------------------------------------------------------------
-Fri Nov  7 18:26:07 CET 2008 - ma@suse.de
-
-- fix SOLVID_POS dataiterator handling
-
--------------------------------------------------------------------
-Fri Nov  7 11:56:37 CET 2008 - kkaempf@suse.de
-
-- make repo_zyppdb more robust (bnc#441043)
-
--------------------------------------------------------------------
-Thu Nov  6 09:49:51 CET 2008 - kkaempf@suse.de
-
-- Add 'user_data' argument to all applayer iterator callbacks
-  (bnc#418491)
-
--------------------------------------------------------------------
-Wed Oct 29 12:36:57 CET 2008 - ma@suse.de
-
-- Add 'sh4' architectures.
-
--------------------------------------------------------------------
-Tue Oct 28 16:55:03 CET 2008 - ma@suse.de
-
-- Add 'arm' architectures.
-
--------------------------------------------------------------------
-Mon Oct 27 10:54:36 CET 2008 - kkaempf@suse.de
-
-- Improve error detection and reporting when parsing 'content' file
-
--------------------------------------------------------------------
-Fri Oct 24 16:03:13 CEST 2008 - ma@suse.de
-
-- Remember the /etc/products.d enties filename in .solv
-  (bnc #432932)
-- 0.12.1
-
--------------------------------------------------------------------
-Thu Oct 23 10:49:40 CEST 2008 - mrueckert@suse.de
-
-- add zlib-devel as buildrequires, cmake is looking for it
-  explicitely. rpm-devel used to require it but you dont really
-  need it to link against librpm*
-- requires rpm-devel in the devel package, it is required to link
-  against libsatsolver.
-
--------------------------------------------------------------------
-Wed Oct 22 13:00:56 CEST 2008 - mls@suse.de
-
-- add pool_set_installed()
-- drop "installed" arguments from some functions
-- 0.12.0
-
--------------------------------------------------------------------
-Wed Oct 22 13:00:25 CEST 2008 - dmacvicar@suse.de
-
-- support the new standarized tags available in
-  createrepo > 0.9.6
-  saving of the distro tag still missing.
-
--------------------------------------------------------------------
-Thu Oct 16 00:50:47 CEST 2008 - mls@suse.de
-
-- make iterator work with completely empty repos [bnc#435838]
-
--------------------------------------------------------------------
-Tue Oct 14 18:28:57 CEST 2008 - mls@suse.de
-
-- the big solv data change
-  * incompatible new file format
-  * repodata handles are solvable ids
-  * no more extra handles
-  * no need to call repodata_extend anymore
-- work around solver dup repo priority bug, real fix follows soon
-- implement releasever
-- repo_products.c is now more robust
-
--------------------------------------------------------------------
-Mon Oct 13 16:50:14 CEST 2008 - kkaempf@suse.de
-
-- make product parsing more robust (bnc#433362)
-
--------------------------------------------------------------------
-Thu Oct  2 18:46:55 CEST 2008 - ma@suse.de
-
-- Product arttributes: removed FLAVOR and REFERENCES, added PRODUCTLINE.
-- revision 11233
-- 0.11.0
-
--------------------------------------------------------------------
-Tue Sep 30 13:03:10 CEST 2008 - ma@suse.de
-
-- repo_content.c: fix broken dependency parsing.
-- revision 11214
-
--------------------------------------------------------------------
-Mon Sep 29 14:53:09 CEST 2008 - ma@suse.de
-
-- rpms2solv failed to write out most solvable data (bnc #422338).
-- revision 11201
-
--------------------------------------------------------------------
-Fri Sep 26 11:54:34 CEST 2008 - kkaempf@suse.de
-
-- new fallback strategy for installed products in rpmdb2solv
-  try /etc/products.d (code11 style) first
-  if this fails, try /var/lib/zypp/db/products/*
-  if this fails, fallback to /etc/*-release
-  (bnc#429177)
-- 0.10.16
-
--------------------------------------------------------------------
-Thu Sep 25 17:14:42 CEST 2008 - kkaempf@suse.de
-
-- fully support Dataiterator in Python and Ruby bindings.
-- 0.10.15
-
--------------------------------------------------------------------
-Thu Sep 25 13:53:54 CEST 2008 - dmacvicar@suse.de
-
-- add support for keywords in susedata
-
--------------------------------------------------------------------
-Wed Sep 24 10:55:01 CEST 2008 - kkaempf@suse.de
-
-- parse /etc/<xyz>-release if no /etc/products.d present
-  (bnc#429177)
-- 0.10.14
-
--------------------------------------------------------------------
-Mon Sep 22 12:51:51 CEST 2008 - dmacvicar@suse.de
-
-- ability to parse suseinfo.xml for extended repomd.xml attributes
-- fix susedata.xml parsing
-- add CPE attribute to installed product
-- real fix for segfault in multiarch parsing (bnc#427271)
-- 0.10.13
-
--------------------------------------------------------------------
-Thu Sep 18 14:44:31 CEST 2008 - dmacvicar@suse.de
-
-- fix segfault in multiarch parsing (bnc#427271)
-
--------------------------------------------------------------------
-Wed Sep 17 14:10:23 CEST 2008 - mls@suse.de
-
-- fix segfault in provides iterator
-- 0.10.12
-
--------------------------------------------------------------------
-Fri Sep 12 17:32:02 CEST 2008 - dmacvicar@suse.de
-
-- support for susedata.xml
-
--------------------------------------------------------------------
-Fri Sep 12 14:01:11 CEST 2008 - dmacvicar@suse.de
-
-- add repo_add_poolstr_array
-- move updates="key,key.." to repomd.xml
-- make product url ids more extensible
-- 0.10.11
-
--------------------------------------------------------------------
-Thu Sep 11 14:30:16 CEST 2008 - dmacvicar@suse.de
-
-- add REPOSITORY_UPDATES to match product -> repos
-- make updateinfo.xml support id attribute in collection that
-  leads to insert that the repository updates that id.
-
--------------------------------------------------------------------
-Wed Sep 10 18:11:10 CEST 2008 - dmacvicar@suse.de
-
-- create one product per BASEARCHS
-
--------------------------------------------------------------------
-Wed Sep 10 14:19:26 CEST 2008 - ma@suse.de
-
-- repo_products: Parse schemeversion, propagate product
-  updaterepokey and flavor. Fix segfault on malformed
-  xml.
-- 0.10.10
-
--------------------------------------------------------------------
-Wed Sep 10 11:57:27 CEST 2008 - dmacvicar@suse.de
-
-- accept the PATTERNS tag in content file
-
--------------------------------------------------------------------
-Tue Sep  9 21:26:31 CEST 2008 - kkaempf@suse.de
-
-- rpmdb2solv changes:
-  - fix bug when parsing multiple products
-  - adapt to .prod file as of 9/9/08 7:20pm
-- 0.10.9
-
--------------------------------------------------------------------
-Tue Sep  9 17:52:30 CEST 2008 - ma@suse.de
-
-- Reenable -Werror and fix bindings.
-- 0.10.8
-
--------------------------------------------------------------------
-Tue Sep  9 11:50:39 CEST 2008 - dmacvicar@suse.de
-
-- disable -Werror for swig generated stuff
-
--------------------------------------------------------------------
-Fri Sep  5 18:59:35 CEST 2008 - kkaempf@suse.de
-
-- adapt /etc/product.d parser to generated .prod files.
-
--------------------------------------------------------------------
-Fri Sep  5 13:29:47 CEST 2008 - ma@suse.de
-
-- tools/repo_susetags.c: Parse packages vendor (bnc #422493).
-- 0.10.7
-
--------------------------------------------------------------------
-Thu Sep  4 12:30:06 CEST 2008 - kkaempf@suse.de
-
-- tools/rpmdb2solv: Adapt to xml-based /etc/products.d
-- tools/rpmdb2solv: Add '-a <attribute>' to print
-  distribution.target attribute of baseproduct.
-
--------------------------------------------------------------------
-Tue Sep  2 12:17:03 CEST 2008 - mls@suse.de
-
-- make solver includes use "" instead of <>, fixes bnc#415920
-- implement otherproviders()
-- make patches do nevr matching
-- make patch conflicts work with multiversion
-- new job commands, now combinded from job type and select type
-- support for distupgrade mode
-- make SOLVER_ERASE_SOLVABLE work
-- also check obsoletes when disabling update rules
-- 0.10.6
-
--------------------------------------------------------------------
-Fri Aug 22 18:04:12 CEST 2008 - dmacvicar@suse.de
-
-- add support for extensible metadata over primary +
-  diskusage
-- 0.10.5
-
--------------------------------------------------------------------
-Fri Aug 15 16:29:00 CEST 2008 - kkaempf@suse.de
-
-- ensure existance of product solvable in repo_content(bnc#417594)
-
--------------------------------------------------------------------
-Fri Aug 15 15:00:32 CEST 2008 - kkaempf@suse.de
-
-- follow /etc/products.d/baseproduct and mark product as 'base'
-
--------------------------------------------------------------------
-Fri Aug 15 14:26:29 CEST 2008 - kkaempf@suse.de
-
-- Implement pre-code11 fallback for products, parse /etc/*-release
-  if /etc/products.d is not available.
-
--------------------------------------------------------------------
-Wed Aug 13 18:06:41 CEST 2008 - kkaempf@suse.de
-
-- provide installtime for installed products.
-
--------------------------------------------------------------------
-Wed Aug 13 15:42:36 CEST 2008 - dmacvicar@suse.de
-
-- include new file search capability commited by matz
-  (SEARCH_FILES)
-- 0.10.4
-
--------------------------------------------------------------------
-Wed Aug 13 10:31:01 CEST 2008 - kkaempf@suse.de
-
-- Honor rpmdb2solv's '-r <root>' also for the products.d path.
-
--------------------------------------------------------------------
-Tue Aug 12 14:22:29 CEST 2008 - kkaempf@suse.de
-
-- Add .prod parsing for 'installed' products to rpmdb2solv.
-- Improve python-bindings, add iterators.
-
--------------------------------------------------------------------
-Thu Aug  7 22:00:55 CEST 2008 - dmacvicar@suse.de
-
-- implement relogin suggested support (fate#304889)
-
--------------------------------------------------------------------
-Thu Aug  7 13:36:59 CEST 2008 - ma@suse.de
-
-- Susetags: Allow whitespace in file provides generated by
-  autobuild (bnc#415115)
-
--------------------------------------------------------------------
-Fri Aug  1 18:59:22 CEST 2008 - dmacvicar@suse.de
-
-- insert the checksum in rpmmd generated solv files
-  (bnc#414002)
-- 0.10.3
-
--------------------------------------------------------------------
-Tue Jul 29 10:53:22 CEST 2008 - mls@suse.de
-
-- resolve job rules before installing system packages [bnc#411086]
-- no more freshens. R.I.P.
-- make repo2solv.sh also take repomd.xml in count
-- install repomdxml2solv
-- add Packager, Build Host, Distribution
-- disallow arch/vendor changes even if the package name changes
-
--------------------------------------------------------------------
-Sat Jul 12 02:32:15 CEST 2008 - dmacvicar@suse.de
-
-- infrastructure to save generated and expiration time
-  stamp in rpm-md repositories (fate #301904)
-- 0.10.1
-
--------------------------------------------------------------------
-Wed Jul  9 16:25:36 CEST 2008 - ma@suse.de
-
-- Fix repo_content dependency parsing. Parser may lose up to
-  two trailing dependencies.
-
--------------------------------------------------------------------
-Tue Jul  1 14:54:38 CEST 2008 - kkaempf@suse.de
-
-- rename language bindings to {perl,python,ruby}-satsolver
-  to follow naming conventions.
-
--------------------------------------------------------------------
-Mon Jun 30 23:55:20 CEST 2008 - dmacvicar@suse.de
-
-- forward port
-- add message tag to updateinfo.xml for displaying
-  messages in the user interface
-- Fix missing self provides for patches (bnc #397132).
-- do not reorder binary rules if they are not rpm rules [bnc#397456]
-- 0.10.0
-
--------------------------------------------------------------------
-Mon Jun  2 11:47:32 CEST 2008 - coolo@suse.de
-
-- calculate recommendation list also if ignorealreadyrecommended is set,
-  as some recommendations would be missing otherwise
-- make dependency output less confusing (bnc#396309)
-- 0.9.0
-
--------------------------------------------------------------------
-Tue May 27 22:34:05 CEST 2008 - coolo@suse.de
-
-- compile with RPM_OPT_FLAGS
-
--------------------------------------------------------------------
-Fri May 23 21:07:01 CEST 2008 - mls@suse.de
-
-- add "zypper" flag
-- add "ignorealreadyrecommended" aka "zypper" solver option
-
--------------------------------------------------------------------
-Thu May 22 20:16:22 CEST 2008 - coolo@suse.de
-
-- fixed language support in patterns (bnc#386524)
-
--------------------------------------------------------------------
-Mon May 19 14:53:01 CEST 2008 - dmacvicar@suse.de
-
-- make solvable_look_bool more robust by allowing both
-  the void or the num == 1 strategy.
-
--------------------------------------------------------------------
-Thu May 15 16:05:50 CEST 2008 - coolo@suse.de
-
-- fix susetags parser
-
-------------------------------------------------------------------
-Wed May 14 16:41:26 CEST 2008 - dmacvicar@suse.de
-
-- mls fix of satisfied patterns
-- 0.0.33
-
--------------------------------------------------------------------
-Tue May 13 17:14:26 CEST 2008 - dmacvicar@suse.de
-
-- use repodata_set_void for pattern visible attr
-
--------------------------------------------------------------------
-Tue May 13 14:11:30 CEST 2008 - jreidinger@suse.cz
-
-- read description dir path from content file (bnc #389414)
-
--------------------------------------------------------------------
-Tue May 13 12:20:58 CEST 2008 - dmacvicar@suse.de
-
-- a boolean is not a num attribute set to 1, but just a existing void
-  attribute. (bnc#388818)
-
--------------------------------------------------------------------
-Mon May 12 10:16:20 CEST 2008 - coolo@suse.de
-
-- provide libsatsolver to fix requires of debuginfo
-
--------------------------------------------------------------------
-Sat May 10 15:33:15 CEST 2008 - coolo@suse.de
-
-- resubmit clean tar
-
--------------------------------------------------------------------
-Fri May  9 21:56:43 CEST 2008 - ma@suse.de
-
-- Parse the products LABEL in content file to SUMMARY.
-
--------------------------------------------------------------------
-Fri May  9 20:26:52 CEST 2008 - dmacvicar@suse.de
-
-- recognize 1 as true for reboot suggested and
-  restart suggested (bnc#388818)
-
--------------------------------------------------------------------
-Fri May  9 16:04:42 CEST 2008 - kkaempf@suse.de
-
-- move 'helix2solv' from satsolver-tools to satsolver-devel package
-  (bnc#388595)
-
--------------------------------------------------------------------
-Mon May  5 16:24:14 CEST 2008 - coolo@suse.de
-
-- add obsoleteusesprovides and implicitobsoleteusesprovides solver
-  flags
-- speed up solving by not recreating the watch chains every time
-  some rule is enabled/disabled. To do this, the "disabled" flag
-  had to be moved from w1 to d.
-- fix bug that broke rule disabling when "forceResolve" was true
-- fix bug in update rule calculation
-- speed up solver a bit by creating a queue holding all assertion
-  rules, so we do not have to scan all rules for assertions
-- parse also DISTPRODUCT and DISTVERSION (for registration), and the other
-  (often unused) attributes of products.
-
--------------------------------------------------------------------
-Mon Apr 28 19:36:54 CEST 2008 - coolo@suse.de
-
-- (De-)Serialize structured types.  Dataiterator and repo_search support
-  them too, but not yet nested, so that is unsupported for now.
-- skipping kinds in matcher when a flag is specified.
-- make --force behave a bit more like --noforce
-
--------------------------------------------------------------------
-Fri Apr 25 19:23:51 CEST 2008 - coolo@suse.de
-
-- detect and skip empty lines (bnc#381828)
-- fix endless loop
-- move debug functions to solverdebug.c
-- do not delete negative bitfield entries [bnc#381908]
-- add "showinstalledrecommended" option to make the solver
-  put installed packages on the suggestions/recommendations
-  queues
-- Fix content parsing if PRODUCT isn't the first entry.
-- add more statistics
-- add two assertions
-- add support for susetags filelist
-- plug mem join2 leak
-- fix anchoring of filelist data
-- susetags move files added to provides back into filelist
-- ignore packages.FL for now
-
--------------------------------------------------------------------
-Sun Apr 20 18:25:14 CEST 2008 - coolo@suse.de
-
-- fix build
-
--------------------------------------------------------------------
-Sat Apr 19 08:10:51 CEST 2008 - coolo@suse.de
-
-- fix probleminfo if solvable conflicts with itself and has no requires
-- Fix parsing dep lines of content files (bnc #380396).
-- C++-guard also solver.h
-- add support for feature rules
-- fix a couple of small bugs
-- use new interface
-
--------------------------------------------------------------------
-Wed Apr 16 17:44:20 CEST 2008 - coolo@suse.de
-
-- fix (rare) case of crashing solver
-
--------------------------------------------------------------------
-Tue Apr 15 09:06:36 CEST 2008 - coolo@suse.de
-
-- some fixes around updateinfo parsing
-
--------------------------------------------------------------------
-Wed Apr  9 16:09:36 CEST 2008 - jkupec@suse.cz
-
-- enable regex matching in Dataiterator
-
--------------------------------------------------------------------
-Fri Apr  4 15:45:44 CEST 2008 - coolo@suse.de
-
-- package deptestomatic in -devel
-
--------------------------------------------------------------------
-Mon Mar 31 16:25:03 CEST 2008 - coolo@suse.de
-
-- truly restart when analyze_unsolvable is hit (fixes bnc#368209)
-- make it work with really large directories
-
--------------------------------------------------------------------
-Mon Mar 24 15:31:18 CET 2008 - coolo@suse.de
-
-- install rpms2solv
-
--------------------------------------------------------------------
-Mon Mar 17 16:10:22 CET 2008 - matz@suse.de
-
-- Initialize all allocated array members for blocky arrays (when it
-  matters, e.g. when extending also in blocks - bnc#371137)
-
--------------------------------------------------------------------
-Fri Mar 14 08:37:47 CET 2008 - coolo@suse.de
-
-- fix build on other distris
-- fix requires of tools
-
--------------------------------------------------------------------
-Wed Mar 12 11:45:21 CET 2008 - coolo@suse.de
-
-- store datadir for susetags
-- fixing assertion in rules learning
-
--------------------------------------------------------------------
-Fri Mar  7 10:51:09 CET 2008 - coolo@suse.de
-
-- several fixes in whatprovides (possibly root cause of bnc#367210)
-
--------------------------------------------------------------------
-Mon Feb 25 12:59:00 CET 2008 - coolo@suse.de
-
-- fixing rpmdb2solv argument handling
-
--------------------------------------------------------------------
-Fri Feb 22 11:09:05 CET 2008 - coolo@suse.de
-
-- support rpmdb2solv -r for chroots
-
--------------------------------------------------------------------
-Thu Feb 21 18:14:41 CET 2008 - coolo@suse.de
-
-- fix susetags parser for so called full trees
-
--------------------------------------------------------------------
-Wed Feb 20 13:23:31 CET 2008 - coolo@suse.de
-
-- no longer link against db43 but against rpmlib
-
--------------------------------------------------------------------
-Tue Feb 19 15:01:55 CET 2008 - coolo@suse.de
-
-- fix requires/obsoletes
-
--------------------------------------------------------------------
-Tue Feb 19 08:10:01 CET 2008 - coolo@suse.de
-
-- mls is back from vacation - several fixes and enhancements
-
--------------------------------------------------------------------
-Fri Feb 15 11:04:09 CET 2008 - coolo@suse.de
-
-- several fixes for the solv files
-
--------------------------------------------------------------------
-Tue Feb 12 18:29:43 CET 2008 - kkaempf@suse.de
-
-- add libappsatsolver, an application layer to ease coding
-  against sat-solver.
-
--------------------------------------------------------------------
-Tue Feb 12 17:14:04 CET 2008 - coolo@suse.de
-
-- let susetags parse vendors
-
--------------------------------------------------------------------
-Thu Feb  7 18:41:05 CET 2008 - coolo@suse.de
-
-- rename libsatsolver in satsolver-tools
-- several updates and fixes
-
--------------------------------------------------------------------
-Fri Feb  1 13:59:53 CET 2008 - coolo@suse.de
-
-- really don't strip
-
--------------------------------------------------------------------
-Mon Jan 14 17:14:03 CET 2008 - coolo@suse.de
-
-- update from SVN:
-  - various fixes
-  - less logging
-
--------------------------------------------------------------------
-Tue Jan  8 16:02:26 CET 2008 - coolo@suse.de
-
-- update to SVN again and don't strip
-
--------------------------------------------------------------------
-Sat Dec 22 19:02:57 CET 2007 - coolo@suse.de
-
-- update to SVN so libzypp compiles again
-
--------------------------------------------------------------------
-Fri Nov 30 16:01:39 CET 2007 - schubi@suse.de
-
-- update for libzypp integration
-
--------------------------------------------------------------------
-Fri Nov 16 12:17:13 CET 2007 - coolo@suse.de
-
-- update to SVN again to make libzypp compilable again
-
--------------------------------------------------------------------
-Wed Nov 14 16:10:21 CET 2007 - schubi@suse.de
-
-- further develpment. bugfix, logging, docu,...
-
--------------------------------------------------------------------
-Mon Nov 12 13:44:52 CET 2007 - coolo@suse.de
-
-- update to the latest version from SVN
-  - compilation fixes
-  - policy engine
-
--------------------------------------------------------------------
-Thu Nov  8 13:14:20 CET 2007 - coolo@suse.de
-
-- update to the latest version from SVN
-
--------------------------------------------------------------------
-Tue Oct  2 15:26:36 CEST 2007 - kkaempf@suse.de
-
-- Initial release
-
diff --git a/libsolv-0.6.15/package/libsolv.spec.in b/libsolv-0.6.15/package/libsolv.spec.in
deleted file mode 100644 (file)
index c2251ec..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-#
-# spec file for package libsolv
-#
-# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
-#
-# All modifications and additions to the file contributed by third parties
-# remain the property of their copyright owners, unless otherwise agreed
-# upon. The license for this file, and modifications and additions to the
-# file, is the same license as for the pristine package itself (unless the
-# license for the pristine package is not an Open Source License, in which
-# case the license is the MIT License). An "Open Source License" is a
-# license that conforms to the Open Source Definition (Version 1.9)
-# published by the Open Source Initiative.
-
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
-#
-
-Name:           libsolv
-Version:        @VERSION@
-Release:        0
-Url:            https://github.com/openSUSE/libsolv
-Source:         libsolv-%{version}.tar.bz2
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-
-%bcond_without enable_static
-%bcond_without disable_shared
-%bcond_without perl_binding
-%bcond_without python_binding
-%bcond_without ruby_binding
-%bcond_with zypp
-
-%if 0%{?mandriva_version}
-# force this version on mandriva
-BuildRequires:  libneon0.26-devel
-%endif
-%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
-BuildRequires:  db-devel
-%endif
-%if 0%{?suse_version}
-%if 0%{?suse_version} < 1030
-BuildRequires:  expat
-%else
-BuildRequires:  libexpat-devel
-%endif
-%if 0%{?suse_version} < 1100
-BuildRequires:  graphviz
-%endif
-%if 0%{?suse_version} > 1020
-BuildRequires:  fdupes
-%endif
-%else
-BuildRequires:  expat-devel
-%endif
-BuildRequires:  cmake
-BuildRequires:  gcc-c++
-BuildRequires:  rpm-devel
-BuildRequires:  zlib-devel
-
-%if %{with perl_binding}
-BuildRequires:  perl
-%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
-BuildRequires:  perl-devel
-%endif
-BuildRequires:  swig
-%endif
-%if %{with ruby_binding}
-%global ruby_vendorarch %(ruby  -r rbconfig -e "puts RbConfig::CONFIG['vendorarchdir'].nil? ? RbConfig::CONFIG['sitearchdir'] : RbConfig::CONFIG['vendorarchdir']")
-BuildRequires:  ruby
-BuildRequires:  ruby-devel
-BuildRequires:  swig
-%endif
-%if %{with python_binding}
-%global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True);")
-BuildRequires:  python-devel
-BuildRequires:  swig
-%endif
-
-Summary:        A new approach to package dependency solving
-License:        BSD-3-Clause
-Group:          Development/Libraries/C and C++
-
-%description
-A new approach to package dependency solving
-
-%if !%{with disable_shared}
-%package -n libsolv@LIBSOLV_SOVERSION@
-Summary:        A new approach to package dependency solving
-Group:          Development/Libraries/C and C++
-
-%description -n libsolv@LIBSOLV_SOVERSION@
-A new approach to package dependency solving
-
-%endif
-%package devel
-Summary:        A new approach to package dependency solving
-Group:          Development/Libraries/C and C++
-%if !%{with disable_shared}
-Requires:       libsolv@LIBSOLV_SOVERSION@ = %version
-%endif
-Requires:       rpm-devel
-Conflicts:      libsatsolver-devel
-
-%description devel
-Development files for libsolv, a new approach to package dependency solving
-
-%package tools
-Summary:        A new approach to package dependency solving
-Group:          Development/Libraries/C and C++
-Obsoletes:      satsolver-tools < 0.18
-Provides:       satsolver-tools = 0.18
-Conflicts:      satsolver-tools-obsolete
-Requires:       gzip bzip2 coreutils findutils
-
-%description tools
-A new approach to package dependency solving.
-
-%package demo
-Summary:        Applications demoing the libsolv library
-Group:          System/Management
-Requires:       curl
-%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
-Requires:       gnupg2
-%endif
-%if 0%{?suse_version}
-Requires:       gpg2
-%endif
-Conflicts:      libsatsolver-demo
-
-%description demo
-Applications demoing the libsolv library.
-
-%package -n ruby-solv
-Summary:        Ruby bindings for the libsolv library
-Group:          Development/Languages/Ruby
-
-%description -n ruby-solv
-Ruby bindings for sat solver.
-
-%package -n python-solv
-%if 0%{?py_requires:1} && %{with python_binding}
-%py_requires
-%endif
-Summary:        Python bindings for the libsolv library
-Group:          Development/Languages/Python
-
-%description -n python-solv
-Python bindings for sat solver.
-
-%package -n perl-solv
-Requires:       perl = %{perl_version}
-Summary:        Perl bindings for the libsolv library
-Group:          Development/Languages/Perl
-
-%description -n perl-solv
-Perl bindings for sat solver.
-
-%prep
-%setup -n libsolv-%{version}
-
-%build
-export CFLAGS="$RPM_OPT_FLAGS"
-export CXXFLAGS="$CFLAGS"
-
-CMAKE_FLAGS=
-%if 0%{?fedora_version} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600
-CMAKE_FLAGS="-DFEDORA=1"
-%endif
-%if 0%{?suse_version}
-CMAKE_FLAGS="-DSUSE=1 -DENABLE_APPDATA=1 -DENABLE_COMPS=1"
-%endif
-
-cmake   $CMAKE_FLAGS \
-       -DCMAKE_INSTALL_PREFIX=%{_prefix} \
-       -DLIB=%{_lib} \
-       -DCMAKE_VERBOSE_MAKEFILE=TRUE \
-       -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-       %{?with_enable_static:-DENABLE_STATIC=1} \
-       %{?with_disable_shared:-DDISABLE_SHARED=1} \
-       %{?with_perl_binding:-DENABLE_PERL=1} \
-       %{?with_python_binding:-DENABLE_PYTHON=1} \
-       %{?with_ruby_binding:-DENABLE_RUBY=1} \
-       %{?with_zypp:-DENABLE_SUSEREPO=1 -DENABLE_HELIXREPO=1} \
-       -DUSE_VENDORDIRS=1 \
-       -DCMAKE_SKIP_RPATH=1
-make %{?jobs:-j %jobs}
-
-%install
-make DESTDIR=$RPM_BUILD_ROOT install
-%if %{with python_binding}
-%if 0%{?suse_version}
-pushd $RPM_BUILD_ROOT/%{python_sitearch}
-python %py_libdir/py_compile.py *.py
-python -O %py_libdir/py_compile.py *.py
-popd
-%endif
-%endif
-%if %{with disable_shared}
-# we want to leave the .a file untouched
-export NO_BRP_STRIP_DEBUG=true
-%endif
-
-%clean
-rm -rf "$RPM_BUILD_ROOT"
-
-%if !%{with disable_shared}
-%post -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig
-
-%postun -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig
-
-%files -n libsolv@LIBSOLV_SOVERSION@
-%defattr(-,root,root)
-%doc LICENSE*
-%{_libdir}/libsolv.so.*
-%{_libdir}/libsolvext.so.*
-%endif
-
-%files tools
-%defattr(-,root,root)
-%if 0%{?suse_version}
-%exclude %{_bindir}/helix2solv
-%exclude %{_mandir}/man1/helix2solv*
-%endif
-%exclude %{_bindir}/solv
-%{_bindir}/*
-%{_mandir}/man1/*
-
-%files devel
-%defattr(-,root,root)
-%if %{with enable_static}
-%{_libdir}/libsolv.a
-%{_libdir}/libsolvext.a
-%endif
-%if !%{with disable_shared}
-%{_libdir}/libsolv.so
-%{_libdir}/libsolvext.so
-%endif
-%{_includedir}/solv
-%if 0%{?suse_version}
-%{_bindir}/helix2solv
-%{_mandir}/man1/helix2solv*
-%endif
-%{_datadir}/cmake/Modules/*
-%{_libdir}/pkgconfig/libsolv.pc
-%{_mandir}/man3/*
-
-%files demo
-%defattr(-,root,root)
-%{_bindir}/solv
-
-%if %{with perl_binding}
-%files -n perl-solv
-%defattr(-,root,root)
-%{perl_vendorarch}/*
-%endif
-
-%if %{with ruby_binding}
-%files -n ruby-solv
-%defattr(-,root,root)
-%{ruby_vendorarch}/*
-%endif
-
-%if %{with python_binding}
-%files -n python-solv
-%defattr(-,root,root)
-%{python_sitearch}/*
-%endif
-
-%changelog
diff --git a/libsolv-0.6.15/src/CMakeLists.txt b/libsolv-0.6.15/src/CMakeLists.txt
deleted file mode 100644 (file)
index a2c0098..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-
-INCLUDE (CheckFunctionExists)
-CHECK_FUNCTION_EXISTS (qsort_r HAVE_QSORT_R)
-CHECK_FUNCTION_EXISTS (__qsort_r HAVE___QSORT_R)
-
-IF (HAVE_QSORT_R)
-  ADD_DEFINITIONS (-DHAVE_QSORT_R=1)
-ENDIF (HAVE_QSORT_R)
-
-IF (HAVE___QSORT_R)
-  ADD_DEFINITIONS (-DHAVE___QSORT_R=1)
-ENDIF (HAVE___QSORT_R)
-
-ADD_DEFINITIONS (-DLIBSOLV_INTERNAL=1)
-
-SET (libsolv_SRCS
-    bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c
-    solver.c solverdebug.c repo_solv.c repo_write.c evr.c pool.c
-    queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
-    transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
-    chksum.c md5.c sha1.c sha2.c solvversion.c selection.c)
-
-SET (libsolv_HEADERS
-    bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
-    poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h
-    repo.h repodata.h repo_solv.h repo_write.h util.h selection.h
-    strpool.h dirpool.h knownid.h transaction.h rules.h problems.h
-    chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h)
-
-SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
-IF (HAVE_LINKER_VERSION_SCRIPT)
-SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver")
-ENDIF (HAVE_LINKER_VERSION_SCRIPT)
-
-IF (DISABLE_SHARED)
-ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS})
-ELSE (DISABLE_SHARED)
-ADD_LIBRARY (libsolv SHARED ${libsolv_SRCS})
-ENDIF (DISABLE_SHARED)
-
-SET_TARGET_PROPERTIES(libsolv PROPERTIES OUTPUT_NAME "solv")
-SET_TARGET_PROPERTIES(libsolv PROPERTIES SOVERSION ${LIBSOLV_SOVERSION})
-SET_TARGET_PROPERTIES(libsolv PROPERTIES INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
-
-INSTALL (FILES ${libsolv_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/solv")
-INSTALL (TARGETS libsolv LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
-
-IF (ENABLE_STATIC AND NOT DISABLE_SHARED)
-ADD_LIBRARY (libsolv_static STATIC ${libsolv_SRCS})
-SET_TARGET_PROPERTIES(libsolv_static PROPERTIES OUTPUT_NAME "solv")
-SET_TARGET_PROPERTIES(libsolv_static PROPERTIES SOVERSION ${LIBSOLV_SOVERSION})
-INSTALL (TARGETS libsolv_static LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
-ENDIF (ENABLE_STATIC AND NOT DISABLE_SHARED)
diff --git a/libsolv-0.6.15/src/bitmap.c b/libsolv-0.6.15/src/bitmap.c
deleted file mode 100644 (file)
index 1bf1666..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * bitmap.c
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "bitmap.h"
-#include "util.h"
-
-/* constructor */
-void
-map_init(Map *m, int n)
-{
-  m->size = (n + 7) >> 3;
-  m->map = m->size ? solv_calloc(m->size, 1) : 0;
-}
-
-/* destructor */
-void
-map_free(Map *m)
-{
-  m->map = solv_free(m->map);
-  m->size = 0;
-}
-
-/* copy constructor t <- s */
-void
-map_init_clone(Map *t, Map *s)
-{
-  t->size = s->size;
-  if (s->size)
-    {
-      t->map = solv_malloc(s->size);
-      memcpy(t->map, s->map, s->size);
-    }
-  else
-    t->map = 0;
-}
-
-/* grow a map */
-void
-map_grow(Map *m, int n)
-{
-  n = (n + 7) >> 3;
-  if (m->size < n)
-    {
-      m->map = solv_realloc(m->map, n);
-      memset(m->map + m->size, 0, n - m->size);
-      m->size = n;
-    }
-}
-
-/* bitwise-ands maps t and s, stores the result in t. */
-void
-map_and(Map *t, Map *s)
-{
-    unsigned char *ti, *si, *end;
-    ti = t->map;
-    si = s->map;
-    end = ti + (t->size < s->size ? t->size : s->size);
-    while (ti < end)
-       *ti++ &= *si++;
-}
-
-/* bitwise-ors maps t and s, stores the result in t. */
-void
-map_or(Map *t, Map *s)
-{
-    unsigned char *ti, *si, *end;
-    if (t->size < s->size)
-      map_grow(t, s->size << 3);
-    ti = t->map;
-    si = s->map;
-    end = ti + (t->size < s->size ? t->size : s->size);
-    while (ti < end)
-       *ti++ |= *si++;
-}
-
-/* remove all set bits in s from t. */
-void
-map_subtract(Map *t, Map *s)
-{
-    unsigned char *ti, *si, *end;
-    ti = t->map;
-    si = s->map;
-    end = ti + (t->size < s->size ? t->size : s->size);
-    while (ti < end)
-       *ti++ &= ~*si++;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/src/bitmap.h b/libsolv-0.6.15/src/bitmap.h
deleted file mode 100644 (file)
index 5784e6c..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2007-2011, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * bitmap.h
- *
- */
-
-#ifndef LIBSOLV_BITMAP_H
-#define LIBSOLV_BITMAP_H
-
-#include <string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct _Map {
-  unsigned char *map;
-  int size;
-} Map;
-
-#define MAPZERO(m) (memset((m)->map, 0, (m)->size))
-/* set all bits */
-#define MAPSETALL(m) (memset((m)->map, 0xff, (m)->size))
-/* set bit */
-#define MAPSET(m, n) ((m)->map[(n) >> 3] |= 1 << ((n) & 7))
-/* clear bit */
-#define MAPCLR(m, n) ((m)->map[(n) >> 3] &= ~(1 << ((n) & 7)))
-/* test bit */
-#define MAPTST(m, n) ((m)->map[(n) >> 3] & (1 << ((n) & 7)))
-
-extern void map_init(Map *m, int n);
-extern void map_init_clone(Map *t, Map *s);
-extern void map_grow(Map *m, int n);
-extern void map_free(Map *m);
-extern void map_and(Map *t, Map *s);
-extern void map_or(Map *t, Map *s);
-extern void map_subtract(Map *t, Map *s);
-
-static inline void map_empty(Map *m)
-{
-  MAPZERO(m);
-}
-static inline void map_set(Map *m, int n)
-{
-  MAPSET(m, n);
-}
-static inline void map_setall(Map *m)
-{
-  MAPSETALL(m);
-}
-static inline void map_clr(Map *m, int n)
-{
-  MAPCLR(m, n);
-}
-static inline int map_tst(Map *m, int n)
-{
-  return MAPTST(m, n);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_BITMAP_H */
diff --git a/libsolv-0.6.15/src/chksum.c b/libsolv-0.6.15/src/chksum.c
deleted file mode 100644 (file)
index 935aea8..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) 2008-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "util.h"
-#include "chksum.h"
-
-#include "md5.h"
-#include "sha1.h"
-#include "sha2.h"
-
-struct _Chksum {
-  Id type;
-  int done;
-  unsigned char result[64];
-  union {
-    MD5_CTX md5;
-    SHA1_CTX sha1;
-    SHA224_CTX sha224;
-    SHA256_CTX sha256;
-    SHA384_CTX sha384;
-    SHA512_CTX sha512;
-  } c;
-};
-
-Chksum *
-solv_chksum_create(Id type)
-{
-  Chksum *chk;
-  chk = solv_calloc(1, sizeof(*chk));
-  chk->type = type;
-  switch(type)
-    {
-    case REPOKEY_TYPE_MD5:
-      solv_MD5_Init(&chk->c.md5);
-      return chk;
-    case REPOKEY_TYPE_SHA1:
-      solv_SHA1_Init(&chk->c.sha1);
-      return chk;
-    case REPOKEY_TYPE_SHA224:
-      solv_SHA224_Init(&chk->c.sha224);
-      return chk;
-    case REPOKEY_TYPE_SHA256:
-      solv_SHA256_Init(&chk->c.sha256);
-      return chk;
-    case REPOKEY_TYPE_SHA384:
-      solv_SHA384_Init(&chk->c.sha384);
-      return chk;
-    case REPOKEY_TYPE_SHA512:
-      solv_SHA512_Init(&chk->c.sha512);
-      return chk;
-    default:
-      break;
-    }
-  free(chk);
-  return 0;
-}
-
-Chksum *
-solv_chksum_create_clone(Chksum *chk)
-{
-  return solv_memdup(chk, sizeof(*chk));
-}
-
-int
-solv_chksum_len(Id type)
-{
-  switch (type)
-    {
-    case REPOKEY_TYPE_MD5:
-      return 16;
-    case REPOKEY_TYPE_SHA1:
-      return 20;
-    case REPOKEY_TYPE_SHA224:
-      return 28;
-    case REPOKEY_TYPE_SHA256:
-      return 32;
-    case REPOKEY_TYPE_SHA384:
-      return 48;
-    case REPOKEY_TYPE_SHA512:
-      return 64;
-    default:
-      return 0;
-    }
-}
-
-Chksum *
-solv_chksum_create_from_bin(Id type, const unsigned char *buf)
-{
-  Chksum *chk;
-  int l = solv_chksum_len(type);
-  if (buf == 0 || l == 0)
-    return 0;
-  chk = solv_calloc(1, sizeof(*chk));
-  chk->type = type;
-  chk->done = 1;
-  memcpy(chk->result, buf, l);
-  return chk;
-}
-
-void
-solv_chksum_add(Chksum *chk, const void *data, int len)
-{
-  if (chk->done)
-    return;
-  switch(chk->type)
-    {
-    case REPOKEY_TYPE_MD5:
-      solv_MD5_Update(&chk->c.md5, (void *)data, len);
-      return;
-    case REPOKEY_TYPE_SHA1:
-      solv_SHA1_Update(&chk->c.sha1, data, len);
-      return;
-    case REPOKEY_TYPE_SHA224:
-      solv_SHA224_Update(&chk->c.sha224, data, len);
-      return;
-    case REPOKEY_TYPE_SHA256:
-      solv_SHA256_Update(&chk->c.sha256, data, len);
-      return;
-    case REPOKEY_TYPE_SHA384:
-      solv_SHA384_Update(&chk->c.sha384, data, len);
-      return;
-    case REPOKEY_TYPE_SHA512:
-      solv_SHA512_Update(&chk->c.sha512, data, len);
-      return;
-    default:
-      return;
-    }
-}
-
-const unsigned char *
-solv_chksum_get(Chksum *chk, int *lenp)
-{
-  if (chk->done)
-    {
-      if (lenp)
-        *lenp = solv_chksum_len(chk->type);
-      return chk->result;
-    }
-  switch(chk->type)
-    {
-    case REPOKEY_TYPE_MD5:
-      solv_MD5_Final(chk->result, &chk->c.md5);
-      chk->done = 1;
-      if (lenp)
-       *lenp = 16;
-      return chk->result;
-    case REPOKEY_TYPE_SHA1:
-      solv_SHA1_Final(&chk->c.sha1, chk->result);
-      chk->done = 1;
-      if (lenp)
-       *lenp = 20;
-      return chk->result;
-    case REPOKEY_TYPE_SHA224:
-      solv_SHA224_Final(chk->result, &chk->c.sha224);
-      chk->done = 1;
-      if (lenp)
-       *lenp = 28;
-      return chk->result;
-    case REPOKEY_TYPE_SHA256:
-      solv_SHA256_Final(chk->result, &chk->c.sha256);
-      chk->done = 1;
-      if (lenp)
-       *lenp = 32;
-      return chk->result;
-    case REPOKEY_TYPE_SHA384:
-      solv_SHA384_Final(chk->result, &chk->c.sha384);
-      chk->done = 1;
-      if (lenp)
-       *lenp = 48;
-      return chk->result;
-    case REPOKEY_TYPE_SHA512:
-      solv_SHA512_Final(chk->result, &chk->c.sha512);
-      chk->done = 1;
-      if (lenp)
-       *lenp = 64;
-      return chk->result;
-    default:
-      if (lenp)
-       *lenp = 0;
-      return 0;
-    }
-}
-
-Id
-solv_chksum_get_type(Chksum *chk)
-{
-  return chk->type;
-}
-
-int
-solv_chksum_isfinished(Chksum *chk)
-{
-  return chk->done != 0;
-}
-
-const char *
-solv_chksum_type2str(Id type)
-{
-  switch(type)
-    {
-    case REPOKEY_TYPE_MD5:
-      return "md5";
-    case REPOKEY_TYPE_SHA1:
-      return "sha1";
-    case REPOKEY_TYPE_SHA224:
-      return "sha224";
-    case REPOKEY_TYPE_SHA256:
-      return "sha256";
-    case REPOKEY_TYPE_SHA384:
-      return "sha384";
-    case REPOKEY_TYPE_SHA512:
-      return "sha512";
-    default:
-      return 0;
-    }
-}
-
-Id
-solv_chksum_str2type(const char *str)
-{
-  if (!strcasecmp(str, "md5"))
-    return REPOKEY_TYPE_MD5;
-  if (!strcasecmp(str, "sha") || !strcasecmp(str, "sha1"))
-    return REPOKEY_TYPE_SHA1;
-  if (!strcasecmp(str, "sha224"))
-    return REPOKEY_TYPE_SHA224;
-  if (!strcasecmp(str, "sha256"))
-    return REPOKEY_TYPE_SHA256;
-  if (!strcasecmp(str, "sha384"))
-    return REPOKEY_TYPE_SHA384;
-  if (!strcasecmp(str, "sha512"))
-    return REPOKEY_TYPE_SHA512;
-  return 0;
-}
-
-void *
-solv_chksum_free(Chksum *chk, unsigned char *cp)
-{
-  if (cp)
-    {
-      const unsigned char *res;
-      int l;
-      res = solv_chksum_get(chk, &l);
-      if (l && res)
-        memcpy(cp, res, l);
-    }
-  solv_free(chk);
-  return 0;
-}
-
-int
-solv_chksum_cmp(Chksum *chk, Chksum *chk2)
-{
-  int len;
-  const unsigned char *res1, *res2;
-  if (chk == chk2)
-    return 1;
-  if (!chk || !chk2 || chk->type != chk2->type)
-    return 0;
-  res1 = solv_chksum_get(chk, &len);
-  res2 = solv_chksum_get(chk2, 0);
-  return memcmp(res1, res2, len) == 0 ? 1 : 0;
-}
diff --git a/libsolv-0.6.15/src/chksum.h b/libsolv-0.6.15/src/chksum.h
deleted file mode 100644 (file)
index 479923a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef LIBSOLV_CHKSUM_H
-#define LIBSOLV_CHKSUM_H
-
-#include "pool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _Chksum;
-typedef struct _Chksum Chksum;
-
-Chksum *solv_chksum_create(Id type);
-Chksum *solv_chksum_create_clone(Chksum *chk);
-Chksum *solv_chksum_create_from_bin(Id type, const unsigned char *buf);
-void solv_chksum_add(Chksum *chk, const void *data, int len);
-Id solv_chksum_get_type(Chksum *chk);
-int solv_chksum_isfinished(Chksum *chk);
-const unsigned char *solv_chksum_get(Chksum *chk, int *lenp);
-void *solv_chksum_free(Chksum *chk, unsigned char *cp);
-const char *solv_chksum_type2str(Id type);
-Id solv_chksum_str2type(const char *str);
-int solv_chksum_len(Id type);
-int solv_chksum_cmp(Chksum *chk, Chksum *chk2);
-
-#ifdef LIBSOLV_INTERNAL
-
-#define case_CHKSUM_TYPES \
-    case REPOKEY_TYPE_MD5: \
-    case REPOKEY_TYPE_SHA1: \
-    case REPOKEY_TYPE_SHA224: \
-    case REPOKEY_TYPE_SHA256: \
-    case REPOKEY_TYPE_SHA384: \
-    case REPOKEY_TYPE_SHA512
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_CHKSUM_H */
diff --git a/libsolv-0.6.15/src/cplxdeps.c b/libsolv-0.6.15/src/cplxdeps.c
deleted file mode 100644 (file)
index aadbc48..0000000
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (c) 2014, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * cplxdeps.c
- *
- * normalize complex dependencies into CNF/DNF form
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "pool.h"
-#include "cplxdeps.h"
-
-#ifdef ENABLE_COMPLEX_DEPS
-
-#undef CPLXDEBUG
-
-int
-pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
-{
-  for (;;)
-    {
-      if (rd->flags == REL_AND || rd->flags == REL_COND)       /* those two are the complex ones */
-       return 1;
-      if (rd->flags != REL_OR)
-       return 0;
-      if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name)))
-       return 1;
-      if (!ISRELDEP(rd->evr))
-       return 0;
-      rd = GETRELDEP(pool, rd->evr);
-    }
-}
-
-/* expand simple dependencies into package lists */
-static int
-expand_simpledeps(Pool *pool, Queue *bq, int start, int split)
-{
-  int end = bq->count;
-  int i, x;
-  int newsplit = 0;
-  for (i = start; i < end; i++)
-    {
-      if (i == split)
-       newsplit = bq->count - (end - start);
-      x = bq->elements[i];
-      if (x == pool->nsolvables)
-       {
-         Id *dp = pool->whatprovidesdata + bq->elements[++i];
-         for (; *dp; dp++)
-           queue_push(bq, *dp);
-       }
-      else
-       queue_push(bq, x);
-    }
-  if (i == split)
-    newsplit = bq->count - (end - start);
-  queue_deleten(bq, start, end - start);
-  return newsplit;
-}
-
-#ifdef CPLXDEBUG
-static void
-print_depblocks(Pool *pool, Queue *bq, int start)
-{
-  int i;
-
-  for (i = start; i < bq->count; i++)
-    {
-      if (bq->elements[i] == pool->nsolvables)
-       {
-         Id *dp = pool->whatprovidesdata + bq->elements[++i];
-         printf(" (");
-         while (*dp)
-           printf(" %s", pool_solvid2str(pool, *dp++));
-         printf(" )");
-       }
-      else if (bq->elements[i] > 0)
-       printf(" %s", pool_solvid2str(pool, bq->elements[i]));
-      else if (bq->elements[i] < 0)
-       printf(" -%s", pool_solvid2str(pool, -bq->elements[i]));
-      else
-       printf(" ||");
-    }
-  printf("\n");
-}
-#endif
-
-/* invert all literals in the blocks. note that this also turns DNF into CNF and vice versa */
-static int
-invert_depblocks(Pool *pool, Queue *bq, int start, int r)
-{
-  int i, j, end;
-  if (r == 0 || r == 1)
-    return r ? 0 : 1;
-  expand_simpledeps(pool, bq, start, 0);
-  end = bq->count;
-  for (i = j = start; i < end; i++)
-    {
-      if (bq->elements[i])
-       {
-          bq->elements[i] = -bq->elements[i];
-         continue;
-       }
-      /* end of block reached, reverse */
-      if (i - 1 > j)
-       {
-         int k;
-         for (k = i - 1; j < k; j++, k--)
-           {
-             Id t = bq->elements[j];
-             bq->elements[j] = bq->elements[k];
-             bq->elements[k] = t;
-           }
-       }
-      j = i + 1;
-    }
-  return -1;
-}
-
-/*
- * returns:
- *   0: no blocks
- *   1: matches all
- *  -1: at least one block
- */
-static int
-normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
-{
-  int bqcnt = bq->count;
-  int bqcnt2;
-  int todnf = flags & CPLXDEPS_TODNF ? 1 : 0;
-  Id p, dp;
-
-#ifdef CPLXDEBUG
-  printf("normalize_dep %s todnf:%d\n", pool_dep2str(pool, dep), todnf);
-#endif
-  if (pool_is_complex_dep(pool, dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_COND)
-       {
-         int rdflags = rd->flags;
-         Id name = rd->name;
-         Id evr = rd->evr;
-         int r, mode;
-         
-          if (rdflags == REL_COND)
-           {
-             /* check for relly complex ELSE case */
-             if (ISRELDEP(evr))
-               {
-                 Reldep *rd2 = GETRELDEP(pool, evr);
-                 if (rd2->flags == REL_ELSE)
-                   {
-                     int r2;
-                     /* really complex case */
-                     if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_1)
-                       {
-                         /* A OR ~B */
-                         rdflags = REL_COND;
-                         evr = rd2->name;
-                       }
-                     else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_AND_2)
-                       {
-                         /* C OR B */
-                         rdflags = REL_OR;
-                         name = rd2->evr;
-                         evr = rd2->name;
-                       }
-                     else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_1)
-                       {
-                         /* A AND B */
-                         rdflags = REL_AND;
-                         evr = rd2->name;
-                       }
-                     else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_2)
-                       {
-                         /* A AND C */
-                         rdflags = REL_AND;
-                         evr = rd2->evr;
-                       }
-                     else if ((flags & CPLXDEPS_ELSE_MASK) == CPLXDEPS_ELSE_OR_3)
-                       {
-                         /* C AND ~B */
-                         rdflags = REL_ELSE;
-                         name = rd2->evr;
-                         evr = rd2->name;
-                       }
-                     else if (!todnf)
-                       {
-                         /* we want AND: A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
-                         r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_1);
-                         if (r == 0 && (flags & CPLXDEPS_DONTFIX) == 0)
-                           return 0;
-                         r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_AND_2);
-                         if (r2 == 0 && (flags & CPLXDEPS_DONTFIX) == 0)
-                           {
-                             queue_truncate(bq, bqcnt);
-                             return 0;
-                           }
-                         if (r == -1 || r2 == -1)
-                           return -1;
-                         return r == 1 || r2 == 1 ? 1 : 0;
-                       }
-                     else
-                       {
-                         int r2, r3;
-                         /* we want OR: A IF (B ELSE C) -> (A AND B) OR (A AND C) OR (~B AND C) */
-                         r = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_1);
-                         if (r == 1)
-                           return 1;
-                         r2 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_2);
-                         if (r2 == 1)
-                           {
-                             queue_truncate(bq, bqcnt);
-                             return 1;
-                           }
-                         r3 = normalize_dep(pool, dep, bq, flags | CPLXDEPS_ELSE_OR_3);
-                         if (r3 == 1)
-                           {
-                             queue_truncate(bq, bqcnt);
-                             return 1;
-                           }
-                         if (r == -1 || r2 == -1 || r3 == -1)
-                           return -1;
-                         return 0;
-                       }
-                   }
-               }
-           }
-         mode = rdflags == REL_AND || rdflags == REL_ELSE ? 0 : 1;
-
-         /* get blocks of first argument */
-         r = normalize_dep(pool, name, bq, flags);
-         if (r == 0)
-           {
-             if (rdflags == REL_ELSE)
-               return 0;
-             if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) == 0)
-               return 0;
-             if (rdflags == REL_COND)
-               {
-                 r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
-                 return invert_depblocks(pool, bq, bqcnt, r);  /* invert block for COND */
-               }
-             return normalize_dep(pool, evr, bq, flags);
-           }
-         if (r == 1)
-           {
-             if (rdflags == REL_ELSE)
-               {
-                 r = normalize_dep(pool, evr, bq, (flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX);
-                 return invert_depblocks(pool, bq, bqcnt, r);  /* invert block for ELSE */
-               }
-             if (rdflags == REL_OR || rdflags == REL_COND)
-               return 1;
-             return normalize_dep(pool, evr, bq, flags);
-           }
-
-         /* get blocks of second argument */
-         bqcnt2 = bq->count;
-         /* COND is OR with NEG on evr block, so we invert the todnf flag in that case */
-         r = normalize_dep(pool, evr, bq, rdflags == REL_COND || rdflags == REL_ELSE ? ((flags ^ CPLXDEPS_TODNF) & ~CPLXDEPS_DONTFIX) : flags);
-         if (rdflags == REL_COND || rdflags == REL_ELSE)
-           r = invert_depblocks(pool, bq, bqcnt2, r);  /* invert 2nd block */
-         if (r == 0)
-           {
-             if (rdflags == REL_OR)
-               return -1;
-             if (rdflags == REL_AND && (flags & CPLXDEPS_DONTFIX) != 0)
-               return -1;
-             queue_truncate(bq, bqcnt);
-             return 0;
-           }
-         if (r == 1)
-           {
-             if (rdflags == REL_COND || rdflags == REL_OR)
-               {
-                 queue_truncate(bq, bqcnt);
-                 return 1;
-               }
-             return -1;
-           }
-         if (mode == todnf)
-           {
-             /* simple case: just join em. nothing more to do here. */
-#ifdef CPLXDEBUG
-             printf("SIMPLE JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
-#endif
-             return -1;
-           }
-         else
-           {
-             /* complex case: mix em */
-             int i, j, bqcnt3;
-#ifdef CPLXDEBUG
-             printf("COMPLEX JOIN %d %d %d\n", bqcnt, bqcnt2, bq->count);
-#endif
-             bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2);
-             bqcnt3 = bq->count;
-             for (i = bqcnt; i < bqcnt2; i++)
-               {
-                 for (j = bqcnt2; j < bqcnt3; j++)
-                   {
-                     int a, b;
-                     int bqcnt4 = bq->count;
-                     int k = i;
-
-                     /* mix i block with j block, both blocks are sorted */
-                     while (bq->elements[k] && bq->elements[j])
-                       {
-                         if (bq->elements[k] < bq->elements[j])
-                           queue_push(bq, bq->elements[k++]);
-                         else
-                           {
-                             if (bq->elements[k] == bq->elements[j])
-                               k++;
-                             queue_push(bq, bq->elements[j++]);
-                           }
-                       }
-                     while (bq->elements[j])
-                       queue_push(bq, bq->elements[j++]);
-                     while (bq->elements[k])
-                       queue_push(bq, bq->elements[k++]);
-
-                     /* block is finished, check for A + -A */
-                     for (a = bqcnt4, b = bq->count - 1; a < b; )
-                       {
-                         if (-bq->elements[a] == bq->elements[b])
-                           break;
-                         if (-bq->elements[a] > bq->elements[b])
-                           a++;
-                         else
-                           b--;
-                       }
-                     if (a < b)
-                       queue_truncate(bq, bqcnt4);     /* ignore this block */
-                     else
-                       queue_push(bq, 0);      /* finish block */
-                   }
-                 /* advance to next block */
-                 while (bq->elements[i])
-                   i++;
-               }
-             i = -1;
-             if (bqcnt3 == bq->count)  /* ignored all blocks? */
-               i = todnf ? 0 : 1;
-             queue_deleten(bq, bqcnt, bqcnt3 - bqcnt);
-             return i;
-           }
-       }
-    }
-
-  /* fallback case: just use package list */
-  dp = pool_whatprovides(pool, dep);
-  if (dp <= 2 || !pool->whatprovidesdata[dp])
-    return dp == 2 ? 1 : 0;
-  if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
-    return 1;
-  bqcnt = bq->count;
-  if ((flags & CPLXDEPS_NAME) != 0)
-    {
-      while ((p = pool->whatprovidesdata[dp++]) != 0)
-       {
-         if (!pool_match_nevr(pool, pool->solvables + p, dep))
-           continue;
-         queue_push(bq, p);
-         if (todnf)
-           queue_push(bq, 0);
-       }
-    }
-  else if (todnf)
-    {
-      while ((p = pool->whatprovidesdata[dp++]) != 0)
-        queue_push2(bq, p, 0);
-    }
-  else
-    queue_push2(bq, pool->nsolvables, dp);     /* not yet expanded marker + offset */
-  if (bq->count == bqcnt)
-    return 0;  /* no provider */
-  if (!todnf)
-    queue_push(bq, 0); /* finish block */
-  return -1;
-}
-
-int
-pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags)
-{
-  int i, bqcnt = bq->count;
-
-  i = normalize_dep(pool, dep, bq, flags);
-  if ((flags & CPLXDEPS_EXPAND) != 0)
-    {
-      if (i != 0 && i != 1)
-        expand_simpledeps(pool, bq, bqcnt, 0);
-    }
-  if ((flags & CPLXDEPS_INVERT) != 0)
-    i = invert_depblocks(pool, bq, bqcnt, i);
-#ifdef CPLXDEBUG
-  if (i == 0)
-    printf("NONE\n");
-  else if (i == 1)
-    printf("ALL\n");
-  else
-    print_depblocks(pool, bq, bqcnt);
-#endif
-  return i;
-}
-
-void
-pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg)
-{
-  while (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND)
-       break;
-      pool_add_pos_literals_complex_dep(pool, rd->name, q, m, neg);
-      dep = rd->evr;
-      if (rd->flags == REL_COND)
-       {
-         neg = !neg;
-         if (ISRELDEP(dep))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 pool_add_pos_literals_complex_dep(pool, rd2->evr, q, m, !neg);
-                 dep = rd2->name;
-               }
-           }
-       }
-    }
-  if (!neg)
-    {
-      Id p, pp;
-      FOR_PROVIDES(p, pp, dep)
-       if (!MAPTST(m, p))
-         queue_push(q, p);
-    }
-}
-
-#endif /* ENABLE_COMPLEX_DEPS */
-
diff --git a/libsolv-0.6.15/src/cplxdeps.h b/libsolv-0.6.15/src/cplxdeps.h
deleted file mode 100644 (file)
index 798b485..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2014, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * cplxdeps.h (internal)
- */
-
-#ifndef LIBSOLV_CPLXDEPS_H
-#define LIBSOLV_CPLXDEPS_H
-
-extern int pool_is_complex_dep_rd(Pool *pool, Reldep *rd);
-
-static inline int 
-pool_is_complex_dep(Pool *pool, Id dep)
-{
-  if (ISRELDEP(dep))
-    {   
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags >= 8 && pool_is_complex_dep_rd(pool, rd))
-        return 1;
-    }   
-  return 0;
-}
-
-extern int pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags);
-extern void pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg);
-
-#define CPLXDEPS_TODNF   (1 << 0)
-#define CPLXDEPS_EXPAND  (1 << 1)
-#define CPLXDEPS_INVERT  (1 << 2)
-#define CPLXDEPS_NAME    (1 << 3)
-#define CPLXDEPS_DONTFIX (1 << 4)
-
-#define CPLXDEPS_ELSE_AND_1 (1 << 8)
-#define CPLXDEPS_ELSE_AND_2 (1 << 9)
-#define CPLXDEPS_ELSE_OR_1  (1 << 10)
-#define CPLXDEPS_ELSE_OR_2  (1 << 11)
-#define CPLXDEPS_ELSE_OR_3  (1 << 12)
-#define CPLXDEPS_ELSE_MASK  (0x1f00)
-
-#endif
-
diff --git a/libsolv-0.6.15/src/dataiterator.h b/libsolv-0.6.15/src/dataiterator.h
deleted file mode 100644 (file)
index 3133686..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2007-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * dataiterator.h
- *
- */
-
-#ifndef LIBSOLV_DATAITERATOR_H
-#define LIBSOLV_DATAITERATOR_H
-
-#include "pooltypes.h"
-#include "pool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _Repo;
-
-typedef struct _KeyValue {
-  Id id;
-  const char *str;
-  unsigned int num;
-  unsigned int num2;
-
-  int entry;   /* array entry, starts with 0 */
-  int eof;     /* last entry reached */
-
-  struct _KeyValue *parent;
-} KeyValue;
-
-#define SOLV_KV_NUM64(kv) (((unsigned long long)((kv)->num2)) << 32 | (kv)->num)
-
-/* search matcher flags */
-#define SEARCH_STRINGMASK              15
-#define SEARCH_STRING                  1
-#define SEARCH_STRINGSTART             2
-#define SEARCH_STRINGEND               3
-#define SEARCH_SUBSTRING               4
-#define SEARCH_GLOB                    5
-#define SEARCH_REGEX                   6
-#define SEARCH_ERROR                   15
-#define        SEARCH_NOCASE                   (1<<7)
-
-/* iterator control */
-#define        SEARCH_NO_STORAGE_SOLVABLE      (1<<8)
-#define SEARCH_SUB                     (1<<9)
-#define SEARCH_ARRAYSENTINEL           (1<<10)
-#define SEARCH_DISABLED_REPOS          (1<<11)
-#define SEARCH_COMPLETE_FILELIST       (1<<12)
-
-/* stringification flags */
-#define SEARCH_SKIP_KIND               (1<<16)
-/* By default we stringify just to the basename of a file because
-   the construction of the full filename is costly.  Specify this
-   flag if you want to match full filenames */
-#define SEARCH_FILES                   (1<<17)
-#define SEARCH_CHECKSUMS               (1<<18)
-
-/* dataiterator internal */
-#define SEARCH_THISSOLVID              (1<<31)
-
-/*
- * Datamatcher: match a string against a query
- */
-typedef struct _Datamatcher {
-  int flags;           /* see matcher flags above */
-  const char *match;   /* the query string */
-  void *matchdata;     /* e.g. compiled regexp */
-  int error;
-} Datamatcher;
-
-int  datamatcher_init(Datamatcher *ma, const char *match, int flags);
-void datamatcher_free(Datamatcher *ma);
-int  datamatcher_match(Datamatcher *ma, const char *str);
-int  datamatcher_checkbasename(Datamatcher *ma, const char *str);
-
-
-/*
- * Dataiterator
- *
- * Iterator like interface to 'search' functionality
- *
- * Dataiterator is per-pool, additional filters can be applied
- * to limit the search domain. See dataiterator_init below.
- *
- * Use these like:
- *    Dataiterator di;
- *    dataiterator_init(&di, repo->pool, repo, 0, 0, "bla", SEARCH_SUBSTRING);
- *    while (dataiterator_step(&di))
- *      dosomething(di.solvid, di.key, di.kv);
- *    dataiterator_free(&di);
- */
-typedef struct _Dataiterator
-{
-  int state;
-  int flags;
-
-  Pool *pool;
-  struct _Repo *repo;
-  struct _Repodata *data;
-
-  /* data pointers */
-  unsigned char *dp;
-  unsigned char *ddp;
-  Id *idp;
-  Id *keyp;
-
-  /* the result */
-  struct _Repokey *key;
-  KeyValue kv;
-
-  /* our matcher */
-  Datamatcher matcher;
-
-  /* iterators/filters */
-  Id keyname;
-  Id repodataid;
-  Id solvid;
-  Id repoid;
-
-  Id keynames[3 + 1];
-  int nkeynames;
-  int rootlevel;
-
-  /* recursion data */
-  struct di_parent {
-    KeyValue kv;
-    unsigned char *dp;
-    Id *keyp;
-  } parents[3];
-  int nparents;
-
-  /* vertical data */
-  unsigned char *vert_ddp;
-  Id vert_off;
-  Id vert_len;
-  Id vert_storestate;
-
-  /* strdup data */
-  char *dupstr;
-  int dupstrn;
-
-} Dataiterator;
-
-
-/*
- * Initialize dataiterator
- *
- * di:      Pointer to Dataiterator to be initialized
- * pool:    Search domain for the iterator
- * repo:    if non-null, limit search to this repo
- * solvid:  if non-null, limit search to this solvable
- * keyname: if non-null, limit search to this keyname
- * match:   if non-null, limit search to this match
- */
-int  dataiterator_init(Dataiterator *di, Pool *pool, struct _Repo *repo, Id p, Id keyname, const char *match, int flags);
-void dataiterator_init_clone(Dataiterator *di, Dataiterator *from);
-void dataiterator_set_search(Dataiterator *di, struct _Repo *repo, Id p);
-void dataiterator_set_keyname(Dataiterator *di, Id keyname);
-int  dataiterator_set_match(Dataiterator *di, const char *match, int flags);
-
-void dataiterator_prepend_keyname(Dataiterator *di, Id keyname);
-void dataiterator_free(Dataiterator *di);
-int  dataiterator_step(Dataiterator *di);
-void dataiterator_setpos(Dataiterator *di);
-void dataiterator_setpos_parent(Dataiterator *di);
-int  dataiterator_match(Dataiterator *di, Datamatcher *ma);
-void dataiterator_skip_attribute(Dataiterator *di);
-void dataiterator_skip_solvable(Dataiterator *di);
-void dataiterator_skip_repo(Dataiterator *di);
-void dataiterator_jump_to_solvid(Dataiterator *di, Id solvid);
-void dataiterator_jump_to_repo(Dataiterator *di, struct _Repo *repo);
-void dataiterator_entersub(Dataiterator *di);
-void dataiterator_clonepos(Dataiterator *di, Dataiterator *from);
-void dataiterator_seek(Dataiterator *di, int whence);
-void dataiterator_strdup(Dataiterator *di);
-
-#define DI_SEEK_STAY    (1 << 16)
-#define DI_SEEK_CHILD   1
-#define DI_SEEK_PARENT  2
-#define DI_SEEK_REWIND  3
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_DATAITERATOR_H */
diff --git a/libsolv-0.6.15/src/dirpool.c b/libsolv-0.6.15/src/dirpool.c
deleted file mode 100644 (file)
index 5f08361..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "pool.h"
-#include "util.h"
-#include "dirpool.h"
-
-#define DIR_BLOCK 127
-
-/* directories are stored as components,
- * components are simple ids from the string pool
- *   /usr/bin   ->  "", "usr", "bin"
- *   /usr/lib   ->  "", "usr", "lib"
- *   foo/bar    ->  "foo", "bar"
- *   /usr/games ->  "", "usr", "games"
- *
- * all directories are stores in the "dirs" array
- *   dirs[id] > 0 : component string pool id
- *   dirs[id] <= 0 : -(parent directory id)
- *
- * Directories with the same parent are stored as
- * multiple blocks. We need multiple blocks because
- * we cannot insert entries into old blocks, as that
- * would shift the ids of already used directories.
- * Each block starts with (-parent_dirid) and contains
- * component ids of the directory entries.
- * (The (-parent_dirid) entry is not a valid directory
- * id, it's just used internally)
- *
- * There is also the aux "dirtraverse" array, which
- * is created on demand to speed things up a bit.
- * if dirs[id] > 0, dirtravers[id] points to the first
- * entry in the last block with parent id.
- * if dirs[id] <= 0, dirtravers[id] points to the entry
- * in the previous block with the same parent.
- * (Thus it acts as a linked list that starts at the
- * parent dirid and chains all the blocks with that
- * parent.)
- *
- *  id    dirs[id]  dirtraverse[id]
- *   0     0           8       [no parent, block#0]
- *   1    ""           3
- *   2    -1                   [parent 1, /, block #0]
- *   3    "usr"       12
- *   4    -3                   [parent 3, /usr, block #0]
- *   5    "bin"
- *   6    "lib"
- *   7     0           1       [no parent, block#1]
- *   8    "foo"       10
- *   9    -8                   [parent 8, foo, block #0]
- *  10    "bar"
- *  11    -3           5       [parent 3, /usr, block #1]
- *  12    "games"
- *
- * to find all children of dirid 3 ("/usr"), follow the
- * dirtraverse link to 12 -> "games". Then follow the
- * dirtraverse link of this block to 5 -> "bin", "lib"
- */
-
-void
-dirpool_init(Dirpool *dp)
-{
-  memset(dp, 0, sizeof(*dp));
-}
-
-void
-dirpool_free(Dirpool *dp)
-{
-  solv_free(dp->dirs);
-  solv_free(dp->dirtraverse);
-}
-
-void
-dirpool_make_dirtraverse(Dirpool *dp)
-{
-  Id parent, i, *dirtraverse;
-  if (!dp->ndirs)
-    return;
-  dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
-  dirtraverse = solv_calloc_block(dp->ndirs, sizeof(Id), DIR_BLOCK);
-  for (parent = 0, i = 0; i < dp->ndirs; i++)
-    {
-      if (dp->dirs[i] > 0)
-       continue;
-      parent = -dp->dirs[i];
-      dirtraverse[i] = dirtraverse[parent];
-      dirtraverse[parent] = i + 1;
-    }
-  dp->dirtraverse = dirtraverse;
-}
-
-Id
-dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create)
-{
-  Id did, d, ds, *dirtraverse;
-
-  if (!dp->ndirs)
-    {
-      if (!create)
-       return 0;
-      dp->ndirs = 2;
-      dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
-      dp->dirs[0] = 0;
-      dp->dirs[1] = 1; /* "" */
-    }
-  if (parent == 0 && comp == 1)
-    return 1;
-  if (!dp->dirtraverse)
-    dirpool_make_dirtraverse(dp);
-  /* check all entries with this parent if we
-   * already have this component */
-  dirtraverse = dp->dirtraverse;
-  ds = dirtraverse[parent];
-  while (ds)
-    {
-      /* ds: first component in this block
-       * ds-1: parent link */
-      for (d = ds--; d < dp->ndirs; d++)
-       {
-         if (dp->dirs[d] == comp)
-           return d;
-         if (dp->dirs[d] <= 0) /* reached end of this block */
-           break;
-       }
-      if (ds)
-        ds = dp->dirtraverse[ds];
-    }
-  if (!create)
-    return 0;
-  /* a new one, find last parent */
-  for (did = dp->ndirs - 1; did > 0; did--)
-    if (dp->dirs[did] <= 0)
-      break;
-  if (dp->dirs[did] != -parent)
-    {
-      /* make room for parent entry */
-      dp->dirs = solv_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
-      dp->dirtraverse = solv_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
-      /* new parent block, link in */
-      dp->dirs[dp->ndirs] = -parent;
-      dp->dirtraverse[dp->ndirs] = dp->dirtraverse[parent];
-      dp->dirtraverse[parent] = ++dp->ndirs;
-    }
-  /* make room for new entry */
-  dp->dirs = solv_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
-  dp->dirtraverse = solv_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
-  dp->dirs[dp->ndirs] = comp;
-  dp->dirtraverse[dp->ndirs] = 0;
-  return dp->ndirs++;
-}
diff --git a/libsolv-0.6.15/src/dirpool.h b/libsolv-0.6.15/src/dirpool.h
deleted file mode 100644 (file)
index fe05cc6..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-#ifndef LIBSOLV_DIRPOOL_H
-#define LIBSOLV_DIRPOOL_H
-
-
-#include "pooltypes.h"
-#include "util.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct _Dirpool {
-  Id *dirs;
-  int ndirs;
-  Id *dirtraverse;
-} Dirpool;
-
-void dirpool_init(Dirpool *dp);
-void dirpool_free(Dirpool *dp);
-
-void dirpool_make_dirtraverse(Dirpool *dp);
-Id dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create);
-
-/* return the parent directory of child did */
-static inline Id dirpool_parent(Dirpool *dp, Id did)
-{
-  if (!did)
-    return 0;
-  while (dp->dirs[--did] > 0)
-    ;
-  return -dp->dirs[did];
-}
-
-/* return the next child entry of child did */
-static inline Id
-dirpool_sibling(Dirpool *dp, Id did)
-{
-  /* if this block contains another entry, simply return it */
-  if (did + 1 < dp->ndirs && dp->dirs[did + 1] > 0)
-    return did + 1;
-  /* end of block reached, rewind to get to the block's
-   * dirtraverse entry */
-  while (dp->dirs[--did] > 0)
-    ;
-  /* need to special case did == 0 to prevent looping */
-  if (!did)
-    return 0;
-  if (!dp->dirtraverse)
-    dirpool_make_dirtraverse(dp);
-  return dp->dirtraverse[did];
-}
-
-/* return the first child entry of directory did */
-static inline Id
-dirpool_child(Dirpool *dp, Id did)
-{
-  if (!dp->dirtraverse)
-    dirpool_make_dirtraverse(dp);
-  return dp->dirtraverse[did];
-}
-
-static inline void
-dirpool_free_dirtraverse(Dirpool *dp)
-{
-  solv_free(dp->dirtraverse);
-  dp->dirtraverse = 0;
-}
-
-static inline Id
-dirpool_compid(Dirpool *dp, Id did)
-{
-  return dp->dirs[did];
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_DIRPOOL_H */
diff --git a/libsolv-0.6.15/src/evr.c b/libsolv-0.6.15/src/evr.c
deleted file mode 100644 (file)
index a7d4311..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * evr.c
- *
- * version compare
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include "evr.h"
-#include "pool.h"
-
-
-
-#if defined(DEBIAN) || defined(MULTI_SEMANTICS)
-
-/* debian type version compare */
-int
-solv_vercmp_deb(const char *s1, const char *q1, const char *s2, const char *q2)
-{
-  int r, c1, c2;
-  while (1)
-    {
-      c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
-      c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
-      if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
-       {
-         while (c1 == '0')
-            c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
-         while (c2 == '0')
-            c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
-         r = 0;
-         while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
-           {
-             if (!r)
-               r = c1 - c2;
-              c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
-              c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
-           }
-         if (c1 >= '0' && c1 <= '9')
-           return 1;
-         if (c2 >= '0' && c2 <= '9')
-           return -1;
-         if (r)
-           return r < 0 ? -1 : 1;
-       }
-      c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z')  ? c1 : c1 + 256;
-      c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z')  ? c2 : c2 + 256;
-      r = c1 - c2;
-      if (r)
-       return r < 0 ? -1 : 1;
-      if (!c1)
-       return 0;
-    }
-}
-
-#endif
-
-#if !defined(DEBIAN) || defined(MULTI_SEMANTICS)
-
-/* rpm type version compare */
-/* note: the code assumes that *q1 and *q2 are not alphanumeric! */
-
-int
-solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
-{
-  int r = 0;
-  const char *e1, *e2;
-
-  for (;;)
-    {
-      while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
-          !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~')
-       s1++;
-      while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
-          !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~')
-       s2++;
-      if (s1 < q1 && *s1 == '~')
-        {
-         if (s2 < q2 && *s2 == '~')
-           {
-             s1++;
-             s2++;
-             continue;
-           }
-         return -1;
-        }
-      if (s2 < q2 && *s2 == '~')
-       return 1;
-      if (s1 >= q1 || s2 >= q2)
-       break;
-      if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
-       {
-         while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
-           s1++;
-         while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
-           s2++;
-         for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
-           e1++;
-         for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
-           e2++;
-         r = (e1 - s1) - (e2 - s2);
-          if (!r)
-           r = strncmp(s1, s2, e1 - s1);
-          if (r)
-           return r > 0 ? 1 : -1;
-       }
-      else
-       {
-         for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
-           e1++;
-         for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
-           e2++;
-         r = (e1 - s1) - (e2 - s2);
-          if (r > 0)
-           {
-             r = strncmp(s1, s2, e2 - s2);
-             return r >= 0 ? 1 : -1;
-           }
-          if (r < 0)
-           {
-             r = strncmp(s1, s2, e1 - s1);
-             return r <= 0 ? -1 : 1;
-           }
-         r = strncmp(s1, s2, e1 - s1);
-         if (r)
-           return r > 0 ? 1 : -1;
-       }
-      s1 = e1;
-      s2 = e2;
-    }
-  return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
-}
-
-int
-solv_vercmp_rpm_notilde(const char *s1, const char *q1, const char *s2, const char *q2)
-{
-  int r = 0;
-  const char *e1, *e2;
-
-  while (s1 < q1 && s2 < q2)
-    {
-      while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
-          !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z'))
-       s1++;
-      while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
-          !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z'))
-       s2++;
-      if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
-       {
-         while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
-           s1++;
-         while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
-           s2++;
-         for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
-           e1++;
-         for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
-           e2++;
-         r = (e1 - s1) - (e2 - s2);
-          if (!r)
-           r = strncmp(s1, s2, e1 - s1);
-          if (r)
-           return r > 0 ? 1 : -1;
-       }
-      else
-       {
-         for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
-           e1++;
-         for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
-           e2++;
-         r = (e1 - s1) - (e2 - s2);
-          if (r > 0)
-           {
-             r = strncmp(s1, s2, e2 - s2);
-             return r >= 0 ? 1 : -1;
-           }
-          if (r < 0)
-           {
-             r = strncmp(s1, s2, e1 - s1);
-             return r <= 0 ? -1 : 1;
-           }
-         r = strncmp(s1, s2, e1 - s1);
-         if (r)
-           return r > 0 ? 1 : -1;
-       }
-      s1 = e1;
-      s2 = e2;
-    }
-  return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
-}
-
-#endif
-
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-
-static int
-solv_cmp_version_part_haiku(const char *s1, const char *q1, const char *s2,
-  const char *q2)
-{
-  while (s1 < q1 && s2 < q2)
-    {
-      int cmp, len1, len2;
-      const char *part1 = s1, *part2 = s2;
-
-      /* compare non-number part */
-      while (s1 < q1 && !isdigit(*s1))
-        s1++;
-      while (s2 < q2 && !isdigit(*s2))
-        s2++;
-
-      if (part1 != s1)
-        {
-          if (part2 == s2)
-            return 1;
-
-          len1 = s1 - part1;
-          len2 = s2 - part2;
-          cmp = strncmp(part1, part2, len1 < len2 ? len1 : len2);
-          if (cmp != 0)
-            return cmp;
-          if (len1 != len2)
-            return len1 - len2;
-       }
-      else if (part2 != s2)
-        return -1;
-
-      /* compare number part */
-      part1 = s1;
-      part2 = s2;
-
-      while (s1 < q1 && isdigit(*s1))
-        s1++;
-      while (s2 < q2 && isdigit(*s2))
-        s2++;
-
-      while (part1 + 1 < s1 && *part1 == '0')
-        part1++;
-      while (part2 + 1 < s2 && *part2 == '0')
-        part2++;
-
-      len1 = s1 - part1;
-      len2 = s2 - part2;
-      if (len1 != len2)
-        return len1 - len2;
-      if (len1 == 0)
-        return 0;
-
-      cmp = strncmp(part1, part2, len1);
-      if (cmp != 0)
-       return cmp;
-    }
-
-  return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
-}
-
-int
-solv_vercmp_haiku(const char *s1, const char *q1, const char *s2, const char *q2)
-{
-  const char *pre1 = s1;
-  const char *pre2 = s2;
-  int cmp;
-
-  /* find pre-release separator */
-  while (pre1 != q1 && *pre1 != '~')
-    pre1++;
-  while (pre2 != q2 && *pre2 != '~')
-    pre2++;
-
-  /* compare main versions */
-  cmp = solv_cmp_version_part_haiku(s1, pre1, s2, pre2);
-  if (cmp != 0)
-    return cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
-
-  /* main versions are equal -- compare pre-release (none is greatest) */
-  if (pre1 == q1)
-    return pre2 == q2 ? 0 : 1;
-  if (pre2 == q2)
-    return -1;
-
-  cmp = solv_cmp_version_part_haiku(pre1 + 1, q1, pre2 + 1, q2);
-  return cmp == 0 ? 0 : cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
-}
-
-#endif /* HAIKU */
-
-
-/*
- * the solv_vercmp variant your system uses.
- */
-int
-solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
-{
-#if defined(DEBIAN)
-  return solv_vercmp_deb(s1, q1, s2, q2);
-#elif defined(ARCHLINUX)
-  return solv_vercmp_rpm_notilde(s1, q1, s2, q2);
-#elif defined(HAIKU)
-  return solv_vercmp_haiku(s1, q1, s2, q2);
-#else
-  return solv_vercmp_rpm(s1, q1, s2, q2);
-#endif
-}
-
-#if defined(MULTI_SEMANTICS)
-# define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \
-                        pool->disttype == DISTTYPE_HAIKU ? solv_vercmp_haiku : \
-                        &solv_ver##cmp_rpm))
-#elif defined(DEBIAN)
-# define solv_vercmp solv_vercmp_deb
-#elif defined(ARCHLINUX)
-# define solv_vercmp solv_vercmp_rpm_notilde
-#elif defined(HAIKU)
-# define solv_vercmp solv_vercmp_haiku
-#else
-# define solv_vercmp solv_vercmp_rpm
-#endif
-
-/* edition (e:v-r) compare */
-int
-pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
-{
-  int r;
-  const char *s1, *s2;
-  const char *r1, *r2;
-
-  if (evr1 == evr2)
-    return 0;
-
-#if 0
-  POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
-#endif
-  for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
-    ;
-  for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
-    ;
-  if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
-    {
-      /* empty epoch, skip epoch check */
-      if (*s1 == ':')
-       evr1 = s1 + 1;
-      if (*s2 == ':')
-       evr2 = s2 + 1;
-      s1 = evr1;
-      s2 = evr2;
-    }
-
-  /* compare the epoch */
-  if (s1 == evr1 || *s1 != ':')
-    s1 = 0;
-  if (s2 == evr2 || *s2 != ':')
-    s2 = 0;
-  if (s1 && s2)
-    {
-      r = solv_vercmp(evr1, s1, evr2, s2);
-      if (r)
-       return r;
-      evr1 = s1 + 1;
-      evr2 = s2 + 1;
-    }
-  else if (s1)
-    {
-      if (!pool->promoteepoch)
-       {
-         while (*evr1 == '0')
-           evr1++;
-         if (*evr1 != ':')
-           return 1;
-       }
-      evr1 = s1 + 1;
-    }
-  else if (s2)
-    {
-      while (*evr2 == '0')
-       evr2++;
-      if (*evr2 != ':')
-       return -1;
-      evr2 = s2 + 1;
-    }
-
-  /* same epoch, now split into version/release */
-  for (s1 = evr1, r1 = 0; *s1; s1++)
-    if (*s1 == '-')
-      r1 = s1;
-  for (s2 = evr2, r2 = 0; *s2; s2++)
-    if (*s2 == '-')
-      r2 = s2;
-  r = 0;
-  if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
-    r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
-  if (r)
-    return r;
-
-  if (mode == EVRCMP_COMPARE)
-    {
-      if (!r1 && r2)
-       return -1;
-      if (r1 && !r2)
-       return 1;
-    }
-  if (mode == EVRCMP_COMPARE_EVONLY)
-    return 0;
-  if (mode == EVRCMP_MATCH_RELEASE)
-    {
-      /* rpm treats empty releases as missing, i.e "foo = 4-" is the same as "foo = 4" */
-      if (r1 && r1 + 1 == s1)
-       r1 = 0;
-      if (r2 && r2 + 1 == s2)
-       r2 = 0;
-    }
-  if (r1 && r2)
-    {
-      r1++;
-      r2++;
-      if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2))
-       {
-         if (pool->havedistepoch)
-           {
-             const char *d1, *d2;
-             for (d1 = r1; d1 < s1; d1++)
-               if (*d1 == ':')
-                 break;
-             for (d2 = r2; d2 < s2; d2++)
-               if (*d2 == ':')
-                 break;
-             /* XXX: promote just in one direction? */
-             r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2);
-             if (r == 0 && d1 < s1 && d2 < s2)
-               r = solv_vercmp(d1 + 1, s1, d2 + 1, s2);
-           }
-         else
-            r = solv_vercmp(r1, s1, r2, s2);
-       }
-    }
-  else if (mode == EVRCMP_MATCH_RELEASE)
-    {
-      if (!r1 && r2)
-       return -2;
-      if (r1 && !r2)
-       return 2;
-    }
-  return r;
-}
-
-int
-pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode)
-{
-  const char *evr1, *evr2;
-  if (evr1id == evr2id)
-    return 0;
-  evr1 = pool_id2str(pool, evr1id);
-  evr2 = pool_id2str(pool, evr2id);
-  return pool_evrcmp_str(pool, evr1, evr2, mode);
-}
-
-int
-pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release)
-{
-  const char *evr1;
-  const char *s1;
-  const char *r1;
-  int r;
-
-  evr1 = pool_id2str(pool, evrid);
-  for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
-    ;
-  if (s1 != evr1 && *s1 == ':')
-    {
-      if (epoch)
-       {
-         r = solv_vercmp(evr1, s1, epoch, epoch + strlen(epoch));
-         if (r)
-           return r;
-       }
-      evr1 = s1 + 1;
-    }
-  else if (epoch)
-    {
-      while (*epoch == '0')
-       epoch++;
-      if (*epoch)
-       return -1;
-    }
-  for (s1 = evr1, r1 = 0; *s1; s1++)
-    if (*s1 == '-')
-      r1 = s1;
-  if (version)
-    {
-      r = solv_vercmp(evr1, r1 ? r1 : s1, version, version + strlen(version));
-      if (r)
-       return r;
-    }
-  if (release)
-    {
-      if (!r1)
-       return -1;
-      r = solv_vercmp(r1 + 1, s1, release, release + strlen(release));
-      if (r)
-       return r;
-    }
-  return 0;
-}
-
diff --git a/libsolv-0.6.15/src/evr.h b/libsolv-0.6.15/src/evr.h
deleted file mode 100644 (file)
index d18cc52..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * evr.h
- *
- */
-
-#ifndef LIBSOLV_EVR_H
-#define LIBSOLV_EVR_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "pooltypes.h"
-
-#define EVRCMP_COMPARE                 0
-#define EVRCMP_MATCH_RELEASE           1
-#define EVRCMP_MATCH                   2
-#define EVRCMP_COMPARE_EVONLY          3
-
-extern int solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2);
-
-extern int pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
-extern int pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode);
-extern int pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_EVR_H */
diff --git a/libsolv-0.6.15/src/hash.h b/libsolv-0.6.15/src/hash.h
deleted file mode 100644 (file)
index 4f595bb..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * hash.h
- * generic hash functions
- */
-
-#ifndef LIBSOLV_HASH_H
-#define LIBSOLV_HASH_H
-
-#include "pooltypes.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* value of a hash */
-typedef unsigned int Hashval;
-
-/* inside the hash table, Ids are stored. Hash maps: string -> hash -> Id */
-typedef Id *Hashtable;
-
-/* hash chain */
-#define HASHCHAIN_START 7
-#define HASHCHAIN_NEXT(h, hh, mask) (((h) + (hh)++) & (mask))
-
-/* very simple hash function
- * string -> hash
- */
-static inline Hashval
-strhash(const char *str)
-{
-  Hashval r = 0;
-  unsigned int c;
-  while ((c = *(const unsigned char *)str++) != 0)
-    r += (r << 3) + c;
-  return r;
-}
-
-static inline Hashval
-strnhash(const char *str, unsigned len)
-{
-  Hashval r = 0;
-  unsigned int c;
-  while (len-- && (c = *(const unsigned char *)str++) != 0)
-    r += (r << 3) + c;
-  return r;
-}
-
-static inline Hashval
-strhash_cont(const char *str, Hashval r)
-{
-  unsigned int c;
-  while ((c = *(const unsigned char *)str++) != 0)
-    r += (r << 3) + c;
-  return r;
-}
-
-
-/* hash for rel
- * rel -> hash
- */
-static inline Hashval
-relhash(Id name, Id evr, int flags)
-{
-  return name + 7 * evr + 13 * flags;
-}
-
-
-/* compute bitmask for value
- * returns smallest (2^n-1) > 2 * num + 3
- *
- * used for Hashtable 'modulo' operation
- */
-static inline Hashval
-mkmask(unsigned int num)
-{
-  num = num * 2 + 3;
-  while (num & (num - 1))
-    num &= num - 1;
-  return num * 2 - 1;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_HASH_H */
diff --git a/libsolv-0.6.15/src/knownid.h b/libsolv-0.6.15/src/knownid.h
deleted file mode 100644 (file)
index c094bf5..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (c) 2007-2014, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * knownid.h
- *
- */
-
-/*
- * Warning: you're free to append new entries, but insert/delete breaks
- * the ABI!
- */
-
-#ifndef LIBSOLV_KNOWNID_H
-#define LIBSOLV_KNOWNID_H
-
-#undef KNOWNID
-#ifdef KNOWNID_INITIALIZE
-# define KNOWNID(a, b) b
-static const char *initpool_data[] = {
-#else
-# define KNOWNID(a, b) a
-enum solv_knownid {
-#endif
-
-KNOWNID(ID_NULL,                       "<NULL>"),
-KNOWNID(ID_EMPTY,                      ""),
-
-/* The following Ids are stored in the solvable and must
- * come in one block */
-KNOWNID(SOLVABLE_NAME,                 "solvable:name"),
-KNOWNID(SOLVABLE_ARCH,                 "solvable:arch"),
-KNOWNID(SOLVABLE_EVR,                  "solvable:evr"),
-KNOWNID(SOLVABLE_VENDOR,               "solvable:vendor"),
-KNOWNID(SOLVABLE_PROVIDES,             "solvable:provides"),
-KNOWNID(SOLVABLE_OBSOLETES,            "solvable:obsoletes"),
-KNOWNID(SOLVABLE_CONFLICTS,            "solvable:conflicts"),
-KNOWNID(SOLVABLE_REQUIRES,             "solvable:requires"),
-KNOWNID(SOLVABLE_RECOMMENDS,           "solvable:recommends"),
-KNOWNID(SOLVABLE_SUGGESTS,             "solvable:suggests"),
-KNOWNID(SOLVABLE_SUPPLEMENTS,          "solvable:supplements"),
-KNOWNID(SOLVABLE_ENHANCES,             "solvable:enhances"),
-KNOWNID(RPM_RPMDBID,                   "rpm:dbid"),
-
-/* normal requires before this, prereqs after this */
-KNOWNID(SOLVABLE_PREREQMARKER,         "solvable:prereqmarker"),
-/* normal provides before this, generated file provides after this */
-KNOWNID(SOLVABLE_FILEMARKER,           "solvable:filemarker"),
-
-KNOWNID(NAMESPACE_INSTALLED,           "namespace:installed"),
-KNOWNID(NAMESPACE_MODALIAS,            "namespace:modalias"),
-KNOWNID(NAMESPACE_SPLITPROVIDES,       "namespace:splitprovides"),
-KNOWNID(NAMESPACE_LANGUAGE,            "namespace:language"),
-KNOWNID(NAMESPACE_FILESYSTEM,          "namespace:filesystem"),
-KNOWNID(NAMESPACE_OTHERPROVIDERS,      "namespace:otherproviders"),
-
-KNOWNID(SYSTEM_SYSTEM,                 "system:system"),
-
-/* special solvable architectures */
-KNOWNID(ARCH_SRC,                      "src"),
-KNOWNID(ARCH_NOSRC,                    "nosrc"),
-KNOWNID(ARCH_NOARCH,                   "noarch"),
-KNOWNID(ARCH_ALL,                      "all"),
-KNOWNID(ARCH_ANY,                      "any"),
-
-/* the meta tags used in solv file storage */
-KNOWNID(REPOSITORY_SOLVABLES,          "repository:solvables"),
-KNOWNID(REPOSITORY_DELTAINFO,          "repository:deltainfo"),
-
-/* sub-repository information, they will get loaded on demand */
-KNOWNID(REPOSITORY_EXTERNAL,           "repository:external"),
-KNOWNID(REPOSITORY_KEYS,               "repository:keys"),
-KNOWNID(REPOSITORY_LOCATION,           "repository:location"),
-
-/* file provides already added to our solvables */
-KNOWNID(REPOSITORY_ADDEDFILEPROVIDES,  "repository:addedfileprovides"),
-/* inode of the rpm database for rpm --rebuilddb detection */
-KNOWNID(REPOSITORY_RPMDBCOOKIE,                "repository:rpmdbcookie"),
-
-/* the known data types */
-KNOWNID(REPOKEY_TYPE_VOID,             "repokey:type:void"),
-KNOWNID(REPOKEY_TYPE_CONSTANT,         "repokey:type:constant"),
-KNOWNID(REPOKEY_TYPE_CONSTANTID,       "repokey:type:constantid"),
-KNOWNID(REPOKEY_TYPE_ID,               "repokey:type:id"),
-KNOWNID(REPOKEY_TYPE_NUM,              "repokey:type:num"),
-KNOWNID(REPOKEY_TYPE_U32,              "repokey:type:num32"),
-KNOWNID(REPOKEY_TYPE_DIR,              "repokey:type:dir"),
-KNOWNID(REPOKEY_TYPE_STR,              "repokey:type:str"),
-KNOWNID(REPOKEY_TYPE_BINARY,           "repokey:type:binary"),
-KNOWNID(REPOKEY_TYPE_IDARRAY,          "repokey:type:idarray"),
-KNOWNID(REPOKEY_TYPE_REL_IDARRAY,      "repokey:type:relidarray"),
-KNOWNID(REPOKEY_TYPE_DIRSTRARRAY,      "repokey:type:dirstrarray"),
-KNOWNID(REPOKEY_TYPE_DIRNUMNUMARRAY,   "repokey:type:dirnumnumarray"),
-KNOWNID(REPOKEY_TYPE_MD5,              "repokey:type:md5"),
-KNOWNID(REPOKEY_TYPE_SHA1,             "repokey:type:sha1"),
-KNOWNID(REPOKEY_TYPE_SHA224,           "repokey:type:sha224"),
-KNOWNID(REPOKEY_TYPE_SHA256,           "repokey:type:sha256"),
-KNOWNID(REPOKEY_TYPE_SHA384,           "repokey:type:sha384"),
-KNOWNID(REPOKEY_TYPE_SHA512,           "repokey:type:sha512"),
-KNOWNID(REPOKEY_TYPE_FIXARRAY,         "repokey:type:fixarray"),
-KNOWNID(REPOKEY_TYPE_FLEXARRAY,                "repokey:type:flexarray"),
-KNOWNID(REPOKEY_TYPE_DELETED,          "repokey:type:deleted"),        /* internal only */
-
-KNOWNID(SOLVABLE_SUMMARY,              "solvable:summary"),
-KNOWNID(SOLVABLE_DESCRIPTION,          "solvable:description"),
-KNOWNID(SOLVABLE_DISTRIBUTION,         "solvable:distribution"),
-KNOWNID(SOLVABLE_AUTHORS,              "solvable:authors"),
-KNOWNID(SOLVABLE_PACKAGER,             "solvable:packager"),
-KNOWNID(SOLVABLE_GROUP,                        "solvable:group"),
-KNOWNID(SOLVABLE_URL,                  "solvable:url"),
-KNOWNID(SOLVABLE_KEYWORDS,             "solvable:keywords"),
-KNOWNID(SOLVABLE_LICENSE,              "solvable:license"),
-KNOWNID(SOLVABLE_BUILDTIME,            "solvable:buildtime"),
-KNOWNID(SOLVABLE_BUILDHOST,            "solvable:buildhost"),
-KNOWNID(SOLVABLE_EULA,                 "solvable:eula"),
-KNOWNID(SOLVABLE_CPEID,                        "solvable:cpeid"),
-KNOWNID(SOLVABLE_MESSAGEINS,           "solvable:messageins"),
-KNOWNID(SOLVABLE_MESSAGEDEL,           "solvable:messagedel"),
-KNOWNID(SOLVABLE_INSTALLSIZE,          "solvable:installsize"),
-KNOWNID(SOLVABLE_DISKUSAGE,            "solvable:diskusage"),
-KNOWNID(SOLVABLE_FILELIST,             "solvable:filelist"),
-KNOWNID(SOLVABLE_INSTALLTIME,          "solvable:installtime"),
-KNOWNID(SOLVABLE_MEDIADIR,             "solvable:mediadir"),
-KNOWNID(SOLVABLE_MEDIAFILE,            "solvable:mediafile"),
-KNOWNID(SOLVABLE_MEDIANR,              "solvable:medianr"),
-KNOWNID(SOLVABLE_MEDIABASE,            "solvable:mediabase"),  /* <location xml:base=... > */
-KNOWNID(SOLVABLE_DOWNLOADSIZE,         "solvable:downloadsize"),
-KNOWNID(SOLVABLE_SOURCEARCH,           "solvable:sourcearch"),
-KNOWNID(SOLVABLE_SOURCENAME,           "solvable:sourcename"),
-KNOWNID(SOLVABLE_SOURCEEVR,            "solvable:sourceevr"),
-KNOWNID(SOLVABLE_ISVISIBLE,            "solvable:isvisible"),
-KNOWNID(SOLVABLE_TRIGGERS,             "solvable:triggers"),
-KNOWNID(SOLVABLE_CHECKSUM,             "solvable:checksum"),
-KNOWNID(SOLVABLE_PKGID,                        "solvable:pkgid"),      /* pkgid: md5sum over header + payload */
-KNOWNID(SOLVABLE_HDRID,                        "solvable:hdrid"),      /* hdrid: sha1sum over header only */
-KNOWNID(SOLVABLE_LEADSIGID,            "solvable:leadsigid"),  /* leadsigid: md5sum over lead + sigheader */
-
-KNOWNID(SOLVABLE_PATCHCATEGORY,                "solvable:patchcategory"),
-KNOWNID(SOLVABLE_HEADEREND,            "solvable:headerend"),
-KNOWNID(SOLVABLE_CHANGELOG,            "solvable:changelog"),
-KNOWNID(SOLVABLE_CHANGELOG_AUTHOR,     "solvable:changelog:author"),
-KNOWNID(SOLVABLE_CHANGELOG_TIME,       "solvable:changelog:time"),
-KNOWNID(SOLVABLE_CHANGELOG_TEXT,       "solvable:changelog:text"),
-
-/* stuff for solvables of type pattern */
-KNOWNID(SOLVABLE_CATEGORY,             "solvable:category"),
-KNOWNID(SOLVABLE_INCLUDES,             "solvable:includes"),
-KNOWNID(SOLVABLE_EXTENDS,              "solvable:extends"),
-KNOWNID(SOLVABLE_ICON,                 "solvable:icon"),
-KNOWNID(SOLVABLE_ORDER,                        "solvable:order"),
-
-/* extra definitions for updates (i.e. patch: solvables) */
-KNOWNID(UPDATE_REBOOT,                 "update:reboot"),       /* reboot suggested (kernel update) */
-KNOWNID(UPDATE_RESTART,                        "update:restart"),      /* restart suggested (update stack update) */
-KNOWNID(UPDATE_RELOGIN,                        "update:relogin"),      /* relogin suggested */
-
-KNOWNID(UPDATE_MESSAGE,                        "update:message"),      /* informative message */
-KNOWNID(UPDATE_SEVERITY,               "update:severity"),     /* "Important", ...*/
-KNOWNID(UPDATE_RIGHTS,                 "update:rights"),       /* copyright */
-
-/* 'content' of patch, usually list of packages */
-KNOWNID(UPDATE_COLLECTION,             "update:collection"),          /*  "name evr arch" */
-KNOWNID(UPDATE_COLLECTION_NAME,                "update:collection:name"),     /*   name */
-KNOWNID(UPDATE_COLLECTION_EVR,         "update:collection:evr"),      /*   epoch:version-release */
-KNOWNID(UPDATE_COLLECTION_ARCH,                "update:collection:arch"),     /*   architecture */
-KNOWNID(UPDATE_COLLECTION_FILENAME,    "update:collection:filename"), /*   filename (of rpm) */
-KNOWNID(UPDATE_COLLECTION_FLAGS,       "update:collection:flags"),    /*   reboot(1)/restart(2) suggested if this rpm gets updated */
-
-KNOWNID(UPDATE_REFERENCE,              "update:reference"),            /* external references for the update */
-KNOWNID(UPDATE_REFERENCE_TYPE,         "update:reference:type"),       /*  type, e.g. 'bugzilla' or 'cve' */
-KNOWNID(UPDATE_REFERENCE_HREF,         "update:reference:href"),       /*  href, e.g. 'http://bugzilla...' */
-KNOWNID(UPDATE_REFERENCE_ID,           "update:reference:id"),         /*  id, e.g. bug number */
-KNOWNID(UPDATE_REFERENCE_TITLE,                "update:reference:title"),      /*  title, e.g. "the bla forz scribs on fuggle" */
-
-/* extra definitions for products */
-KNOWNID(PRODUCT_REFERENCEFILE,         "product:referencefile"),       /* installed product only */
-KNOWNID(PRODUCT_SHORTLABEL,            "product:shortlabel"),          /* not in repomd? */
-KNOWNID(PRODUCT_DISTPRODUCT,           "product:distproduct"),         /* obsolete */
-KNOWNID(PRODUCT_DISTVERSION,           "product:distversion"),         /* obsolete */
-KNOWNID(PRODUCT_TYPE,                  "product:type"),                /* e.g. 'base' */
-KNOWNID(PRODUCT_URL,                   "product:url"),
-KNOWNID(PRODUCT_URL_TYPE,              "product:url:type"),
-KNOWNID(PRODUCT_FLAGS,                 "product:flags"),               /* e.g. 'update', 'no_you' */
-KNOWNID(PRODUCT_PRODUCTLINE,           "product:productline"),         /* installed product only */
-KNOWNID(PRODUCT_REGISTER_TARGET,       "product:regtarget"),           /* installed and available product */
-KNOWNID(PRODUCT_REGISTER_RELEASE,      "product:regrelease"),          /* installed product only */
-KNOWNID(PRODUCT_UPDATES_REPOID,                "product:updates:repoid"),
-KNOWNID(PRODUCT_UPDATES,               "product:updates"),
-KNOWNID(PRODUCT_ENDOFLIFE,             "product:endoflife"),
-
-/* argh, should rename to repository and unify with REPOMD */
-KNOWNID(SUSETAGS_DATADIR,              "susetags:datadir"),
-KNOWNID(SUSETAGS_DESCRDIR,             "susetags:descrdir"),
-KNOWNID(SUSETAGS_DEFAULTVENDOR,                "susetags:defaultvendor"),
-KNOWNID(SUSETAGS_FILE,                 "susetags:file"),
-KNOWNID(SUSETAGS_FILE_NAME,            "susetags:file:name"),
-KNOWNID(SUSETAGS_FILE_TYPE,            "susetags:file:type"),
-KNOWNID(SUSETAGS_FILE_CHECKSUM,                "susetags:file:checksum"),
-KNOWNID(SUSETAGS_SHARE_NAME,           "susetags:share:name"),
-KNOWNID(SUSETAGS_SHARE_EVR,            "susetags:share:evr"),
-KNOWNID(SUSETAGS_SHARE_ARCH,           "susetags:share:arch"),
-
-/* timestamp then the repository was generated */
-KNOWNID(REPOSITORY_TIMESTAMP,          "repository:timestamp"),
-/* hint when the metadata could be outdated w/respect to generated timestamp */
-KNOWNID(REPOSITORY_EXPIRE,             "repository:expire"),
-/* which things does this repo provides updates for, if it does (array) */
-KNOWNID(REPOSITORY_UPDATES,            "repository:updates"),          /* obsolete? */
-/* which products this repository is supposed to be for (array) */
-KNOWNID(REPOSITORY_DISTROS,            "repository:distros"),
-KNOWNID(REPOSITORY_PRODUCT_LABEL,       "repository:product:label"),
-KNOWNID(REPOSITORY_PRODUCT_CPEID,      "repository:product:cpeid"),
-KNOWNID(REPOSITORY_REPOID,             "repository:repoid"),           /* obsolete? */
-/* keyword (tags) for this repository */
-KNOWNID(REPOSITORY_KEYWORDS,           "repository:keywords"),
-/* revision of the repository. arbitrary string */
-KNOWNID(REPOSITORY_REVISION,           "repository:revision"),
-KNOWNID(REPOSITORY_TOOLVERSION,                "repository:toolversion"),
-
-KNOWNID(DELTA_PACKAGE_NAME,            "delta:pkgname"),
-KNOWNID(DELTA_PACKAGE_EVR,             "delta:pkgevr"),
-KNOWNID(DELTA_PACKAGE_ARCH,            "delta:pkgarch"),
-KNOWNID(DELTA_LOCATION_DIR,            "delta:locdir"),
-KNOWNID(DELTA_LOCATION_NAME,           "delta:locname"),
-KNOWNID(DELTA_LOCATION_EVR,            "delta:locevr"),
-KNOWNID(DELTA_LOCATION_SUFFIX,         "delta:locsuffix"),
-KNOWNID(DELTA_DOWNLOADSIZE,            "delta:downloadsize"),
-KNOWNID(DELTA_CHECKSUM,                        "delta:checksum"),
-KNOWNID(DELTA_BASE_EVR,                        "delta:baseevr"),
-KNOWNID(DELTA_SEQ_NAME,                        "delta:seqname"),
-KNOWNID(DELTA_SEQ_EVR,                 "delta:seqevr"),
-KNOWNID(DELTA_SEQ_NUM,                 "delta:seqnum"),
-KNOWNID(DELTA_LOCATION_BASE,           "delta:locbase"),       /* <location xml:base=... > */
-
-KNOWNID(REPOSITORY_REPOMD,             "repository:repomd"),
-KNOWNID(REPOSITORY_REPOMD_TYPE,                "repository:repomd:type"),
-KNOWNID(REPOSITORY_REPOMD_LOCATION,    "repository:repomd:location"),
-KNOWNID(REPOSITORY_REPOMD_TIMESTAMP,   "repository:repomd:timestamp"),
-KNOWNID(REPOSITORY_REPOMD_CHECKSUM,    "repository:repomd:checksum"),
-KNOWNID(REPOSITORY_REPOMD_OPENCHECKSUM,        "repository:repomd:openchecksum"),
-KNOWNID(REPOSITORY_REPOMD_SIZE,                "repository:repomd:size"),
-
-KNOWNID(PUBKEY_KEYID,                  "pubkey:keyid"),
-KNOWNID(PUBKEY_FINGERPRINT,            "pubkey:fingerprint"),
-KNOWNID(PUBKEY_EXPIRES,                        "pubkey:expires"),
-KNOWNID(PUBKEY_SIGNATURES,             "pubkey:signatures"),
-KNOWNID(PUBKEY_DATA,                   "pubkey:data"),
-KNOWNID(PUBKEY_SUBKEYOF,               "pubkey:subkeyof"),
-
-KNOWNID(SIGNATURE_ISSUER,              "signature:issuer"),
-KNOWNID(SIGNATURE_TIME,                        "signature:time"),
-KNOWNID(SIGNATURE_EXPIRES,             "signature:expires"),
-KNOWNID(SIGNATURE_DATA,                        "signature:data"),
-
-KNOWNID(PRODUCT_REGISTER_FLAVOR,       "product:regflavor"),           /* installed and available product */
-
-KNOWNID(SOLVABLE_INSTALLSTATUS,                "solvable:installstatus"),      /* debian install status */
-
-KNOWNID(ID_NUM_INTERNAL,               0)
-
-#ifdef KNOWNID_INITIALIZE
-};
-#else
-};
-#endif
-
-#undef KNOWNID
-
-#endif
-
-
diff --git a/libsolv-0.6.15/src/libsolv.ver b/libsolv-0.6.15/src/libsolv.ver
deleted file mode 100644 (file)
index 6508288..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-SOLV_1.0 {
-       global:
-               dataiterator_clonepos;
-               dataiterator_entersub;
-               dataiterator_free;
-               dataiterator_init;
-               dataiterator_init_clone;
-               dataiterator_jump_to_repo;
-               dataiterator_jump_to_solvid;
-               dataiterator_match;
-               dataiterator_prepend_keyname;
-               dataiterator_seek;
-               dataiterator_set_keyname;
-               dataiterator_set_match;
-               dataiterator_set_search;
-               dataiterator_setpos;
-               dataiterator_setpos_parent;
-               dataiterator_skip_attribute;
-               dataiterator_skip_repo;
-               dataiterator_skip_solvable;
-               dataiterator_step;
-               dataiterator_strdup;
-               datamatcher_free;
-               datamatcher_init;
-               datamatcher_match;
-               dirpool_add_dir;
-               dirpool_free;
-               dirpool_init;
-               dirpool_make_dirtraverse;
-               map_and;
-               map_subtract;
-               map_free;
-               map_grow;
-               map_init;
-               map_init_clone;
-               map_or;
-               policy_filter_unwanted;
-               policy_findupdatepackages;
-               policy_illegal2str;
-               policy_illegal_archchange;
-               policy_illegal_vendorchange;
-               policy_is_illegal;
-               pool_add_fileconflicts_deps;
-               pool_add_userinstalled_jobs;
-               pool_addfileprovides;
-               pool_addfileprovides_queue;
-               pool_addrelproviders;
-               pool_addvendorclass;
-               pool_alloctmpspace;
-               pool_arch2color_slow;
-               pool_bin2hex;
-               pool_calc_duchanges;
-               pool_calc_installsizechange;
-               pool_clear_pos;
-               pool_create;
-               pool_create_state_maps;
-               pool_createwhatprovides;
-               pool_debug;
-               pool_dep2str;
-               pool_error;
-               pool_errstr;
-               pool_evrcmp;
-               pool_evrcmp_str;
-               pool_evrmatch;
-               pool_flush_namespaceproviders;
-               pool_free;
-               pool_freeallrepos;
-               pool_freeidhashes;
-               pool_freetmpspace;
-               pool_freewhatprovides;
-               pool_get_flag;
-               pool_get_rootdir;
-               pool_id2evr;
-               pool_id2langid;
-               pool_id2rel;
-               pool_id2str;
-               pool_ids2whatprovides;
-               pool_intersect_evrs;
-               pool_isemptyupdatejob;
-               pool_job2solvables;
-               pool_job2str;
-               pool_lookup_bin_checksum;
-               pool_lookup_checksum;
-               pool_lookup_deltalocation;
-               pool_lookup_id;
-               pool_lookup_idarray;
-               pool_lookup_num;
-               pool_lookup_str;
-               pool_lookup_void;
-               pool_match_dep;
-               pool_match_nevr_rel;
-               pool_prepend_rootdir;
-               pool_prepend_rootdir_tmp;
-               pool_queuetowhatprovides;
-               pool_rel2id;
-               pool_search;
-               pool_selection2str;
-               pool_set_custom_vendorcheck;
-               pool_set_flag;
-               pool_set_installed;
-               pool_set_languages;
-               pool_set_rootdir;
-               pool_setarch;
-               pool_setarchpolicy;
-               pool_setdebugcallback;
-               pool_setdebuglevel;
-               pool_setdebugmask;
-               pool_setdisttype;
-               pool_setloadcallback;
-               pool_setnamespacecallback;
-               pool_setvendorclasses;
-               pool_shrink_rels;
-               pool_shrink_strings;
-               pool_solvable2str;
-               pool_str2id;
-               pool_strn2id;
-               pool_tmpappend;
-               pool_tmpjoin;
-               pool_trivial_installable;
-               pool_trivial_installable_multiversionmap;
-               pool_vendor2mask;
-               pool_whatmatchesdep;
-               queue_alloc_one;
-               queue_alloc_one_head;
-               queue_delete;
-               queue_delete2;
-               queue_deleten;
-               queue_free;
-               queue_init;
-               queue_init_buffer;
-               queue_init_clone;
-               queue_insert;
-               queue_insert2;
-               queue_insertn;
-               queue_prealloc;
-               repo_add_deparray;
-               repo_add_idarray;
-               repo_add_poolstr_array;
-               repo_add_repodata;
-               repo_add_solv;
-               repo_add_solvable;
-               repo_add_solvable_block;
-               repo_add_solvable_block_before;
-               repo_addid;
-               repo_addid_dep;
-               repo_create;
-               repo_disable_paging;
-               repo_empty;
-               repo_fix_conflicts;
-               repo_fix_supplements;
-               repo_free;
-               repo_free_solvable;
-               repo_free_solvable_block;
-               repo_id2repodata;
-               repo_internalize;
-               repo_last_repodata;
-               repo_lookup_bin_checksum;
-               repo_lookup_binary;
-               repo_lookup_checksum;
-               repo_lookup_deparray;
-               repo_lookup_id;
-               repo_lookup_idarray;
-               repo_lookup_num;
-               repo_lookup_str;
-               repo_lookup_type;
-               repo_lookup_void;
-               repo_matchvalue;
-               repo_reserve_ids;
-               repo_search;
-               repo_set_deparray;
-               repo_set_id;
-               repo_set_idarray;
-               repo_set_num;
-               repo_set_poolstr;
-               repo_set_str;
-               repo_sidedata_create;
-               repo_unset;
-               repo_write;
-               repo_write_filtered;
-               repo_write_stdkeyfilter;
-               repodata_add_dirnumnum;
-               repodata_add_dirstr;
-               repodata_add_fixarray;
-               repodata_add_flexarray;
-               repodata_add_idarray;
-               repodata_add_poolstr_array;
-               repodata_chk2str;
-               repodata_create_stubs;
-               repodata_dir2str;
-               repodata_disable_paging;
-               repodata_empty;
-               repodata_extend;
-               repodata_extend_block;
-               repodata_free;
-               repodata_free_dircache;
-               repodata_free_schemahash;
-               repodata_freedata;
-               repodata_globalize_id;
-               repodata_initdata;
-               repodata_internalize;
-               repodata_key2id;
-               repodata_localize_id;
-               repodata_lookup_bin_checksum;
-               repodata_lookup_binary;
-               repodata_lookup_dirstrarray_uninternalized;
-               repodata_lookup_id;
-               repodata_lookup_id_uninternalized;
-               repodata_lookup_idarray;
-               repodata_lookup_num;
-               repodata_lookup_str;
-               repodata_lookup_type;
-               repodata_lookup_void;
-               repodata_memused;
-               repodata_merge_attrs;
-               repodata_merge_some_attrs;
-               repodata_new_handle;
-               repodata_schema2id;
-               repodata_search;
-               repodata_set_binary;
-               repodata_set_bin_checksum;
-               repodata_set_checksum;
-               repodata_set_constant;
-               repodata_set_constantid;
-               repodata_set_deltalocation;
-               repodata_set_id;
-               repodata_set_idarray;
-               repodata_set_location;
-               repodata_set_num;
-               repodata_set_poolstr;
-               repodata_set_sourcepkg;
-               repodata_set_str;
-               repodata_set_void;
-               repodata_setpos_kv;
-               repodata_shrink;
-               repodata_str2dir;
-               repodata_stringify;
-               repodata_swap_attrs;
-               repodata_translate_id;
-               repodata_unset;
-               repodata_unset_uninternalized;
-               repodata_write;
-               repodata_write_filtered;
-               repopagestore_compress_page;
-               selection_add;
-               selection_filter;
-               selection_make;
-               selection_make_matchdeps;
-               selection_solvables;
-               solv_bin2hex;
-               solv_calloc;
-               solv_chksum_add;
-               solv_chksum_cmp;
-               solv_chksum_create;
-               solv_chksum_create_clone;
-               solv_chksum_create_from_bin;
-               solv_chksum_free;
-               solv_chksum_get;
-               solv_chksum_get_type;
-               solv_chksum_isfinished;
-               solv_chksum_len;
-               solv_chksum_str2type;
-               solv_chksum_type2str;
-               solv_depmarker;
-               solv_dupappend;
-               solv_dupjoin;
-               solv_extend_realloc;
-               solv_free;
-               solv_hex2bin;
-               solv_latin1toutf8;
-               solv_malloc;
-               solv_malloc2;
-               solv_oom;
-               solv_realloc;
-               solv_realloc2;
-               solv_replacebadutf8;
-               solv_sort;
-               solv_strdup;
-               solv_timems;
-               solv_validutf8;
-               solv_vercmp;
-               solv_vercmp_deb;
-               solv_vercmp_haiku;
-               solv_vercmp_rpm;
-               solv_vercmp_rpm_notilde;
-               solv_version;
-               solv_version_major;
-               solv_version_minor;
-               solv_version_patch;
-               solvable_add_deparray;
-               solvable_add_idarray;
-               solvable_add_poolstr_array;
-               solvable_get_location;
-               solvable_identical;
-               solvable_lookup_bin_checksum;
-               solvable_lookup_bool;
-               solvable_lookup_checksum;
-               solvable_lookup_deparray;
-               solvable_lookup_id;
-               solvable_lookup_idarray;
-               solvable_lookup_location;
-               solvable_lookup_num;
-               solvable_lookup_sizek;
-               solvable_lookup_sourcepkg;
-               solvable_lookup_str;
-               solvable_lookup_str_lang;
-               solvable_lookup_str_poollang;
-               solvable_lookup_type;
-               solvable_lookup_void;
-               solvable_selfprovidedep;
-               solvable_set_deparray;
-               solvable_set_id;
-               solvable_set_idarray;
-               solvable_set_num;
-               solvable_set_poolstr;
-               solvable_set_str;
-               solvable_trivial_installable_map;
-               solvable_trivial_installable_queue;
-               solvable_trivial_installable_repo;
-               solvable_unset;
-               solver_allruleinfos;
-               solver_alternative2str;
-               solver_alternatives_count;
-               solver_calc_duchanges;
-               solver_calc_installsizechange;
-               solver_calculate_multiversionmap;
-               solver_calculate_noobsmap;
-               solver_create;
-               solver_create_state_maps;
-               solver_create_transaction;
-               solver_describe_decision;
-               solver_describe_weakdep_decision;
-               solver_disableproblem;
-               solver_enableproblem;
-               solver_findallproblemrules;
-               solver_findproblemrule;
-               solver_free;
-               solver_freedupmaps;
-               solver_get_alternative;
-               solver_get_decisionblock;
-               solver_get_decisionlevel;
-               solver_get_decisionqueue;
-               solver_get_flag;
-               solver_get_lastdecisionblocklevel;
-               solver_get_orphaned;
-               solver_get_recommendations;
-               solver_get_unneeded;
-               solver_get_userinstalled;
-               solver_next_problem;
-               solver_next_solution;
-               solver_next_solutionelement;
-               solver_prepare_solutions;
-               solver_printallsolutions;
-               solver_printcompleteprobleminfo;
-               solver_printdecisionq;
-               solver_printdecisions;
-               solver_printproblem;
-               solver_printprobleminfo;
-               solver_printproblemruleinfo;
-               solver_printrule;
-               solver_printruleclass;
-               solver_printruleelement;
-               solver_printsolution;
-               solver_printtrivial;
-               solver_printwatches;
-               solver_problem2str;
-               solver_problem_count;
-               solver_problemruleinfo2str;
-               solver_rule2job;
-               solver_rule2jobidx;
-               solver_rule2pkgrule;
-               solver_rule2rules;
-               solver_rule2solvable;
-               solver_ruleclass;
-               solver_ruleinfo;
-               solver_ruleliterals;
-               solver_rulecmp;
-               solver_select2str;
-               solver_set_flag;
-               solver_solution_count;
-               solver_solutionelement2str;
-               solver_solutionelement_count;
-               solver_solutionelement_internalid;
-               solver_solutionelement_extrajobflags;
-               solver_solve;
-               solver_take_solution;
-               solver_take_solutionelement;
-               solver_trivial_installable;
-               solver_unifyrules;
-               stringpool_clone;
-               stringpool_free;
-               stringpool_freehash;
-               stringpool_init;
-               stringpool_init_empty;
-               stringpool_shrink;
-               stringpool_str2id;
-               stringpool_strn2id;
-               transaction_add_obsoleted;
-               transaction_all_obs_pkgs;
-               transaction_calc_duchanges;
-               transaction_calc_installsizechange;
-               transaction_check_order;
-               transaction_classify;
-               transaction_classify_pkgs;
-               transaction_create;
-               transaction_create_clone;
-               transaction_create_decisionq;
-               transaction_free;
-               transaction_free_orderdata;
-               transaction_installedresult;
-               transaction_obs_pkg;
-               transaction_order;
-               transaction_order_add_choices;
-               transaction_order_get_cycle;
-               transaction_order_get_cycleids;
-               transaction_print;
-               transaction_type;
-       local:
-               *;
-};
diff --git a/libsolv-0.6.15/src/linkedpkg.c b/libsolv-0.6.15/src/linkedpkg.c
deleted file mode 100644 (file)
index 6387373..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2013, SUSE Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * linkedpkg.c
- *
- * Linked packages are "pseudo" packages that are bound to real packages but
- * contain different information (name/summary/description). They are normally
- * somehow generated from the real packages, either when the repositories are
- * created or automatically from the packages by looking at the provides.
- *
- * We currently support:
- *
- * application:
- *   created from AppStream appdata xml in the repository (which is generated
- *   from files in /usr/share/appdata)
- *
- * product:
- *   created from product data in the repository (which is generated from files
- *   in /etc/products.d). In the future we may switch to using product()
- *   provides of packages.
- *
- * pattern:
- *   created from pattern() provides of packages.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "evr.h"
-#include "linkedpkg.h"
-
-#ifdef ENABLE_LINKED_PKGS
-
-void
-find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
-{
-  Id req = 0;
-  Id prv = 0;
-  Id p, pp;
-  Id pkgname = 0, appdataid = 0;
-
-  /* find appdata requires */
-  if (s->requires)
-    {
-      Id *reqp = s->repo->idarraydata + s->requires;
-      while ((req = *reqp++) != 0)            /* go through all requires */
-       {
-         if (ISRELDEP(req))
-           continue;
-         if (!strncmp("appdata(", pool_id2str(pool, req), 8))
-           appdataid = req;
-         else
-           pkgname = req;
-       }
-    }
-  req = appdataid ? appdataid : pkgname;
-  if (!req)
-    return;
-  /* find application-appdata provides */
-  if (s->provides)
-    {
-      Id *prvp = s->repo->idarraydata + s->provides;
-      const char *reqs = pool_id2str(pool, req);
-      const char *prvs;
-      while ((prv = *prvp++) != 0)            /* go through all provides */
-       {
-         if (ISRELDEP(prv))
-           continue;
-         prvs = pool_id2str(pool, prv);
-         if (strncmp("application-appdata(", prvs, 20))
-           continue;
-         if (appdataid)
-           {
-             if (!strcmp(prvs + 12, reqs))
-               break;
-           }
-         else
-           {
-             int reqsl = strlen(reqs);
-             if (!strncmp(prvs + 20, reqs, reqsl) && !strcmp(prvs + 20 + reqsl, ")"))
-               break;
-           }
-       }
-    }
-  if (!prv)
-    return;    /* huh, no provides found? */
-  /* now link em */
-  FOR_PROVIDES(p, pp, req)
-    if (pool->solvables[p].repo == s->repo)
-      if (!pkgname || pool->solvables[p].name == pkgname)
-        queue_push(qr, p);
-  if (!qr->count && pkgname && appdataid)
-    {
-      /* huh, no matching package? try without pkgname filter */
-      FOR_PROVIDES(p, pp, req)
-       if (pool->solvables[p].repo == s->repo)
-          queue_push(qr, p);
-    }
-  if (qp)
-    {
-      FOR_PROVIDES(p, pp, prv)
-       if (pool->solvables[p].repo == s->repo)
-         queue_push(qp, p);
-    }
-  if (reqidp)
-    *reqidp = req;
-  if (prvidp)
-    *prvidp = prv;
-}
-
-void
-find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
-{
-  Id p, pp, namerelid;
-  char *str;
-  unsigned int sbt = 0;
-
-  /* search for project requires */
-  namerelid = 0;
-  if (s->requires)
-    {
-      Id req, *reqp = s->repo->idarraydata + s->requires;
-      const char *nn = pool_id2str(pool, s->name);
-      int nnl = strlen(nn);
-      while ((req = *reqp++) != 0)            /* go through all requires */
-       if (ISRELDEP(req))
-         {
-           const char *rn;
-           Reldep *rd = GETRELDEP(pool, req);
-           if (rd->flags != REL_EQ || rd->evr != s->evr)
-             continue;
-           rn = pool_id2str(pool, rd->name);
-           if (!strncmp(rn, "product(", 8) && !strncmp(rn + 8, nn + 8, nnl - 8) && !strcmp( rn + nnl, ")"))
-             {
-               namerelid = req;
-               break;
-             }
-         }
-    }
-  if (!namerelid)
-    {
-      /* too bad. construct from scratch */
-      str = pool_tmpjoin(pool, pool_id2str(pool, s->name), ")", 0);
-      str[7] = '(';
-      namerelid = pool_rel2id(pool, pool_str2id(pool, str, 1), s->evr, REL_EQ, 1);
-    }
-  FOR_PROVIDES(p, pp, namerelid)
-    {
-      Solvable *ps = pool->solvables + p;
-      if (ps->repo != s->repo || ps->arch != s->arch)
-       continue;
-      queue_push(qr, p);
-    }
-  if (qr->count > 1)
-    {
-      /* multiple providers. try buildtime filter */
-      sbt = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
-      if (sbt)
-       {
-         unsigned int bt;
-         int i, j;
-         int filterqp = 1;
-         for (i = j = 0; i < qr->count; i++)
-           {
-             bt = solvable_lookup_num(pool->solvables + qr->elements[i], SOLVABLE_BUILDTIME, 0);
-             if (!bt)
-               filterqp = 0;   /* can't filter */
-             if (!bt || bt == sbt)
-               qr->elements[j++] = qr->elements[i];
-           }
-         if (j)
-           qr->count = j;
-         if (!j || !filterqp)
-           sbt = 0;    /* filter failed */
-       }
-    }
-  if (!qr->count && s->repo == pool->installed)
-    {
-      /* oh no! Look up reference file */
-      Dataiterator di;
-      const char *refbasename = solvable_lookup_str(s, PRODUCT_REFERENCEFILE);
-      dataiterator_init(&di, pool, s->repo, 0, SOLVABLE_FILELIST, refbasename, SEARCH_STRING);
-      while (dataiterator_step(&di))
-       queue_push(qr, di.solvid);
-      dataiterator_free(&di);
-      if (qp)
-       {
-         dataiterator_init(&di, pool, s->repo, 0, PRODUCT_REFERENCEFILE, refbasename, SEARCH_STRING);
-         while (dataiterator_step(&di))
-           queue_push(qp, di.solvid);
-         dataiterator_free(&di);
-       }
-    }
-  else if (qp)
-    {
-      /* find qp */
-      FOR_PROVIDES(p, pp, s->name)
-       {
-         Solvable *ps = pool->solvables + p;
-         if (s->name != ps->name || ps->repo != s->repo || ps->arch != s->arch || s->evr != ps->evr)
-           continue;
-         if (sbt && solvable_lookup_num(ps, SOLVABLE_BUILDTIME, 0) != sbt)
-           continue;
-         queue_push(qp, p);
-       }
-    }
-  if (reqidp)
-    *reqidp = namerelid;
-  if (prvidp)
-    *prvidp = solvable_selfprovidedep(s);
-}
-
-void
-find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
-{
-  Id p, pp, *pr, apevr = 0, aprel = 0;
-
-  /* check if autopattern */
-  if (!s->provides)
-    return;
-  for (pr = s->repo->idarraydata + s->provides; (p = *pr++) != 0; )
-    if (ISRELDEP(p))
-      {
-       Reldep *rd = GETRELDEP(pool, p);
-       if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
-         {
-           aprel = p;
-           apevr = rd->evr;
-           break;
-         }
-      }
-  if (!apevr)
-    return;
-  FOR_PROVIDES(p, pp, apevr)
-    {
-      Solvable *s2 = pool->solvables + p;
-      if (s2->repo == s->repo && s2->name == apevr && s2->evr == s->evr && s2->vendor == s->vendor)
-        queue_push(qr, p);
-    }
-  if (qp)
-    {
-      FOR_PROVIDES(p, pp, aprel)
-       {
-         Solvable *s2 = pool->solvables + p;
-         if (s2->repo == s->repo && s2->evr == s->evr && s2->vendor == s->vendor)
-           queue_push(qp, p);
-       }
-    }
-  if (reqidp)
-    *reqidp = apevr;
-  if (prvidp)
-    *prvidp = aprel;
-}
-
-/* the following two functions are used in solvable_lookup_str_base to do
- * translated lookups on the product/pattern packages
- */
-Id
-find_autopattern_name(Pool *pool, Solvable *s)
-{
-  Id prv, *prvp;
-  if (!s->provides)
-    return 0;
-  for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
-    if (ISRELDEP(prv))
-      {
-        Reldep *rd = GETRELDEP(pool, prv);
-        if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
-          return strncmp(pool_id2str(pool, rd->evr), "pattern:", 8) != 0 ? rd->evr : 0;
-      }
-  return 0;
-}
-
-Id
-find_autoproduct_name(Pool *pool, Solvable *s)
-{
-  Id prv, *prvp;
-  if (!s->provides)
-    return 0;
-  for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
-    if (ISRELDEP(prv))
-      {
-        Reldep *rd = GETRELDEP(pool, prv);
-        if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autoproduct()"))
-          return strncmp(pool_id2str(pool, rd->evr), "product:", 8) != 0 ? rd->evr : 0;
-      }
-  return 0;
-}
-
-void
-find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
-{
-  const char *name = pool_id2str(pool, s->name);
-  if (name[0] == 'a' && !strncmp("application:", name, 12))
-    find_application_link(pool, s, reqidp, qr, prvidp, qp);
-  else if (name[0] == 'p' && !strncmp("pattern:", name, 7))
-    find_pattern_link(pool, s, reqidp, qr, prvidp, qp);
-  else if (name[0] == 'p' && !strncmp("product:", name, 8))
-    find_product_link(pool, s, reqidp, qr, prvidp, qp);
-}
-
-static int
-name_min_max(Pool *pool, Solvable *s, Id *namep, Id *minp, Id *maxp)
-{
-  Queue q;
-  Id qbuf[4];
-  Id name, min, max;
-  int i;
-
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  find_package_link(pool, s, 0, &q, 0, 0);
-  if (!q.count)
-    {
-      queue_free(&q);
-      return 0;
-    }
-  s = pool->solvables + q.elements[0];
-  name = s->name;
-  min = max = s->evr;
-  for (i = 1; i < q.count; i++)
-    {
-      s = pool->solvables + q.elements[i];
-      if (s->name != name)
-       {
-          queue_free(&q);
-         return 0;
-       }
-      if (s->evr == min || s->evr == max)
-       continue;
-      if (pool_evrcmp(pool, min, s->evr, EVRCMP_COMPARE) >= 0)
-       min = s->evr;
-      else if (min == max || pool_evrcmp(pool, max, s->evr, EVRCMP_COMPARE) <= 0)
-       max = s->evr;
-    }
-  queue_free(&q);
-  *namep = name;
-  *minp = min;
-  *maxp = max;
-  return 1;
-}
-
-int
-pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2)
-{
-  Id name1, evrmin1, evrmax1;
-  Id name2, evrmin2, evrmax2;
-
-  if (s1->name != s2->name)
-    return 0;  /* can't compare */
-  if (!name_min_max(pool, s1, &name1, &evrmin1, &evrmax1))
-    return 0;
-  if (!name_min_max(pool, s2, &name2, &evrmin2, &evrmax2))
-    return 0;
-  /* compare linked names */
-  if (name1 != name2)
-    return 0;
-  if (evrmin1 == evrmin2 && evrmax1 == evrmax2)
-    return 0;
-  /* now compare evr intervals */
-  if (evrmin1 == evrmax1 && evrmin2 == evrmax2)
-    return pool_evrcmp(pool, evrmin1, evrmax2, EVRCMP_COMPARE);
-  if (evrmin1 != evrmax2 && pool_evrcmp(pool, evrmin1, evrmax2, EVRCMP_COMPARE) > 0)
-    return 1;
-  if (evrmax1 != evrmin2 && pool_evrcmp(pool, evrmax1, evrmin2, EVRCMP_COMPARE) < 0)
-    return -1;
-  return 0;
-}
-
-
-#endif
diff --git a/libsolv-0.6.15/src/linkedpkg.h b/libsolv-0.6.15/src/linkedpkg.h
deleted file mode 100644 (file)
index 4463280..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * linkedpkg.h (internal)
- */
-
-#ifndef LIBSOLV_LINKEDPKG_H
-#define LIBSOLV_LINKEDPKG_H
-
-static inline int
-has_package_link(Pool *pool, Solvable *s)
-{
-  const char *name = pool_id2str(pool, s->name);
-  if (name[0] == 'a' && !strncmp("application:", name, 12))
-    return 1;
-  if (name[0] == 'p' && !strncmp("pattern:", name, 7))
-    return 1;
-  if (name[0] == 'p' && !strncmp("product:", name, 8))
-    return 1;
-  return 0;
-}
-
-extern void find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-extern void find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-extern void find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-
-extern Id find_autopattern_name(Pool *pool, Solvable *s);
-extern Id find_autoproduct_name(Pool *pool, Solvable *s);
-
-/* generic */
-extern void find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
-extern int pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2);
-
-#endif
diff --git a/libsolv-0.6.15/src/md5.c b/libsolv-0.6.15/src/md5.c
deleted file mode 100644 (file)
index 0431b50..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * This is an OpenSSL-compatible implementation of the RSA Data Security,
- * Inc. MD5 Message-Digest Algorithm.
- *
- * Written by Solar Designer <solar@openwall.com> in 2001, and placed in
- * the public domain.
- *
- * This differs from Colin Plumb's older public domain implementation in
- * that no 32-bit integer data type is required, there's no compile-time
- * endianness configuration, and the function prototypes match OpenSSL's.
- * The primary goals are portability and ease of use.
- *
- * This implementation is meant to be fast, but not as fast as possible.
- * Some known optimizations are not included to reduce source code size
- * and avoid compile-time configuration.
- */
-
-#include <string.h>
-#include "md5.h"
-
-
-/*
- * The basic MD5 functions.
- *
- * F is optimized compared to its RFC 1321 definition just like in Colin
- * Plumb's implementation.
- */
-#define F(x, y, z)                     ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z)                     ((y) ^ ((z) & ((x) ^ (y))))
-#define H(x, y, z)                     ((x) ^ (y) ^ (z))
-#define I(x, y, z)                     ((y) ^ ((x) | ~(z)))
-
-/*
- * The MD5 transformation for all four rounds.
- */
-#define STEP(f, a, b, c, d, x, t, s) \
-       (a) += f((b), (c), (d)) + (x) + (t); \
-       (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
-       (a) += (b);
-
-/*
- * SET reads 4 input bytes in little-endian byte order and stores them
- * in a properly aligned word in host byte order.
- *
- * The check for little-endian architectures which tolerate unaligned
- * memory accesses is just an optimization.  Nothing will break if it
- * doesn't work.
- */
-#if defined(__i386__) || defined(__vax__)
-#define SET(n) \
-       (*(MD5_u32plus *)&ptr[(n) * 4])
-#define GET(n) \
-       SET(n)
-#else
-#define SET(n) \
-       (ctx->block[(n)] = \
-       (MD5_u32plus)ptr[(n) * 4] | \
-       ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
-       ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
-       ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
-#define GET(n) \
-       (ctx->block[(n)])
-#endif
-
-/*
- * This processes one or more 64-byte data blocks, but does NOT update
- * the bit counters.  There're no alignment requirements.
- */
-static void *body(MD5_CTX *ctx, void *data, unsigned long size)
-{
-       unsigned char *ptr;
-       MD5_u32plus a, b, c, d;
-       MD5_u32plus saved_a, saved_b, saved_c, saved_d;
-
-       ptr = data;
-
-       a = ctx->a;
-       b = ctx->b;
-       c = ctx->c;
-       d = ctx->d;
-
-       do {
-               saved_a = a;
-               saved_b = b;
-               saved_c = c;
-               saved_d = d;
-
-/* Round 1 */
-               STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
-               STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
-               STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
-               STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
-               STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
-               STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
-               STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
-               STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
-               STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
-               STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
-               STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
-               STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
-               STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
-               STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
-               STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
-               STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
-
-/* Round 2 */
-               STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
-               STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
-               STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
-               STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
-               STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
-               STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
-               STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
-               STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
-               STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
-               STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
-               STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
-               STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
-               STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
-               STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
-               STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
-               STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
-
-/* Round 3 */
-               STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
-               STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
-               STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
-               STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
-               STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
-               STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
-               STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
-               STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
-               STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
-               STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
-               STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
-               STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
-               STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
-               STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
-               STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
-               STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
-
-/* Round 4 */
-               STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
-               STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
-               STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
-               STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
-               STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
-               STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
-               STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
-               STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
-               STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
-               STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
-               STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
-               STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
-               STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
-               STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
-               STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
-               STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
-
-               a += saved_a;
-               b += saved_b;
-               c += saved_c;
-               d += saved_d;
-
-               ptr += 64;
-       } while (size -= 64);
-
-       ctx->a = a;
-       ctx->b = b;
-       ctx->c = c;
-       ctx->d = d;
-
-       return ptr;
-}
-
-void solv_MD5_Init(MD5_CTX *ctx)
-{
-       ctx->a = 0x67452301;
-       ctx->b = 0xefcdab89;
-       ctx->c = 0x98badcfe;
-       ctx->d = 0x10325476;
-
-       ctx->lo = 0;
-       ctx->hi = 0;
-}
-
-void solv_MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
-{
-       MD5_u32plus saved_lo;
-       unsigned long used, free;
-
-       saved_lo = ctx->lo;
-       if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
-               ctx->hi++;
-       ctx->hi += size >> 29;
-
-       used = saved_lo & 0x3f;
-
-       if (used) {
-               free = 64 - used;
-
-               if (size < free) {
-                       memcpy(&ctx->buffer[used], data, size);
-                       return;
-               }
-
-               memcpy(&ctx->buffer[used], data, free);
-               data = (unsigned char *)data + free;
-               size -= free;
-               body(ctx, ctx->buffer, 64);
-       }
-
-       if (size >= 64) {
-               data = body(ctx, data, size & ~(unsigned long)0x3f);
-               size &= 0x3f;
-       }
-
-       memcpy(ctx->buffer, data, size);
-}
-
-void solv_MD5_Final(unsigned char *result, MD5_CTX *ctx)
-{
-       unsigned long used, free;
-
-       used = ctx->lo & 0x3f;
-
-       ctx->buffer[used++] = 0x80;
-
-       free = 64 - used;
-
-       if (free < 8) {
-               memset(&ctx->buffer[used], 0, free);
-               body(ctx, ctx->buffer, 64);
-               used = 0;
-               free = 64;
-       }
-
-       memset(&ctx->buffer[used], 0, free - 8);
-
-       ctx->lo <<= 3;
-       ctx->buffer[56] = ctx->lo;
-       ctx->buffer[57] = ctx->lo >> 8;
-       ctx->buffer[58] = ctx->lo >> 16;
-       ctx->buffer[59] = ctx->lo >> 24;
-       ctx->buffer[60] = ctx->hi;
-       ctx->buffer[61] = ctx->hi >> 8;
-       ctx->buffer[62] = ctx->hi >> 16;
-       ctx->buffer[63] = ctx->hi >> 24;
-
-       body(ctx, ctx->buffer, 64);
-
-       result[0] = ctx->a;
-       result[1] = ctx->a >> 8;
-       result[2] = ctx->a >> 16;
-       result[3] = ctx->a >> 24;
-       result[4] = ctx->b;
-       result[5] = ctx->b >> 8;
-       result[6] = ctx->b >> 16;
-       result[7] = ctx->b >> 24;
-       result[8] = ctx->c;
-       result[9] = ctx->c >> 8;
-       result[10] = ctx->c >> 16;
-       result[11] = ctx->c >> 24;
-       result[12] = ctx->d;
-       result[13] = ctx->d >> 8;
-       result[14] = ctx->d >> 16;
-       result[15] = ctx->d >> 24;
-
-       memset(ctx, 0, sizeof(*ctx));
-}
diff --git a/libsolv-0.6.15/src/md5.h b/libsolv-0.6.15/src/md5.h
deleted file mode 100644 (file)
index 54533c7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * This is an OpenSSL-compatible implementation of the RSA Data Security,
- * Inc. MD5 Message-Digest Algorithm.
- *
- * Written by Solar Designer <solar@openwall.com> in 2001, and placed in
- * the public domain.  See md5.c for more information.
- */
-
-/* Any 32-bit or wider unsigned integer data type will do */
-typedef unsigned long MD5_u32plus;
-
-typedef struct {
-       MD5_u32plus lo, hi;
-       MD5_u32plus a, b, c, d;
-       unsigned char buffer[64];
-       MD5_u32plus block[16];
-} MD5_CTX;
-
-extern void solv_MD5_Init(MD5_CTX *ctx);
-extern void solv_MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);
-extern void solv_MD5_Final(unsigned char *result, MD5_CTX *ctx);
diff --git a/libsolv-0.6.15/src/order.c b/libsolv-0.6.15/src/order.c
deleted file mode 100644 (file)
index d560865..0000000
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
- * Copyright (c) 2007-2015, SUSE LLC
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * order.c
- *
- * Transaction ordering
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "transaction.h"
-#include "bitmap.h"
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-
-struct _TransactionElement {
-  Id p;                /* solvable id */
-  Id edges;    /* pointer into edges data */
-  Id mark;
-};
-
-struct _TransactionOrderdata {
-  struct _TransactionElement *tes;
-  int ntes;
-  Id *invedgedata;
-  int ninvedgedata;
-  Queue *cycles;
-};
-
-#define TYPE_BROKEN    (1<<0)
-#define TYPE_CON       (1<<1)
-
-#define TYPE_REQ_P     (1<<2)
-#define TYPE_PREREQ_P  (1<<3)
-
-#define TYPE_REQ       (1<<4)
-#define TYPE_PREREQ    (1<<5)
-
-#define TYPE_CYCLETAIL  (1<<16)
-#define TYPE_CYCLEHEAD  (1<<17)
-
-#define EDGEDATA_BLOCK 127
-
-void
-transaction_clone_orderdata(Transaction *trans, Transaction *srctrans)
-{
-  struct _TransactionOrderdata *od = srctrans->orderdata;
-  if (!od)
-    return;
-  trans->orderdata = solv_calloc(1, sizeof(*trans->orderdata));
-  trans->orderdata->tes = solv_memdup2(od->tes, od->ntes, sizeof(*od->tes));
-  trans->orderdata->ntes = od->ntes;
-  trans->orderdata->invedgedata = solv_memdup2(od->invedgedata, od->ninvedgedata, sizeof(Id));
-  trans->orderdata->ninvedgedata = od->ninvedgedata;
-  if (od->cycles)
-    {
-      trans->orderdata->cycles = solv_calloc(1, sizeof(Queue));
-      queue_init_clone(trans->orderdata->cycles, od->cycles);
-    }
-}
-
-void
-transaction_free_orderdata(Transaction *trans)
-{
-  if (trans->orderdata)
-    {
-      struct _TransactionOrderdata *od = trans->orderdata;
-      od->tes = solv_free(od->tes);
-      od->invedgedata = solv_free(od->invedgedata);
-      if (od->cycles)
-       {
-         queue_free(od->cycles);
-         od->cycles = solv_free(od->cycles);
-       }
-      trans->orderdata = solv_free(trans->orderdata);
-    }
-}
-
-struct orderdata {
-  Transaction *trans;
-  struct _TransactionElement *tes;
-  int ntes;
-  Id *edgedata;
-  int nedgedata;
-  Id *invedgedata;
-
-  Queue cycles;
-  Queue cyclesdata;
-  int ncycles;
-};
-
-static int
-addteedge(struct orderdata *od, int from, int to, int type)
-{
-  int i;
-  struct _TransactionElement *te;
-
-  if (from == to)
-    return 0;
-
-  /* printf("edge %d(%s) -> %d(%s) type %x\n", from, pool_solvid2str(pool, od->tes[from].p), to, pool_solvid2str(pool, od->tes[to].p), type); */
-
-  te = od->tes + from;
-  for (i = te->edges; od->edgedata[i]; i += 2)
-    if (od->edgedata[i] == to)
-      break;
-  /* test of brokenness */
-  if (type == TYPE_BROKEN)
-    return od->edgedata[i] && (od->edgedata[i + 1] & TYPE_BROKEN) != 0 ? 1 : 0;
-  if (od->edgedata[i])
-    {
-      od->edgedata[i + 1] |= type;
-      return 0;
-    }
-  if (i + 1 == od->nedgedata)
-    {
-      /* printf("tail add %d\n", i - te->edges); */
-      if (!i)
-       te->edges = ++i;
-      od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK);
-    }
-  else
-    {
-      /* printf("extend %d\n", i - te->edges); */
-      od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK);
-      if (i > te->edges)
-       memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges));
-      i = od->nedgedata + (i - te->edges);
-      te->edges = od->nedgedata;
-    }
-  od->edgedata[i] = to;
-  od->edgedata[i + 1] = type;
-  od->edgedata[i + 2] = 0;     /* end marker */
-  od->nedgedata = i + 3;
-  return 0;
-}
-
-static int
-addedge(struct orderdata *od, Id from, Id to, int type)
-{
-  Transaction *trans = od->trans;
-  Pool *pool = trans->pool;
-  Solvable *s;
-  struct _TransactionElement *te;
-  int i;
-
-  /* printf("addedge %d %d type %d\n", from, to, type); */
-  s = pool->solvables + from;
-  if (s->repo == pool->installed && trans->transaction_installed[from - pool->installed->start])
-    {
-      /* obsolete, map to install */
-      if (trans->transaction_installed[from - pool->installed->start] > 0)
-       from = trans->transaction_installed[from - pool->installed->start];
-      else
-       {
-         int ret = 0;
-         Queue ti;
-         Id tibuf[5];
-
-         queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
-         transaction_all_obs_pkgs(trans, from, &ti);
-         for (i = 0; i < ti.count; i++)
-           ret |= addedge(od, ti.elements[i], to, type);
-         queue_free(&ti);
-         return ret;
-       }
-    }
-  s = pool->solvables + to;
-  if (s->repo == pool->installed && trans->transaction_installed[to - pool->installed->start])
-    {
-      /* obsolete, map to install */
-      if (trans->transaction_installed[to - pool->installed->start] > 0)
-       to = trans->transaction_installed[to - pool->installed->start];
-      else
-       {
-         int ret = 0;
-         Queue ti;
-         Id tibuf[5];
-
-         queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
-         transaction_all_obs_pkgs(trans, to, &ti);
-         for (i = 0; i < ti.count; i++)
-           ret |= addedge(od, from, ti.elements[i], type);
-         queue_free(&ti);
-         return ret;
-       }
-    }
-
-  /* map from/to to te numbers */
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    if (te->p == to)
-      break;
-  if (i == od->ntes)
-    return 0;
-  to = i;
-
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    if (te->p == from)
-      break;
-  if (i == od->ntes)
-    return 0;
-
-  return addteedge(od, i, to, type);
-}
-
-static inline int
-havescripts(Pool *pool, Id solvid)
-{
-  Solvable *s = pool->solvables + solvid;
-  const char *dep;
-  if (s->requires)
-    {
-      Id req, *reqp;
-      int inpre = 0;
-      reqp = s->repo->idarraydata + s->requires;
-      while ((req = *reqp++) != 0)
-       {
-          if (req == SOLVABLE_PREREQMARKER)
-           {
-             inpre = 1;
-             continue;
-           }
-         if (!inpre)
-           continue;
-         dep = pool_id2str(pool, req);
-         if (*dep == '/' && strcmp(dep, "/sbin/ldconfig") != 0)
-           return 1;
-       }
-    }
-  return 0;
-}
-
-static void
-addsolvableedges(struct orderdata *od, Solvable *s)
-{
-  Transaction *trans = od->trans;
-  Pool *pool = trans->pool;
-  Id req, *reqp, con, *conp;
-  Id p, p2, pp2;
-  int i, j, pre, numins;
-  Repo *installed = pool->installed;
-  Solvable *s2;
-  Queue reqq;
-  int provbyinst;
-
-#if 0
-  printf("addsolvableedges %s\n", pool_solvable2str(pool, s));
-#endif
-  p = s - pool->solvables;
-  queue_init(&reqq);
-  if (s->requires)
-    {
-      reqp = s->repo->idarraydata + s->requires;
-      pre = TYPE_REQ;
-      while ((req = *reqp++) != 0)
-       {
-         if (req == SOLVABLE_PREREQMARKER)
-           {
-             pre = TYPE_PREREQ;
-             continue;
-           }
-#if 0
-         if (pre != TYPE_PREREQ && installed && s->repo == installed)
-           {
-             /* ignore normal requires if we're getting obsoleted */
-             if (trans->transaction_installed[p - pool->installed->start])
-               continue;
-           }
-#endif
-         queue_empty(&reqq);
-         numins = 0;   /* number of packages to be installed providing it */
-         provbyinst = 0;       /* provided by kept package */
-         FOR_PROVIDES(p2, pp2, req)
-           {
-             s2 = pool->solvables + p2;
-             if (p2 == p)
-               {
-                 reqq.count = 0;       /* self provides */
-                 break;
-               }
-             if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
-               {
-                 provbyinst = 1;
-#if 0
-                 printf("IGNORE inst provides %s by %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s2));
-                 reqq.count = 0;       /* provided by package that stays installed */
-                 break;
-#else
-                 continue;
-#endif
-               }
-             if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
-               continue;               /* package stays uninstalled */
-
-             if (s->repo == installed)
-               {
-                 /* s gets uninstalled */
-                 queue_pushunique(&reqq, p2);
-                 if (s2->repo != installed)
-                   numins++;
-               }
-             else
-               {
-                 if (s2->repo == installed)
-                   continue;   /* s2 gets uninstalled */
-                 queue_pushunique(&reqq, p2);
-               }
-           }
-         if (provbyinst)
-           {
-             /* prune to harmless ->inst edges */
-             for (i = j = 0; i < reqq.count; i++)
-               if (pool->solvables[reqq.elements[i]].repo != installed)
-                 reqq.elements[j++] = reqq.elements[i];
-             reqq.count = j;
-           }
-
-         if (numins && reqq.count)
-           {
-             if (s->repo == installed)
-               {
-                 for (i = 0; i < reqq.count; i++)
-                   {
-                     if (pool->solvables[reqq.elements[i]].repo == installed)
-                       {
-                         for (j = 0; j < reqq.count; j++)
-                           {
-                             if (pool->solvables[reqq.elements[j]].repo != installed)
-                               {
-                                 if (trans->transaction_installed[reqq.elements[i] - pool->installed->start] == reqq.elements[j])
-                                   continue;   /* no self edge */
-#if 0
-                                 printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, reqq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, reqq.elements[j]));
-#endif
-                                 addedge(od, reqq.elements[i], reqq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P);
-                               }
-                           }
-                       }
-                   }
-               }
-             /* no mixed types, remove all deps on uninstalls */
-             for (i = j = 0; i < reqq.count; i++)
-               if (pool->solvables[reqq.elements[i]].repo != installed)
-                 reqq.elements[j++] = reqq.elements[i];
-             reqq.count = j;
-           }
-          if (!reqq.count)
-           continue;
-          for (i = 0; i < reqq.count; i++)
-           {
-             p2 = reqq.elements[i];
-             if (pool->solvables[p2].repo != installed)
-               {
-                 /* all elements of reqq are installs, thus have different TEs */
-                 if (pool->solvables[p].repo != installed)
-                   {
-#if 0
-                     printf("add inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
-#endif
-                     addedge(od, p, p2, pre);
-                   }
-                 else
-                   {
-#if 0
-                     printf("add uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
-#endif
-                     addedge(od, p, p2, pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P);
-                   }
-               }
-             else
-               {
-                 if (s->repo != installed)
-                   continue;   /* no inst->uninst edges, please! */
-
-                 /* uninst -> uninst edge. Those make trouble. Only add if we must */
-                 if (trans->transaction_installed[p - installed->start] && !havescripts(pool, p))
-                   {
-                     /* p is obsoleted by another package and has no scripts */
-                     /* we assume that the obsoletor is good enough to replace p */
-                     continue;
-                   }
-#if 0
-                 printf("add uninst->uninst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
-#endif
-                 addedge(od, p2, p, pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P);
-               }
-           }
-       }
-    }
-  if (s->conflicts)
-    {
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-       {
-         FOR_PROVIDES(p2, pp2, con)
-           {
-             if (p2 == p)
-               continue;
-             s2 = pool->solvables + p2;
-             if (!s2->repo)
-               continue;
-             if (s->repo == installed)
-               {
-                 if (s2->repo != installed && MAPTST(&trans->transactsmap, p2))
-                   {
-                     /* deinstall p before installing p2 */
-#if 0
-                     printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, con), pool_solvid2str(pool, p));
-#endif
-                     addedge(od, p2, p, TYPE_CON);
-                   }
-               }
-             else
-               {
-                 if (s2->repo == installed && MAPTST(&trans->transactsmap, p2))
-                   {
-                     /* deinstall p2 before installing p */
-#if 0
-                     printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, con), pool_solvid2str(pool, p2));
-#endif
-                     addedge(od, p, p2, TYPE_CON);
-                   }
-               }
-
-           }
-       }
-    }
-  if (s->repo == installed && solvable_lookup_idarray(s, SOLVABLE_TRIGGERS, &reqq) && reqq.count)
-    {
-      /* we're getting deinstalled/updated. Try to do this before our
-       * triggers are hit */
-      for (i = 0; i < reqq.count; i++)
-       {
-         Id tri = reqq.elements[i];
-         FOR_PROVIDES(p2, pp2, tri)
-           {
-             if (p2 == p)
-               continue;
-             s2 = pool->solvables + p2;
-             if (!s2->repo)
-               continue;
-             if (s2->name == s->name)
-               continue;       /* obsoleted anyway */
-             if (s2->repo != installed && MAPTST(&trans->transactsmap, p2))
-               {
-                 /* deinstall/update p before installing p2 */
-#if 0
-                 printf("add trigger uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, tri), pool_solvid2str(pool, p));
-#endif
-                 addedge(od, p2, p, TYPE_CON);
-               }
-           }
-       }
-    }
-  queue_free(&reqq);
-}
-
-
-/* break an edge in a cycle */
-static void
-breakcycle(struct orderdata *od, Id *cycle)
-{
-  Pool *pool = od->trans->pool;
-  Id ddegmin, ddegmax, ddeg;
-  int k, l;
-  struct _TransactionElement *te;
-
-  l = 0;
-  ddegmin = ddegmax = 0;
-  for (k = 0; cycle[k + 1]; k += 2)
-    {
-      ddeg = od->edgedata[cycle[k + 1] + 1];
-      if (ddeg > ddegmax)
-       ddegmax = ddeg;
-      if (!k || ddeg < ddegmin)
-       {
-         l = k;
-         ddegmin = ddeg;
-         continue;
-       }
-      if (ddeg == ddegmin)
-       {
-         if (havescripts(pool, od->tes[cycle[l]].p) && !havescripts(pool, od->tes[cycle[k]].p))
-           {
-             /* prefer k, as l comes from a package with contains scriptlets */
-             l = k;
-             continue;
-           }
-         /* same edge value, check for prereq */
-       }
-    }
-
-  /* record brkoen cycle starting with the tail */
-  queue_push(&od->cycles, od->cyclesdata.count);               /* offset into data */
-  queue_push(&od->cycles, k / 2);                              /* cycle elements */
-  queue_push(&od->cycles, od->edgedata[cycle[l + 1] + 1]);     /* broken edge */
-  queue_push(&od->cycles, (ddegmax << 16) | ddegmin);          /* max/min values */
-  od->ncycles++;
-  for (k = l;;)
-    {
-      k += 2;
-      if (!cycle[k + 1])
-       k = 0;
-      queue_push(&od->cyclesdata, cycle[k]);
-      if (k == l)
-       break;
-    }
-  queue_push(&od->cyclesdata, 0);      /* mark end */
-
-  /* break that edge */
-  od->edgedata[cycle[l + 1] + 1] |= TYPE_BROKEN;
-
-#if 1
-  if (ddegmin < TYPE_REQ)
-    return;
-#endif
-
-  /* cycle recorded, print it */
-  if (ddegmin >= TYPE_REQ && (ddegmax & TYPE_PREREQ) != 0)
-    POOL_DEBUG(SOLV_DEBUG_STATS, "CRITICAL ");
-  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle: --> ");
-  for (k = 0; cycle[k + 1]; k += 2)
-    {
-      te = od->tes + cycle[k];
-      if ((od->edgedata[cycle[k + 1] + 1] & TYPE_BROKEN) != 0)
-        POOL_DEBUG(SOLV_DEBUG_STATS, "%s ##%x##> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1]);
-      else
-        POOL_DEBUG(SOLV_DEBUG_STATS, "%s --%x--> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1]);
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "\n");
-}
-
-static inline void
-dump_tes(struct orderdata *od)
-{
-  Pool *pool = od->trans->pool;
-  int i, j;
-  Queue obsq;
-  struct _TransactionElement *te, *te2;
-
-  queue_init(&obsq);
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    {
-      Solvable *s = pool->solvables + te->p;
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "TE %4d: %c%s\n", i, s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
-      if (s->repo != pool->installed)
-        {
-         queue_empty(&obsq);
-         transaction_all_obs_pkgs(od->trans, te->p, &obsq);
-         for (j = 0; j < obsq.count; j++)
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "         -%s\n", pool_solvid2str(pool, obsq.elements[j]));
-       }
-      for (j = te->edges; od->edgedata[j]; j += 2)
-       {
-         te2 = od->tes + od->edgedata[j];
-         if ((od->edgedata[j + 1] & TYPE_BROKEN) == 0)
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "       --%x--> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p));
-         else
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "       ##%x##> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p));
-       }
-    }
-}
-
-static void
-reachable(struct orderdata *od, Id i)
-{
-  struct _TransactionElement *te = od->tes + i;
-  int j, k;
-
-  if (te->mark != 0)
-    return;
-  te->mark = 1;
-  for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
-    {
-      if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
-       continue;
-      if (!od->tes[k].mark)
-        reachable(od, k);
-      if (od->tes[k].mark == 2)
-       {
-         te->mark = 2;
-         return;
-       }
-    }
-  te->mark = -1;
-}
-
-static void
-addcycleedges(struct orderdata *od, Id *cycle, Queue *todo)
-{
-#if 0
-  Transaction *trans = od->trans;
-  Pool *pool = trans->pool;
-#endif
-  struct _TransactionElement *te;
-  int i, j, k, tail;
-  int head;
-
-#if 0
-  printf("addcycleedges\n");
-  for (i = 0; (j = cycle[i]) != 0; i++)
-    printf("cycle %s\n", pool_solvid2str(pool, od->tes[j].p));
-#endif
-
-  /* first add all the tail cycle edges */
-
-  /* see what we can reach from the cycle */
-  queue_empty(todo);
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    te->mark = 0;
-  for (i = 0; (j = cycle[i]) != 0; i++)
-    {
-      od->tes[j].mark = -1;
-      queue_push(todo, j);
-    }
-  while (todo->count)
-    {
-      i = queue_pop(todo);
-      te = od->tes + i;
-      if (te->mark > 0)
-       continue;
-      te->mark = te->mark < 0 ? 2 : 1;
-      for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
-       {
-         if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
-           continue;
-         if (od->tes[k].mark > 0)
-           continue;   /* no need to visit again */
-         queue_push(todo, k);
-       }
-    }
-  /* now all cycle TEs are marked with 2, all TEs reachable
-   * from the cycle are marked with 1 */
-  tail = cycle[0];
-  od->tes[tail].mark = 1;      /* no need to add edges */
-
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    {
-      if (te->mark)
-       continue;       /* reachable from cycle */
-      for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
-       {
-         if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
-           continue;
-         if (od->tes[k].mark != 2)
-           continue;
-         /* We found an edge to the cycle. Add an extra edge to the tail */
-         /* the TE was not reachable, so we're not creating a new cycle! */
-#if 0
-         printf("adding TO TAIL cycle edge %d->%d %s->%s!\n", i, tail, pool_solvid2str(pool, od->tes[i].p), pool_solvid2str(pool, od->tes[tail].p));
-#endif
-         j -= te->edges;       /* in case we move */
-         addteedge(od, i, tail, TYPE_CYCLETAIL);
-         j += te->edges;
-         break;        /* one edge is enough */
-       }
-    }
-
-  /* now add all head cycle edges */
-
-  /* reset marks */
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    te->mark = 0;
-  head = 0;
-  for (i = 0; (j = cycle[i]) != 0; i++)
-    {
-      head = j;
-      od->tes[j].mark = 2;
-    }
-  /* first the head to save some time */
-  te = od->tes + head;
-  for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
-    {
-      if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
-       continue;
-      if (!od->tes[k].mark)
-       reachable(od, k);
-      if (od->tes[k].mark == -1)
-       od->tes[k].mark = -2;   /* no need for another edge */
-    }
-  for (i = 0; cycle[i] != 0; i++)
-    {
-      if (cycle[i] == head)
-       break;
-      te = od->tes + cycle[i];
-      for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
-       {
-         if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
-           continue;
-         /* see if we can reach a cycle TE from k */
-         if (!od->tes[k].mark)
-           reachable(od, k);
-         if (od->tes[k].mark == -1)
-           {
-#if 0
-             printf("adding FROM HEAD cycle edge %d->%d %s->%s [%s]!\n", head, k, pool_solvid2str(pool, od->tes[head].p), pool_solvid2str(pool, od->tes[k].p), pool_solvid2str(pool, od->tes[cycle[i]].p));
-#endif
-             addteedge(od, head, k, TYPE_CYCLEHEAD);
-             od->tes[k].mark = -2;     /* no need to add that one again */
-           }
-       }
-    }
-}
-
-void
-transaction_order(Transaction *trans, int flags)
-{
-  Pool *pool = trans->pool;
-  Queue *tr = &trans->steps;
-  Repo *installed = pool->installed;
-  Id p;
-  Solvable *s;
-  int i, j, k, numte, numedge;
-  struct orderdata od;
-  struct _TransactionElement *te;
-  Queue todo, obsq, samerepoq, uninstq;
-  int cycstart, cycel;
-  Id *cycle;
-  int oldcount;
-  int start, now;
-  Repo *lastrepo;
-  int lastmedia;
-  Id *temedianr;
-
-  start = now = solv_timems(0);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n");
-  /* free old data if present */
-  if (trans->orderdata)
-    {
-      struct _TransactionOrderdata *od = trans->orderdata;
-      od->tes = solv_free(od->tes);
-      od->invedgedata = solv_free(od->invedgedata);
-      trans->orderdata = solv_free(trans->orderdata);
-    }
-
-  /* create a transaction element for every active component */
-  numte = 0;
-  for (i = 0; i < tr->count; i++)
-    {
-      p = tr->elements[i];
-      s = pool->solvables + p;
-      if (installed && s->repo == installed && trans->transaction_installed[p - installed->start])
-       continue;
-      numte++;
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "transaction elements: %d\n", numte);
-  if (!numte)
-    return;    /* nothing to do... */
-
-  numte++;     /* leave first one zero */
-  memset(&od, 0, sizeof(od));
-  od.trans = trans;
-  od.ntes = numte;
-  od.tes = solv_calloc(numte, sizeof(*od.tes));
-  od.edgedata = solv_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK);
-  od.edgedata[0] = 0;
-  od.nedgedata = 1;
-  queue_init(&od.cycles);
-
-  /* initialize TEs */
-  for (i = 0, te = od.tes + 1; i < tr->count; i++)
-    {
-      p = tr->elements[i];
-      s = pool->solvables + p;
-      if (installed && s->repo == installed && trans->transaction_installed[p - installed->start])
-       continue;
-      te->p = p;
-      te++;
-    }
-
-  /* create dependency graph */
-  for (i = 0; i < tr->count; i++)
-    addsolvableedges(&od, pool->solvables + tr->elements[i]);
-
-  /* count edges */
-  numedge = 0;
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    for (j = te->edges; od.edgedata[j]; j += 2)
-      numedge++;
-  POOL_DEBUG(SOLV_DEBUG_STATS, "edges: %d, edge space: %d\n", numedge, od.nedgedata / 2);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "edge creation took %d ms\n", solv_timems(now));
-
-#if 0
-  dump_tes(&od);
-#endif
-
-  now = solv_timems(0);
-  /* kill all cycles */
-  queue_init(&todo);
-  for (i = numte - 1; i > 0; i--)
-    queue_push(&todo, i);
-
-  while (todo.count)
-    {
-      i = queue_pop(&todo);
-      /* printf("- look at TE %d\n", i); */
-      if (i < 0)
-       {
-         i = -i;
-         od.tes[i].mark = 2;   /* done with that one */
-         continue;
-       }
-      te = od.tes + i;
-      if (te->mark == 2)
-       continue;               /* already finished before */
-      if (te->mark == 0)
-       {
-         int edgestovisit = 0;
-         /* new node, visit edges */
-         for (j = te->edges; (k = od.edgedata[j]) != 0; j += 2)
-           {
-             if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
-               continue;
-             if (od.tes[k].mark == 2)
-               continue;       /* no need to visit again */
-             if (!edgestovisit++)
-               queue_push(&todo, -i);  /* end of edges marker */
-             queue_push(&todo, k);
-           }
-         if (!edgestovisit)
-           te->mark = 2;       /* no edges, done with that one */
-         else
-           te->mark = 1;       /* under investigation */
-         continue;
-       }
-      /* oh no, we found a cycle */
-      /* find start of cycle node (<0) */
-      for (j = todo.count - 1; j >= 0; j--)
-       if (todo.elements[j] == -i)
-         break;
-      assert(j >= 0);
-      cycstart = j;
-      /* build te/edge chain */
-      k = cycstart;
-      for (j = k; j < todo.count; j++)
-       if (todo.elements[j] < 0)
-         todo.elements[k++] = -todo.elements[j];
-      cycel = k - cycstart;
-      assert(cycel > 1);
-      /* make room for edges, two extra element for cycle loop + terminating 0 */
-      while (todo.count < cycstart + 2 * cycel + 2)
-       queue_push(&todo, 0);
-      cycle = todo.elements + cycstart;
-      cycle[cycel] = i;                /* close the loop */
-      cycle[2 * cycel + 1] = 0;        /* terminator */
-      for (k = cycel; k > 0; k--)
-       {
-         cycle[k * 2] = cycle[k];
-         te = od.tes + cycle[k - 1];
-         assert(te->mark == 1);
-         te->mark = 0; /* reset investigation marker */
-         /* printf("searching for edge from %d to %d\n", cycle[k - 1], cycle[k]); */
-         for (j = te->edges; od.edgedata[j]; j += 2)
-           if (od.edgedata[j] == cycle[k])
-             break;
-         assert(od.edgedata[j]);
-         cycle[k * 2 - 1] = j;
-       }
-      /* now cycle looks like this: */
-      /* te1 edge te2 edge te3 ... teN edge te1 0 */
-      breakcycle(&od, cycle);
-      /* restart with start of cycle */
-      todo.count = cycstart + 1;
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "cycles broken: %d\n", od.ncycles);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle breaking took %d ms\n", solv_timems(now));
-
-  now = solv_timems(0);
-  /* now go through all broken cycles and create cycle edges to help
-     the ordering */
-   for (i = od.cycles.count - 4; i >= 0; i -= 4)
-     {
-       if (od.cycles.elements[i + 2] >= TYPE_REQ)
-         addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
-     }
-   for (i = od.cycles.count - 4; i >= 0; i -= 4)
-     {
-       if (od.cycles.elements[i + 2] < TYPE_REQ)
-         addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
-     }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
-
-#if 0
-  dump_tes(&od);
-#endif
-  /* all edges are finally set up and there are no cycles, now the easy part.
-   * Create an ordered transaction */
-  now = solv_timems(0);
-  /* first invert all edges */
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    te->mark = 1;      /* term 0 */
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    {
-      for (j = te->edges; od.edgedata[j]; j += 2)
-        {
-         if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
-           continue;
-         od.tes[od.edgedata[j]].mark++;
-       }
-    }
-  j = 1;
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    {
-      te->mark += j;
-      j = te->mark;
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "invedge space: %d\n", j + 1);
-  od.invedgedata = solv_calloc(j + 1, sizeof(Id));
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    {
-      for (j = te->edges; od.edgedata[j]; j += 2)
-        {
-         if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
-           continue;
-         od.invedgedata[--od.tes[od.edgedata[j]].mark] = i;
-       }
-    }
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    te->edges = te->mark;      /* edges now points into invedgedata */
-  od.edgedata = solv_free(od.edgedata);
-  od.nedgedata = j + 1;
-
-  /* now the final ordering */
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    te->mark = 0;
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    for (j = te->edges; od.invedgedata[j]; j++)
-      od.tes[od.invedgedata[j]].mark++;
-
-  queue_init(&samerepoq);
-  queue_init(&uninstq);
-  queue_empty(&todo);
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    if (te->mark == 0)
-      {
-       if (installed && pool->solvables[te->p].repo == installed)
-          queue_push(&uninstq, i);
-       else
-          queue_push(&todo, i);
-      }
-  assert(todo.count > 0 || uninstq.count > 0);
-  oldcount = tr->count;
-  queue_empty(tr);
-
-  queue_init(&obsq);
-
-  lastrepo = 0;
-  lastmedia = 0;
-  temedianr = solv_calloc(numte, sizeof(Id));
-  for (i = 1; i < numte; i++)
-    {
-      Solvable *s = pool->solvables + od.tes[i].p;
-      if (installed && s->repo == installed)
-       j = 1;
-      else
-        j = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
-      temedianr[i] = j;
-    }
-  for (;;)
-    {
-      /* select an TE i */
-      if (uninstq.count)
-       i = queue_shift(&uninstq);
-      else if (samerepoq.count)
-       i = queue_shift(&samerepoq);
-      else if (todo.count)
-       {
-         /* find next repo/media */
-         for (j = 0; j < todo.count; j++)
-           {
-             if (!j || temedianr[todo.elements[j]] < lastmedia)
-               {
-                 i = j;
-                 lastmedia = temedianr[todo.elements[j]];
-               }
-           }
-         lastrepo = pool->solvables[od.tes[todo.elements[i]].p].repo;
-
-         /* move all matching TEs to samerepoq */
-         for (i = j = 0; j < todo.count; j++)
-           {
-             int k = todo.elements[j];
-             if (temedianr[k] == lastmedia && pool->solvables[od.tes[k].p].repo == lastrepo)
-               queue_push(&samerepoq, k);
-             else
-               todo.elements[i++] = k;
-           }
-         todo.count = i;
-
-         assert(samerepoq.count);
-         i = queue_shift(&samerepoq);
-       }
-      else
-       break;
-
-      te = od.tes + i;
-      queue_push(tr, te->p);
-#if 0
-printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
-#endif
-      s = pool->solvables + te->p;
-      for (j = te->edges; od.invedgedata[j]; j++)
-       {
-         struct _TransactionElement *te2 = od.tes + od.invedgedata[j];
-         assert(te2->mark > 0);
-         if (--te2->mark == 0)
-           {
-             Solvable *s = pool->solvables + te2->p;
-#if 0
-printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata[j]]);
-#endif
-             if (installed && s->repo == installed)
-               queue_push(&uninstq, od.invedgedata[j]);
-             else if (s->repo == lastrepo && temedianr[od.invedgedata[j]] == lastmedia)
-               queue_push(&samerepoq, od.invedgedata[j]);
-             else
-               queue_push(&todo, od.invedgedata[j]);
-           }
-       }
-    }
-  solv_free(temedianr);
-  queue_free(&todo);
-  queue_free(&samerepoq);
-  queue_free(&uninstq);
-  queue_free(&obsq);
-  for (i = 1, te = od.tes + i; i < numte; i++, te++)
-    assert(te->mark == 0);
-
-  /* add back obsoleted packages */
-  transaction_add_obsoleted(trans);
-  assert(tr->count == oldcount);
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "creating new transaction took %d ms\n", solv_timems(now));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "transaction ordering took %d ms\n", solv_timems(start));
-
-  if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES)) != 0)
-    {
-      struct _TransactionOrderdata *tod;
-      trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata));
-      if ((flags & SOLVER_TRANSACTION_KEEP_ORDERCYCLES) != 0)
-       {
-         Queue *cycles = tod->cycles = solv_calloc(1, sizeof(Queue));
-         queue_init_clone(cycles, &od.cyclesdata);
-         /* map from tes to packages */
-         for (i = 0; i < cycles->count; i++)
-           if (cycles->elements[i])
-             cycles->elements[i] = od.tes[cycles->elements[i]].p;
-         queue_insertn(cycles, cycles->count, od.cycles.count, od.cycles.elements);
-         queue_push(cycles, od.cycles.count / 4);
-       }
-      if ((flags & SOLVER_TRANSACTION_KEEP_ORDERDATA) != 0)
-       {
-         tod->tes = od.tes;
-         tod->ntes = numte;
-         tod->invedgedata = od.invedgedata;
-         tod->ninvedgedata = od.nedgedata;
-         od.tes = 0;
-         od.invedgedata = 0;
-       }
-    }
-  solv_free(od.tes);
-  solv_free(od.invedgedata);
-  queue_free(&od.cycles);
-  queue_free(&od.cyclesdata);
-}
-
-
-int
-transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices)
-{
-  int i, j;
-  struct _TransactionOrderdata *od = trans->orderdata;
-  struct _TransactionElement *te;
-
-  if (!od)
-     return choices->count;
-  if (!chosen)
-    {
-      /* initialization step */
-      for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-       te->mark = 0;
-      for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-       {
-         for (j = te->edges; od->invedgedata[j]; j++)
-           od->tes[od->invedgedata[j]].mark++;
-       }
-      for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-       if (!te->mark)
-         queue_push(choices, te->p);
-      return choices->count;
-    }
-  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
-    if (te->p == chosen)
-      break;
-  if (i == od->ntes)
-    return choices->count;
-  if (te->mark > 0)
-    {
-      /* hey! out-of-order installation! */
-      te->mark = -1;
-    }
-  for (j = te->edges; od->invedgedata[j]; j++)
-    {
-      te = od->tes + od->invedgedata[j];
-      assert(te->mark > 0 || te->mark == -1);
-      if (te->mark > 0 && --te->mark == 0)
-       queue_push(choices, te->p);
-    }
-  return choices->count;
-}
-
-void
-transaction_add_obsoleted(Transaction *trans)
-{
-  Pool *pool = trans->pool;
-  Repo *installed = pool->installed;
-  Id p;
-  Solvable *s;
-  int i, j, k, max;
-  Map done;
-  Queue obsq, *steps;
-
-  if (!installed || !trans->steps.count)
-    return;
-  /* calculate upper bound */
-  max = 0;
-  FOR_REPO_SOLVABLES(installed, p, s)
-    if (MAPTST(&trans->transactsmap, p))
-      max++;
-  if (!max)
-    return;
-  /* make room */
-  steps = &trans->steps;
-  queue_insertn(steps, 0, max, 0);
-
-  /* now add em */
-  map_init(&done, installed->end - installed->start);
-  queue_init(&obsq);
-  for (j = 0, i = max; i < steps->count; i++)
-    {
-      p = trans->steps.elements[i];
-      if (pool->solvables[p].repo == installed)
-       {
-         if (!trans->transaction_installed[p - pool->installed->start])
-           trans->steps.elements[j++] = p;
-         continue;
-       }
-      trans->steps.elements[j++] = p;
-      queue_empty(&obsq);
-      transaction_all_obs_pkgs(trans, p, &obsq);
-      for (k = 0; k < obsq.count; k++)
-       {
-         p = obsq.elements[k];
-         assert(p >= installed->start && p < installed->end);
-         if (!MAPTST(&trans->transactsmap, p)) /* just in case */
-           continue;
-         if (MAPTST(&done, p - installed->start))
-           continue;
-         MAPSET(&done, p - installed->start);
-         trans->steps.elements[j++] = p;
-       }
-    }
-
-  /* free unneeded space */
-  queue_truncate(steps, j);
-  map_free(&done);
-  queue_free(&obsq);
-}
-
-static void
-transaction_check_pkg(Transaction *trans, Id tepkg, Id pkg, Map *ins, Map *seen, int onlyprereq, Id noconfpkg, int depth)
-{
-  Pool *pool = trans->pool;
-  Id p, pp;
-  Solvable *s;
-  int good;
-
-  if (MAPTST(seen, pkg))
-    return;
-  MAPSET(seen, pkg);
-  s = pool->solvables + pkg;
-#if 0
-  printf("- %*s%c%s\n", depth * 2, "", s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
-#endif
-  if (s->requires)
-    {
-      Id req, *reqp;
-      int inpre = 0;
-      reqp = s->repo->idarraydata + s->requires;
-      while ((req = *reqp++) != 0)
-       {
-          if (req == SOLVABLE_PREREQMARKER)
-           {
-             inpre = 1;
-             continue;
-           }
-         if (onlyprereq && !inpre)
-           continue;
-         if (!strncmp(pool_id2str(pool, req), "rpmlib(", 7))
-           continue;
-         good = 0;
-         /* first check kept packages, then freshly installed, then not yet uninstalled */
-         FOR_PROVIDES(p, pp, req)
-           {
-             if (!MAPTST(ins, p))
-               continue;
-             if (MAPTST(&trans->transactsmap, p))
-               continue;
-             good++;
-             transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
-           }
-         if (!good)
-           {
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (!MAPTST(ins, p))
-                   continue;
-                 if (pool->solvables[p].repo == pool->installed)
-                   continue;
-                 good++;
-                 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
-               }
-           }
-         if (!good)
-           {
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (!MAPTST(ins, p))
-                   continue;
-                 good++;
-                 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
-               }
-           }
-         if (!good)
-           {
-             POOL_DEBUG(SOLV_DEBUG_RESULT, "  %c%s: nothing provides %s needed by %c%s\n", pool->solvables[tepkg].repo == pool->installed ? '-' : '+', pool_solvid2str(pool, tepkg), pool_dep2str(pool, req), s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
-           }
-       }
-    }
-}
-
-void
-transaction_check_order(Transaction *trans)
-{
-  Pool *pool = trans->pool;
-  Solvable *s;
-  Id p, lastins;
-  Map ins, seen;
-  int i;
-
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "\nchecking transaction order...\n");
-  map_init(&ins, pool->nsolvables);
-  map_init(&seen, pool->nsolvables);
-  if (pool->installed)
-    FOR_REPO_SOLVABLES(pool->installed, p, s)
-      MAPSET(&ins, p);
-  lastins = 0;
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      p = trans->steps.elements[i];
-      s = pool->solvables + p;
-      if (s->repo != pool->installed)
-       lastins = p;
-      if (s->repo != pool->installed)
-       MAPSET(&ins, p);
-      if (havescripts(pool, p))
-       {
-         MAPZERO(&seen);
-         transaction_check_pkg(trans, p, p, &ins, &seen, 1, lastins, 0);
-       }
-      if (s->repo == pool->installed)
-       MAPCLR(&ins, p);
-    }
-  map_free(&seen);
-  map_free(&ins);
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "transaction order check done.\n");
-}
-
-void
-transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity)
-{
-  struct _TransactionOrderdata *od = trans->orderdata;
-  Queue *cq;
-  int i, cid, ncycles;
-
-  queue_empty(q);
-  if (!od || !od->cycles || !od->cycles->count)
-    return;
-  cq = od->cycles;
-  ncycles = cq->elements[cq->count - 1];
-  i = cq->count - 1 - ncycles * 4;
-  for (cid = 1; cid <= ncycles; cid++, i += 4)
-    {
-      if (minseverity)
-       {
-         int cmin = cq->elements[i + 3] & 0xffff;
-         int cmax = (cq->elements[i + 3] >> 16) & 0xffff;
-         if (minseverity >= SOLVER_ORDERCYCLE_NORMAL && cmin < TYPE_REQ)
-           continue;
-         if (minseverity >= SOLVER_ORDERCYCLE_CRITICAL && (cmax & TYPE_PREREQ) == 0)
-           continue;
-       }
-      queue_push(q, cid);
-    }
-}
-
-int
-transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q)
-{
-  struct _TransactionOrderdata *od = trans->orderdata;
-  Queue *cq;
-  int cmin, cmax, severity;
-  int ncycles;
-
-  queue_empty(q);
-  if (!od || !od->cycles || !od->cycles->count)
-    return SOLVER_ORDERCYCLE_HARMLESS;
-  cq = od->cycles;
-  ncycles = cq->elements[cq->count - 1];
-  if (cid < 1 || cid > ncycles)
-    return SOLVER_ORDERCYCLE_HARMLESS;
-  cid =  cq->count - 1 - 4 * (ncycles - cid + 1);
-  cmin = cq->elements[cid + 3] & 0xffff;
-  cmax = (cq->elements[cid + 3] >> 16) & 0xffff;
-  if (cmin < TYPE_REQ)
-    severity = SOLVER_ORDERCYCLE_HARMLESS;
-  else if ((cmax & TYPE_PREREQ) == 0)
-    severity = SOLVER_ORDERCYCLE_NORMAL;
-  else
-    severity = SOLVER_ORDERCYCLE_CRITICAL;
-  if (q)
-    queue_insertn(q, 0, cq->elements[cid + 1], cq->elements + cq->elements[cid]);
-  return severity;
-}
-
diff --git a/libsolv-0.6.15/src/policy.c b/libsolv-0.6.15/src/policy.c
deleted file mode 100644 (file)
index 12ad771..0000000
+++ /dev/null
@@ -1,1463 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * Generic policy interface for SAT solver
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "solver.h"
-#include "solver_private.h"
-#include "evr.h"
-#include "policy.h"
-#include "poolvendor.h"
-#include "poolarch.h"
-#include "linkedpkg.h"
-#include "cplxdeps.h"
-
-
-
-/*-----------------------------------------------------------------*/
-
-/*
- * prep for prune_best_version
- *   sort by name
- */
-
-static int
-prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  int r;
-  Id a = *(Id *)ap;
-  Id b = *(Id *)bp;
-  Solvable *sa, *sb;
-
-  sa = pool->solvables + a;
-  sb = pool->solvables + b;
-  r = sa->name - sb->name;
-  if (r)
-    {
-      const char *na, *nb;
-      /* different names. We use real strcmp here so that the result
-       * is not depending on some random solvable order */
-      na = pool_id2str(pool, sa->name);
-      nb = pool_id2str(pool, sb->name);
-      return strcmp(na, nb);
-    }
-  if (sa->arch != sb->arch)
-    {
-      int aa, ab;
-      aa = (sa->arch <= pool->lastarch) ? pool->id2arch[sa->arch] : 0;
-      ab = (sb->arch <= pool->lastarch) ? pool->id2arch[sb->arch] : 0;
-      if (aa != ab && aa > 1 && ab > 1)
-       return aa - ab;         /* lowest score first */
-    }
-
-  /* the same name, bring installed solvables to the front */
-  if (pool->installed)
-    {
-      if (sa->repo == pool->installed)
-       {
-         if (sb->repo != pool->installed)
-           return -1;
-       }
-      else if (sb->repo == pool->installed)
-       return 1;       
-    }
-  /* sort by repository sub-prio (installed repo handled above) */
-  r = (sb->repo ? sb->repo->subpriority : 0) - (sa->repo ? sa->repo->subpriority : 0);
-  if (r)
-    return r;
-  /* no idea about the order, sort by id */
-  return a - b;
-}
-
-
-/*
- * prune to repository with highest priority.
- * does not prune installed solvables.
- */
-
-static void
-prune_to_highest_prio(Pool *pool, Queue *plist)
-{
-  int i, j;
-  Solvable *s;
-  int bestprio = 0, bestprioset = 0;
-
-  /* prune to highest priority */
-  for (i = 0; i < plist->count; i++)  /* find highest prio in queue */
-    {
-      s = pool->solvables + plist->elements[i];
-      if (pool->installed && s->repo == pool->installed)
-       continue;
-      if (!bestprioset || s->repo->priority > bestprio)
-       {
-         bestprio = s->repo->priority;
-         bestprioset = 1;
-       }
-    }
-  if (!bestprioset)
-    return;
-  for (i = j = 0; i < plist->count; i++) /* remove all with lower prio */
-    {
-      s = pool->solvables + plist->elements[i];
-      if (s->repo->priority == bestprio || (pool->installed && s->repo == pool->installed))
-       plist->elements[j++] = plist->elements[i];
-    }
-  plist->count = j;
-}
-
-
-/* installed packages involed in a dup operation can only be kept
- * if they are identical to a non-installed one */
-static void
-solver_prune_installed_dup_packages(Solver *solv, Queue *plist)
-{
-  Pool *pool = solv->pool;
-  int i, j, bestprio = 0;
-
-  /* find bestprio (again) */
-  for (i = 0; i < plist->count; i++)
-    {
-      Solvable *s = pool->solvables + plist->elements[i];
-      if (s->repo != pool->installed)
-       {
-         bestprio = s->repo->priority;
-         break;
-       }
-    }
-  if (i == plist->count)
-    return;    /* only installed packages, could not find prio */
-  for (i = j = 0; i < plist->count; i++)
-    {
-      Id p = plist->elements[i];
-      Solvable *s = pool->solvables + p;
-      if (s->repo != pool->installed && s->repo->priority < bestprio)
-       continue;
-      if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
-       {
-         Id p2, pp2;
-         int keepit = 0;
-         FOR_PROVIDES(p2, pp2, s->name)
-           {
-             Solvable *s2 = pool->solvables + p2;
-             if (s2->repo == pool->installed || s2->evr != s->evr || s2->repo->priority < bestprio)
-               continue;
-             if (!solvable_identical(s, s2))
-               continue;
-             keepit = 1;
-             if (s2->repo->priority > bestprio)
-               {
-                 /* new max prio! */
-                 bestprio = s2->repo->priority;
-                 j = 0;
-               }
-           }
-         if (!keepit)
-           continue;   /* no identical package found, ignore installed package */
-       }
-      plist->elements[j++] = p;
-    }
-  if (j)
-    plist->count = j;
-}
-
-/*
- * like prune_to_highest_prio, but calls solver prune_installed_dup_packages
- * when there are dup packages
- */
-static inline void
-solver_prune_to_highest_prio(Solver *solv, Queue *plist)
-{
-  prune_to_highest_prio(solv->pool, plist);
-  if (plist->count > 1 && solv->pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size))
-    solver_prune_installed_dup_packages(solv, plist);
-}
-
-
-static void
-solver_prune_to_highest_prio_per_name(Solver *solv, Queue *plist)
-{
-  Pool *pool = solv->pool;
-  Queue pq;
-  int i, j, k;
-  Id name;
-
-  queue_init(&pq);
-  solv_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
-  queue_push(&pq, plist->elements[0]);
-  name = pool->solvables[pq.elements[0]].name;
-  for (i = 1, j = 0; i < plist->count; i++)
-    {
-      if (pool->solvables[plist->elements[i]].name != name)
-       {
-         if (pq.count > 2)
-           solver_prune_to_highest_prio(solv, &pq);
-         for (k = 0; k < pq.count; k++)
-           plist->elements[j++] = pq.elements[k];
-         queue_empty(&pq);
-         queue_push(&pq, plist->elements[i]);
-         name = pool->solvables[pq.elements[0]].name;
-       }
-    }
-  if (pq.count > 2)
-    solver_prune_to_highest_prio(solv, &pq);
-  for (k = 0; k < pq.count; k++)
-    plist->elements[j++] = pq.elements[k];
-  queue_free(&pq);
-  plist->count = j;
-}
-
-
-#ifdef ENABLE_COMPLEX_DEPS
-
-/* simple fixed-size hash for package ids */
-#define CPLXDEPHASH_EMPTY(elements) (memset(elements, 0, sizeof(Id) * 256))
-#define CPLXDEPHASH_SET(elements, p) (elements[(p) & 255] |= (1 << ((p) >> 8 & 31)))
-#define CPLXDEPHASH_TST(elements, p) (elements[(p) & 255] && (elements[(p) & 255] & (1 << ((p) >> 8 & 31))))
-
-static void
-check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp)
-{
-  Pool *pool = solv->pool;
-  Queue q;
-  queue_init(&q);
-  Id p;
-  int i, qcnt;
-
-#if 0
-  printf("check_complex_dep %s\n", pool_dep2str(pool, dep));
-#endif
-  i = pool_normalize_complex_dep(pool, dep, &q, CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    {
-      queue_free(&q);
-      return;
-    }
-  qcnt = q.count;
-  for (i = 0; i < qcnt; i++)
-    {
-      /* we rely on the fact that blocks are ordered here.
-       * if we reach a positive element, we know that we
-       * saw all negative ones */
-      for (; (p = q.elements[i]) < 0; i++)
-       {
-         if (solv->decisionmap[-p] < 0)
-           break;
-         if (solv->decisionmap[-p] == 0)
-           queue_push(&q, -p);         /* undecided negative literal */
-       }
-      if (p <= 0)
-       {
-#if 0
-         printf("complex dep block cannot be true or no pos literals\n");
-#endif
-         while (q.elements[i])
-           i++;
-         if (qcnt != q.count)
-           queue_truncate(&q, qcnt);
-         continue;
-       }
-      if (qcnt == q.count)
-       {
-         /* all negative literals installed, add positive literals to map */
-         for (; (p = q.elements[i]) != 0; i++)
-           MAPSET(m, p);
-       }
-      else
-       {
-         /* at least one undecided negative literal, postpone */
-         int j, k;
-         Queue *cq;
-#if 0
-         printf("add new complex dep block\n");
-         for (j = qcnt; j < q.count; j++)
-           printf("  - %s\n", pool_solvid2str(pool, q.elements[j]));
-#endif
-         while (q.elements[i])
-           i++;
-         if (!(cq = *cqp))
-           {
-             cq = solv_calloc(1, sizeof(Queue));
-             queue_init(cq);
-             queue_insertn(cq, 0, 256, 0);     /* allocate hash area */
-             *cqp = cq;
-           }
-         for (j = qcnt; j < q.count; j++)
-           {
-             p = q.elements[j];
-             /* check if we already have this (dep, p) entry */
-             for (k = 256; k < cq->count; k += 2)
-               if (cq->elements[k + 1] == dep && cq->elements[k] == p)
-                 break;
-             if (k == cq->count)
-               {
-                 /* a new one. add to cq and hash */
-                 queue_push2(cq, p, dep);
-                 CPLXDEPHASH_SET(cq->elements, p);
-               }
-           }
-         queue_truncate(&q, qcnt);
-       }
-    }
-  queue_free(&q);
-}
-
-static void
-recheck_complex_deps(Solver *solv, Id p, Map *m, Queue **cqp)
-{
-  Queue *cq = *cqp;
-  Id pp;
-  int i;
-#if 0
-  printf("recheck_complex_deps for package %s\n", pool_solvid2str(solv->pool, p));
-#endif
-  /* make sure that we don't have a false hit */
-  for (i = 256; i < cq->count; i += 2)
-    if (cq->elements[i] == p)
-      break;
-  if (i == cq->count)
-    return;    /* false alert */
-  if (solv->decisionmap[p] <= 0)
-    return;    /* just in case... */
-
-  /* rebuild the hash, call check_complex_dep for our package */
-  CPLXDEPHASH_EMPTY(cq->elements);
-  for (i = 256; i < cq->count; i += 2)
-    if ((pp = cq->elements[i]) == p)
-      {
-       Id dep = cq->elements[i + 1];
-       queue_deleten(cq, i, 2);
-       i -= 2;
-        check_complex_dep(solv, dep, m, &cq);
-      }
-    else
-      CPLXDEPHASH_SET(cq->elements, pp);
-}
-
-#endif
-
-
-void
-policy_update_recommendsmap(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Solvable *s;
-  Id p, pp, rec, *recp, sug, *sugp;
-
-  if (solv->recommends_index < 0)
-    {
-      MAPZERO(&solv->recommendsmap);
-      MAPZERO(&solv->suggestsmap);
-#ifdef ENABLE_COMPLEX_DEPS
-      if (solv->recommendscplxq)
-       {
-         queue_free(solv->recommendscplxq);
-         solv->recommendscplxq = solv_free(solv->recommendscplxq);
-       }
-      if (solv->suggestscplxq)
-       {
-         queue_free(solv->suggestscplxq);
-         solv->suggestscplxq = solv_free(solv->suggestscplxq);
-       }
-#endif
-      solv->recommends_index = 0;
-    }
-  while (solv->recommends_index < solv->decisionq.count)
-    {
-      p = solv->decisionq.elements[solv->recommends_index++];
-      if (p < 0)
-       continue;
-      s = pool->solvables + p;
-#ifdef ENABLE_COMPLEX_DEPS
-      /* re-check postponed complex blocks */
-      if (solv->recommendscplxq && CPLXDEPHASH_TST(solv->recommendscplxq->elements, p))
-        recheck_complex_deps(solv, p, &solv->recommendsmap, &solv->recommendscplxq);
-      if (solv->suggestscplxq && CPLXDEPHASH_TST(solv->suggestscplxq->elements, p))
-        recheck_complex_deps(solv, p, &solv->suggestsmap, &solv->suggestscplxq);
-#endif
-      if (s->recommends)
-       {
-         recp = s->repo->idarraydata + s->recommends;
-          while ((rec = *recp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, rec))
-               {
-                 check_complex_dep(solv, rec, &solv->recommendsmap, &solv->recommendscplxq);
-                 continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, rec)
-               MAPSET(&solv->recommendsmap, p);
-           }
-       }
-      if (s->suggests)
-       {
-         sugp = s->repo->idarraydata + s->suggests;
-          while ((sug = *sugp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, sug))
-               {
-                 check_complex_dep(solv, sug, &solv->suggestsmap, &solv->suggestscplxq);
-                 continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, sug)
-               MAPSET(&solv->suggestsmap, p);
-           }
-       }
-    }
-}
-
-/* bring suggested/enhanced packages to front
- * installed packages count as suggested */
-static void
-prefer_suggested(Solver *solv, Queue *plist)
-{
-  Pool *pool = solv->pool;
-  int i, count;
-
-  /* update our recommendsmap/suggestsmap */
-  if (solv->recommends_index < solv->decisionq.count)
-    policy_update_recommendsmap(solv);
-
-  for (i = 0, count = plist->count; i < count; i++)
-    {
-      Id p = plist->elements[i];
-      Solvable *s = pool->solvables + p;
-      if ((pool->installed && s->repo == pool->installed) ||
-          MAPTST(&solv->suggestsmap, p) ||
-          solver_is_enhancing(solv, s))
-       continue;       /* good package */
-      /* bring to back */
-     if (i < plist->count - 1)
-       {
-         memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
-         plist->elements[plist->count - 1] = p;
-       }
-      i--;
-      count--;
-    }
-}
-
-/*
- * prune to recommended/suggested packages.
- * does not prune installed packages (they are also somewhat recommended).
- */
-static void
-prune_to_recommended(Solver *solv, Queue *plist)
-{
-  Pool *pool = solv->pool;
-  int i, j, k, ninst;
-  Solvable *s;
-  Id p;
-
-  ninst = 0;
-  if (pool->installed)
-    {
-      for (i = 0; i < plist->count; i++)
-       {
-         p = plist->elements[i];
-         s = pool->solvables + p;
-         if (pool->installed && s->repo == pool->installed)
-           ninst++;
-       }
-    }
-  if (plist->count - ninst < 2)
-    return;
-
-  /* update our recommendsmap/suggestsmap */
-  if (solv->recommends_index < solv->decisionq.count)
-    policy_update_recommendsmap(solv);
-
-  /* prune to recommended/supplemented */
-  ninst = 0;
-  for (i = j = 0; i < plist->count; i++)
-    {
-      p = plist->elements[i];
-      s = pool->solvables + p;
-      if (pool->installed && s->repo == pool->installed)
-       {
-         ninst++;
-         if (j)
-           plist->elements[j++] = p;
-         continue;
-       }
-      if (!MAPTST(&solv->recommendsmap, p))
-       if (!solver_is_supplementing(solv, s))
-         continue;
-      if (!j && ninst)
-       {
-         for (k = 0; j < ninst; k++)
-           {
-             s = pool->solvables + plist->elements[k];
-             if (pool->installed && s->repo == pool->installed)
-               plist->elements[j++] = plist->elements[k];
-           }
-       }
-      plist->elements[j++] = p;
-    }
-  if (j)
-    plist->count = j;
-
-#if 0
-  /* anything left to prune? */
-  if (plist->count - ninst < 2)
-    return;
-
-  /* prune to suggested/enhanced */
-  ninst = 0;
-  for (i = j = 0; i < plist->count; i++)
-    {
-      p = plist->elements[i];
-      s = pool->solvables + p;
-      if (pool->installed && s->repo == pool->installed)
-       {
-         ninst++;
-         if (j)
-           plist->elements[j++] = p;
-         continue;
-       }
-      if (!MAPTST(&solv->suggestsmap, p))
-        if (!solver_is_enhancing(solv, s))
-         continue;
-      if (!j && ninst)
-       {
-         for (k = 0; j < ninst; k++)
-           {
-             s = pool->solvables + plist->elements[k];
-             if (pool->installed && s->repo == pool->installed)
-               plist->elements[j++] = plist->elements[k];
-           }
-       }
-      plist->elements[j++] = p;
-    }
-  if (j)
-    plist->count = j;
-#endif
-}
-
-static void
-prune_to_best_arch(const Pool *pool, Queue *plist)
-{
-  Id a, bestscore;
-  Solvable *s;
-  int i, j;
-
-  if (!pool->id2arch || plist->count < 2)
-    return;
-  bestscore = 0;
-  for (i = 0; i < plist->count; i++)
-    {
-      s = pool->solvables + plist->elements[i];
-      a = s->arch;
-      a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-      if (a && a != 1 && (!bestscore || a < bestscore))
-       bestscore = a;
-    }
-  if (!bestscore)
-    return;
-  for (i = j = 0; i < plist->count; i++)
-    {
-      s = pool->solvables + plist->elements[i];
-      a = s->arch;
-      if (a > pool->lastarch)
-       continue;
-      a = pool->id2arch[a];
-      /* a == 1 -> noarch */
-      if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
-       continue;
-      plist->elements[j++] = plist->elements[i];
-    }
-  if (j)
-    plist->count = j;
-}
-
-
-struct trj_data {
-  Pool *pool;
-  Queue *plist;
-  Id *stack;
-  Id nstack;
-  Id *low;
-  Id firstidx;
-  Id idx;
-};
-
-/* This is Tarjan's SCC algorithm, slightly modified */
-static void
-trj_visit(struct trj_data *trj, Id node)
-{
-  Id *low = trj->low;
-  Pool *pool = trj->pool;
-  Queue *plist = trj->plist;
-  Id myidx, stackstart;
-  Solvable *s;
-  int i;
-  Id p, pp, obs, *obsp;
-
-  low[node] = myidx = trj->idx++;
-  trj->stack[(stackstart = trj->nstack++)] = node;
-
-  s = pool->solvables + plist->elements[node];
-  if (s->obsoletes)
-    {
-      obsp = s->repo->idarraydata + s->obsoletes;
-      while ((obs = *obsp++) != 0)
-       {
-         FOR_PROVIDES(p, pp, obs)
-           {
-             Solvable *ps = pool->solvables + p;
-             if (ps->name == s->name)
-               continue;
-             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-               continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-               continue;
-             /* hmm, expensive. should use hash if plist is big */
-             for (i = 0; i < plist->count; i++)
-               {
-                 if (node != i && plist->elements[i] == p)
-                   {
-                     Id l = low[i];
-                     if (!l)
-                       {
-                         if (!ps->obsoletes)
-                           {
-                             /* don't bother */
-                             trj->idx++;
-                             low[i] = -1;
-                             continue;
-                           }
-                         trj_visit(trj, i);
-                         l = low[i];
-                       }
-                     if (l < 0)
-                       continue;
-                     if (l < trj->firstidx)
-                       {
-                         int k;
-                         /* this means we have reached an old SCC found earlier.
-                          * delete it as we obsolete it */
-                         for (k = l; ; k++)
-                           {
-                             if (low[trj->stack[k]] == l)
-                               low[trj->stack[k]] = -1;
-                             else
-                               break;
-                           }
-                       }
-                     else if (l < low[node])
-                       low[node] = l;
-                   }
-               }
-           }
-       }
-    }
-  if (low[node] == myidx)      /* found a SCC? */
-    {
-      /* we're only interested in SCCs that contain the first node,
-       * as all others are "obsoleted" */
-      if (myidx != trj->firstidx)
-       myidx = -1;
-      for (i = stackstart; i < trj->nstack; i++)
-       low[trj->stack[i]] = myidx;
-      trj->nstack = stackstart;        /* empty stack */
-    }
-}
-
-/*
- * remove entries from plist that are obsoleted by other entries
- * with different name.
- */
-static void
-prune_obsoleted(Pool *pool, Queue *plist)
-{
-  Id data_buf[2 * 16], *data;
-  struct trj_data trj;
-  int i, j;
-  Solvable *s;
-
-  if (plist->count <= 16)
-    {
-      memset(data_buf, 0, sizeof(data_buf));
-      data = data_buf;
-    }
-  else
-    data = solv_calloc(plist->count, 2 * sizeof(Id));
-  trj.pool = pool;
-  trj.plist = plist;
-  trj.low = data;
-  trj.idx = 1;
-  trj.stack = data + plist->count - 1; /* -1 so we can index with idx (which starts with 1) */
-  for (i = 0; i < plist->count; i++)
-    {
-      if (trj.low[i])
-       continue;
-      s = pool->solvables + plist->elements[i];
-      if (s->obsoletes)
-       {
-         trj.firstidx = trj.nstack = trj.idx;
-          trj_visit(&trj, i);
-       }
-      else
-        {
-          Id myidx = trj.idx++;
-          trj.low[i] = myidx;
-          trj.stack[myidx] = i;
-        }
-    }
-  for (i = j = 0; i < plist->count; i++)
-    if (trj.low[i] >= 0)
-      plist->elements[j++] = plist->elements[i];
-  plist->count = j;
-  if (data != data_buf)
-    solv_free(data);
-}
-
-/* this is prune_obsoleted special-cased for two elements */
-static void
-prune_obsoleted_2(Pool *pool, Queue *plist)
-{
-  int i;
-  Solvable *s;
-  Id p, pp, obs, *obsp;
-  Id other;
-  int obmap = 0;
-
-  for (i = 0; i < 2; i++)
-    {
-      s = pool->solvables + plist->elements[i];
-      other = plist->elements[1 - i];
-      if (s->obsoletes)
-       {
-         obsp = s->repo->idarraydata + s->obsoletes;
-         while ((obs = *obsp++) != 0)
-           {
-             FOR_PROVIDES(p, pp, obs)
-               {
-                 Solvable *ps;
-                 if (p != other)
-                   continue;
-                 ps = pool->solvables + p;
-                 if (ps->name == s->name)
-                   continue;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-                   continue;
-                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-                   continue;
-                 obmap |= 1 << i;
-                 break;
-               }
-             if (p)
-               break;
-           }
-       }
-    }
-  if (obmap == 0 || obmap == 3)
-    return;
-  if (obmap == 2)
-    plist->elements[0] = plist->elements[1];
-  plist->count = 1;
-}
-
-/*
- * bring those elements to the front of the queue that
- * have a installed solvable with the same name
- */
-static void
-move_installed_to_front(Pool *pool, Queue *plist)
-{
-  int i, j;
-  Solvable *s;
-  Id p, pp;
-
-  for (i = j = 0; i < plist->count; i++)
-    {
-      s = pool->solvables + plist->elements[i];
-      if (s->repo != pool->installed)
-        {
-          FOR_PROVIDES(p, pp, s->name)
-           {
-             Solvable *ps = pool->solvables + p;
-             if (s->name == ps->name && ps->repo == pool->installed)
-               {
-                 s = ps;
-                 break;
-               }
-           }
-        }
-      if (s->repo == pool->installed)
-       {
-         if (i != j)
-           {
-             p = plist->elements[i];
-              if (i - j == 1)
-               plist->elements[i] = plist->elements[j];
-             else
-               memmove(plist->elements + j + 1, plist->elements + j, (i - j) * sizeof(Id));
-             plist->elements[j] = p;
-           }
-         else if (j + 2 == plist->count)
-           break;      /* no need to check last element if all prev ones are installed */
-         j++;
-       }
-    }
-}
-
-/*
- * prune_to_best_version
- *
- * sort list of packages (given through plist) by name and evr
- * return result through plist
- */
-void
-prune_to_best_version(Pool *pool, Queue *plist)
-{
-  int i, j, r;
-  Solvable *s, *best;
-
-  if (plist->count < 2)                /* no need to prune for a single entry */
-    return;
-  POOL_DEBUG(SOLV_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
-
-  /* sort by name first, prefer installed */
-  solv_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
-
-  /* now find best 'per name' */
-  best = 0;
-  for (i = j = 0; i < plist->count; i++)
-    {
-      s = pool->solvables + plist->elements[i];
-
-      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
-                pool_solvable2str(pool, s),
-                (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
-
-      if (!best)               /* if no best yet, the current is best */
-        {
-          best = s;
-          continue;
-        }
-
-      /* name switch: finish group, re-init */
-      if (best->name != s->name)   /* new name */
-        {
-          plist->elements[j++] = best - pool->solvables; /* move old best to front */
-          best = s;            /* take current as new best */
-          continue;
-        }
-      r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0;
-#ifdef ENABLE_LINKED_PKGS
-      if (r == 0 && has_package_link(pool, s))
-        r = pool_link_evrcmp(pool, best, s);
-#endif
-      if (r < 0)
-       best = s;
-    }
-  plist->elements[j++] = best - pool->solvables;       /* finish last group */
-  plist->count = j;
-
-  /* we reduced the list to one package per name, now look at
-   * package obsoletes */
-  if (plist->count > 1)
-    {
-      if (plist->count == 2)
-        prune_obsoleted_2(pool, plist);
-      else
-        prune_obsoleted(pool, plist);
-    }
-  if (plist->count > 1 && pool->installed)
-    move_installed_to_front(pool, plist);
-}
-
-
-static int
-sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  Id a, *aa = (Id *)ap;
-  Id b, *bb = (Id *)bp;
-  Id r = aa[1] - bb[1];
-  if (r)
-    return r < 0 ? -1 : 1;
-  if (aa[2] == bb[2])
-    return 0;
-  a = aa[2] < 0 ? -aa[2] : aa[2];
-  b = bb[2] < 0 ? -bb[2] : bb[2];
-  if (pool->disttype != DISTTYPE_DEB && a != b)
-    {
-      /* treat release-less versions different */
-      const char *as = pool_id2str(pool, a);
-      const char *bs = pool_id2str(pool, b);
-      if (strchr(as, '-'))
-       {
-         if (!strchr(bs, '-'))
-           return -2;
-       }
-      else
-       {
-         if (strchr(bs, '-'))
-           return 2;
-       }
-    }
-  r = pool_evrcmp(pool, b, a, EVRCMP_COMPARE);
-  if (!r && (aa[2] < 0 || bb[2] < 0))
-    {
-      if (bb[2] >= 0)
-       return 1;
-      if (aa[2] >= 0)
-       return -1;
-    }
-  if (r)
-    return r < 0 ? -1 : 1;
-  return 0;
-}
-
-/* common end of sort_by_srcversion and sort_by_common_dep */
-static void
-sort_by_name_evr_array(Pool *pool, Queue *plist, int count, int ent)
-{
-  Id lastname;
-  int i, j, bad, havebad;
-  Id *pp, *elements = plist->elements;
-
-  if (ent < 2)
-    {
-      queue_truncate(plist, count);
-      return;
-    }
-  solv_sort(elements + count * 2, ent, sizeof(Id) * 3, sort_by_name_evr_sortcmp, pool);
-  lastname = 0;
-  bad = havebad = 0;
-  for (i = 0, pp = elements + count * 2; i < ent; i++, pp += 3)
-    {
-      if (lastname && pp[1] == lastname)
-       {
-          if (pp[0] != pp[-3] && sort_by_name_evr_sortcmp(pp - 3, pp, pool) == -1)
-           {
-#if 0
-             printf("%s - %s: bad %s %s - %s\n", pool_solvid2str(pool, elements[pp[-3]]), pool_solvid2str(pool, elements[pp[0]]), pool_dep2str(pool, lastname), pool_id2str(pool, pp[-1] < 0 ? -pp[-1] : pp[-1]), pool_id2str(pool, pp[2] < 0 ? -pp[2] : pp[2]));
-#endif
-             bad++;
-             havebad = 1;
-           }
-       }
-      else
-       {
-         bad = 0;
-         lastname = pp[1];
-       }
-      elements[count + pp[0]] += bad;
-    }
-
-#if 0
-for (i = 0; i < count; i++)
-  printf("%s badness %d\n", pool_solvid2str(pool, elements[i]), elements[count + i]);
-#endif
-
-  if (havebad)
-    {
-      /* simple stable insertion sort */
-      if (pool->installed)
-       for (i = 0; i < count; i++)
-         if (pool->solvables[elements[i]].repo == pool->installed)
-           elements[i + count] = 0;
-      for (i = 1; i < count; i++)
-       for (j = i, pp = elements + count + j; j > 0; j--, pp--)
-         if (pp[-1] > pp[0])
-           {
-             Id *pp2 = pp - count;
-             Id p = pp[-1];
-             pp[-1] = pp[0];
-             pp[0] = p;
-             p = pp2[-1];
-             pp2[-1] = pp2[0];
-             pp2[0] = p;
-           }
-         else
-           break;
-    }
-  queue_truncate(plist, count);
-}
-
-#if 0
-static void
-sort_by_srcversion(Pool *pool, Queue *plist)
-{
-  int i, count = plist->count, ent = 0;
-  queue_insertn(plist, count, count, 0);
-  for (i = 0; i < count; i++)
-    {
-      Id name, evr, p = plist->elements[i];
-      Solvable *s = pool->solvables + p;
-      if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
-       name = s->name;
-      else
-        name = solvable_lookup_id(s, SOLVABLE_SOURCENAME);
-      if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
-       evr = s->evr;
-      else
-        evr = solvable_lookup_id(s, SOLVABLE_SOURCEEVR);
-      if (!name || !evr || ISRELDEP(evr))
-       continue;
-      queue_push(plist, i);
-      queue_push2(plist, name, evr);
-      ent++;
-    }
-  sort_by_name_evr_array(pool, plist, count, ent);
-}
-#endif
-
-static void
-sort_by_common_dep(Pool *pool, Queue *plist)
-{
-  int i, count = plist->count, ent = 0;
-  Id id, *dp;
-  queue_insertn(plist, count, count, 0);
-  for (i = 0; i < count; i++)
-    {
-      Id p = plist->elements[i];
-      Solvable *s = pool->solvables + p;
-      if (!s->provides)
-       continue;
-      for (dp = s->repo->idarraydata + s->provides; (id = *dp++) != 0; )
-       {
-         Reldep *rd;
-         if (!ISRELDEP(id))
-           continue;
-         rd = GETRELDEP(pool, id);
-         if ((rd->flags == REL_EQ || rd->flags == (REL_EQ | REL_LT) || rd->flags == REL_LT) && !ISRELDEP(rd->evr))
-           {
-             if (rd->flags == REL_EQ)
-               {
-                 /* ignore hashes */
-                 const char *s = pool_id2str(pool, rd->evr);
-                 if (strlen(s) >= 4)
-                   {
-                     while ((*s >= 'a' && *s <= 'f') || (*s >= '0' && *s <= '9'))
-                       s++;
-                     if (!*s)
-                       continue;
-                   }
-               }
-             queue_push(plist, i);
-             queue_push2(plist, rd->name, rd->flags == REL_LT ? -rd->evr : rd->evr);
-             ent++;
-           }
-       }
-    }
-  sort_by_name_evr_array(pool, plist, count, ent);
-}
-
-/* check if we have an update candidate */
-static void
-dislike_old_versions(Pool *pool, Queue *plist)
-{
-  int i, count;
-
-  for (i = 0, count = plist->count; i < count; i++)
-    {
-      Id p = plist->elements[i];
-      Solvable *s = pool->solvables + p;
-      Repo *repo = s->repo;
-      Id q, qq;
-      int bad = 0;
-
-      if (!repo || repo == pool->installed)
-       continue;
-      FOR_PROVIDES(q, qq, s->name)
-       {
-         Solvable *qs = pool->solvables + q;
-         if (q == p)
-           continue;
-         if (s->name != qs->name || s->arch != qs->arch)
-           continue;
-         if (repo->priority != qs->repo->priority)
-           {
-             if (repo->priority > qs->repo->priority)
-               continue;
-             bad = 1;
-             break;
-           }
-         if (pool_evrcmp(pool, qs->evr, s->evr, EVRCMP_COMPARE) > 0)
-           {
-             bad = 1;
-             break;
-           }
-       }
-      if (!bad)
-       continue;
-      /* bring to back */
-      if (i < plist->count - 1)
-       {
-         memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
-         plist->elements[plist->count - 1] = p;
-       }
-      i--;
-      count--;
-    }
-}
-
-/*
- *  POLICY_MODE_CHOOSE:     default, do all pruning steps
- *  POLICY_MODE_RECOMMEND:  leave out prune_to_recommended
- *  POLICY_MODE_SUGGEST:    leave out prune_to_recommended, do prio pruning just per name
- */
-void
-policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
-{
-  Pool *pool = solv->pool;
-  if (plist->count > 1)
-    {
-      if (mode != POLICY_MODE_SUGGEST)
-        solver_prune_to_highest_prio(solv, plist);
-      else
-        solver_prune_to_highest_prio_per_name(solv, plist);
-    }
-  if (plist->count > 1)
-    prune_to_best_arch(pool, plist);
-  if (plist->count > 1)
-    prune_to_best_version(pool, plist);
-  if (plist->count > 1 && (mode == POLICY_MODE_CHOOSE || mode == POLICY_MODE_CHOOSE_NOREORDER))
-    {
-      prune_to_recommended(solv, plist);
-      if (plist->count > 1 && mode != POLICY_MODE_CHOOSE_NOREORDER)
-       {
-         /* do some fancy reordering */
-#if 0
-         sort_by_srcversion(pool, plist);
-#endif
-         dislike_old_versions(pool, plist);
-         sort_by_common_dep(pool, plist);
-         prefer_suggested(solv, plist);
-       }
-    }
-}
-
-
-/* check if there is an illegal architecture change if
- * installed solvable s1 is replaced by s2 */
-int
-policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
-{
-  Pool *pool = solv->pool;
-  Id a1 = s1->arch, a2 = s2->arch;
-
-  /* we allow changes to/from noarch */
-  if (a1 == a2 || a1 == pool->noarchid || a2 == pool->noarchid)
-    return 0;
-  if (!pool->id2arch)
-    return 0;
-  a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
-  a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
-  if (((a1 ^ a2) & 0xffff0000) != 0)
-    return 1;
-  return 0;
-}
-
-/* check if there is an illegal vendor change if
- * installed solvable s1 is replaced by s2 */
-int
-policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
-{
-  Pool *pool = solv->pool;
-  Id v1, v2;
-  Id vendormask1, vendormask2;
-
-  if (pool->custom_vendorcheck)
-     return pool->custom_vendorcheck(pool, s1, s2);
-
-  /* treat a missing vendor as empty string */
-  v1 = s1->vendor ? s1->vendor : ID_EMPTY;
-  v2 = s2->vendor ? s2->vendor : ID_EMPTY;
-  if (v1 == v2)
-    return 0;
-  vendormask1 = pool_vendor2mask(pool, v1);
-  if (!vendormask1)
-    return 1;  /* can't match */
-  vendormask2 = pool_vendor2mask(pool, v2);
-  if ((vendormask1 & vendormask2) != 0)
-    return 0;
-  return 1;    /* no class matches */
-}
-
-/* check if it is illegal to replace installed
- * package "is" with package "s" (which must obsolete "is")
- */
-int
-policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
-{
-  Pool *pool = solv->pool;
-  int ret = 0;
-  int duppkg = solv->dupmap_all ? 1 : 0;
-  if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !(duppkg ? solv->dup_allowdowngrade : solv->allowdowngrade))
-    {
-      if (is->name == s->name && pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
-       ret |= POLICY_ILLEGAL_DOWNGRADE;
-    }
-  if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !(duppkg ? solv->dup_allowarchchange : solv->allowarchchange))
-    {
-      if (is->arch != s->arch && policy_illegal_archchange(solv, is, s))
-       ret |= POLICY_ILLEGAL_ARCHCHANGE;
-    }
-  if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !(duppkg ? solv->dup_allowvendorchange : solv->allowvendorchange))
-    {
-      if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, is, s))
-       ret |= POLICY_ILLEGAL_VENDORCHANGE;
-    }
-  if (!(ignore & POLICY_ILLEGAL_NAMECHANGE) && !(duppkg ? solv->dup_allownamechange : solv->allownamechange))
-    {
-      if (is->name != s->name)
-       ret |= POLICY_ILLEGAL_NAMECHANGE;
-    }
-  return ret;
-}
-
-/*-------------------------------------------------------------------
- *
- * create reverse obsoletes map for installed solvables
- *
- * For each installed solvable find which packages with *different* names
- * obsolete the solvable.
- * This index is used in policy_findupdatepackages() below.
- */
-void
-policy_create_obsolete_index(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Solvable *s;
-  Repo *installed = solv->installed;
-  Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
-  int i, n, cnt;
-
-  solv->obsoletes = solv_free(solv->obsoletes);
-  solv->obsoletes_data = solv_free(solv->obsoletes_data);
-  if (!installed || installed->start == installed->end)
-    return;
-  cnt = installed->end - installed->start;
-  solv->obsoletes = obsoletes = solv_calloc(cnt, sizeof(Id));
-  for (i = 1; i < pool->nsolvables; i++)
-    {
-      s = pool->solvables + i;
-      if (!s->obsoletes)
-       continue;
-      if (!pool_installable(pool, s))
-       continue;
-      obsp = s->repo->idarraydata + s->obsoletes;
-      while ((obs = *obsp++) != 0)
-       {
-         FOR_PROVIDES(p, pp, obs)
-           {
-             Solvable *ps = pool->solvables + p;;
-             if (ps->repo != installed)
-               continue;
-             if (ps->name == s->name)
-               continue;
-             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-               continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-               continue;
-             obsoletes[p - installed->start]++;
-           }
-       }
-    }
-  n = 0;
-  for (i = 0; i < cnt; i++)
-    if (obsoletes[i])
-      {
-        n += obsoletes[i] + 1;
-        obsoletes[i] = n;
-      }
-  solv->obsoletes_data = obsoletes_data = solv_calloc(n + 1, sizeof(Id));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
-  for (i = pool->nsolvables - 1; i > 0; i--)
-    {
-      s = pool->solvables + i;
-      if (!s->obsoletes)
-       continue;
-      if (!pool_installable(pool, s))
-       continue;
-      obsp = s->repo->idarraydata + s->obsoletes;
-      while ((obs = *obsp++) != 0)
-       {
-         FOR_PROVIDES(p, pp, obs)
-           {
-             Solvable *ps = pool->solvables + p;;
-             if (ps->repo != installed)
-               continue;
-             if (ps->name == s->name)
-               continue;
-             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-               continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-               continue;
-             if (obsoletes_data[obsoletes[p - installed->start]] != i)
-               obsoletes_data[--obsoletes[p - installed->start]] = i;
-           }
-       }
-    }
-}
-
-
-/*
- * find update candidates
- *
- * s: installed solvable to be updated
- * qs: [out] queue to hold Ids of candidates
- * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
- *            2 = dup mode
- *
- */
-void
-policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
-{
-  /* installed packages get a special upgrade allowed rule */
-  Pool *pool = solv->pool;
-  Id p, pp, n, p2, pp2;
-  Id obs, *obsp;
-  Solvable *ps;
-  int haveprovobs = 0;
-  int allowdowngrade = allow_all ? 1 : solv->allowdowngrade;
-  int allownamechange = allow_all ? 1 : solv->allownamechange;
-  int allowarchchange = allow_all ? 1 : solv->allowarchchange;
-  int allowvendorchange = allow_all ? 1 : solv->allowvendorchange;
-  if (allow_all == 2)
-    {
-      allowdowngrade = solv->dup_allowdowngrade;
-      allownamechange = solv->dup_allownamechange;
-      allowarchchange = solv->dup_allowarchchange;
-      allowvendorchange = solv->dup_allowvendorchange;
-    }
-
-  queue_empty(qs);
-
-  n = s - pool->solvables;
-
-  /*
-   * look for updates for s
-   */
-  FOR_PROVIDES(p, pp, s->name) /* every provider of s' name */
-    {
-      if (p == n)              /* skip itself */
-       continue;
-
-      ps = pool->solvables + p;
-      if (s->name == ps->name) /* name match */
-       {
-         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
-           continue;
-         if (!allowdowngrade && pool_evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0)
-           continue;
-       }
-      else if (!allownamechange)
-       continue;
-      else if ((!solv->noupdateprovide || solv->needupdateprovide) && ps->obsoletes)   /* provides/obsoletes combination ? */
-       {
-         /* check if package ps obsoletes installed package s */
-         /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
-          * use it to limit our update candidates */
-         if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, ps))
-           continue;
-         obsp = ps->repo->idarraydata + ps->obsoletes;
-         while ((obs = *obsp++) != 0)  /* for all obsoletes */
-           {
-             FOR_PROVIDES(p2, pp2, obs)   /* and all matching providers of the obsoletes */
-               {
-                 Solvable *ps2 = pool->solvables + p2;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
-                   continue;
-                 if (p2 == n)          /* match ! */
-                   break;
-               }
-             if (p2)                   /* match! */
-               break;
-           }
-         if (!obs)                     /* continue if no match */
-           continue;
-         /* here we have 'p' with a matching provides/obsoletes combination
-          * thus flagging p as a valid update candidate for s
-          */
-         haveprovobs = 1;
-       }
-      else
-        continue;
-      if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
-       continue;
-      if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
-       continue;
-      queue_push(qs, p);
-    }
-  if (!allownamechange)
-    return;
-  /* if we have found some valid candidates and noupdateprovide is not set, we're
-     done. otherwise we fallback to all obsoletes */
-  if (solv->needupdateprovide || (!solv->noupdateprovide && haveprovobs))
-    return;
-  if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
-    {
-      Id *opp;
-      for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
-       {
-         ps = pool->solvables + p;
-         if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
-           continue;
-         if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
-           continue;
-         /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
-          * use it to limit our update candidates */
-         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
-           continue;
-         queue_push(qs, p);
-       }
-    }
-}
-
-const char *
-policy_illegal2str(Solver *solv, int illegal, Solvable *s, Solvable *rs)
-{
-  Pool *pool = solv->pool;
-  const char *str;
-  if (illegal == POLICY_ILLEGAL_DOWNGRADE)
-    {
-      str = pool_tmpjoin(pool, "downgrade of ", pool_solvable2str(pool, s), 0);
-      return pool_tmpappend(pool, str, " to ", pool_solvable2str(pool, rs));
-    }
-  if (illegal == POLICY_ILLEGAL_NAMECHANGE)
-    {
-      str = pool_tmpjoin(pool, "name change of ", pool_solvable2str(pool, s), 0);
-      return pool_tmpappend(pool, str, " to ", pool_solvable2str(pool, rs));
-    }
-  if (illegal == POLICY_ILLEGAL_ARCHCHANGE)
-    {
-      str = pool_tmpjoin(pool, "architecture change of ", pool_solvable2str(pool, s), 0);
-      return pool_tmpappend(pool, str, " to ", pool_solvable2str(pool, rs));
-    }
-  if (illegal == POLICY_ILLEGAL_VENDORCHANGE)
-    {
-      str = pool_tmpjoin(pool, "vendor change from '", pool_id2str(pool, s->vendor), "' (");
-      if (rs->vendor)
-       {
-          str = pool_tmpappend(pool, str, pool_solvable2str(pool, s), ") to '");
-          str = pool_tmpappend(pool, str, pool_id2str(pool, rs->vendor), "' (");
-       }
-      else
-        str = pool_tmpappend(pool, str, pool_solvable2str(pool, s), ") to no vendor (");
-      return pool_tmpappend(pool, str, pool_solvable2str(pool, rs), ")");
-    }
-  return "unknown illegal change";
-}
-
diff --git a/libsolv-0.6.15/src/policy.h b/libsolv-0.6.15/src/policy.h
deleted file mode 100644 (file)
index 73410ee..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * Generic policy interface for SAT solver
- * The policy* function can be "overloaded" by defining a callback in the solver struct.
- */
-
-#include "solver.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define POLICY_MODE_CHOOSE     0
-#define POLICY_MODE_RECOMMEND  1
-#define POLICY_MODE_SUGGEST    2
-#define POLICY_MODE_CHOOSE_NOREORDER   3       /* internal, do not use */
-
-
-#define POLICY_ILLEGAL_DOWNGRADE       1
-#define POLICY_ILLEGAL_ARCHCHANGE      2
-#define POLICY_ILLEGAL_VENDORCHANGE    4
-#define POLICY_ILLEGAL_NAMECHANGE      8
-
-extern void policy_filter_unwanted(Solver *solv, Queue *plist, int mode);
-extern int  policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2);
-extern int  policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2);
-extern int  policy_is_illegal(Solver *solv, Solvable *s1, Solvable *s2, int ignore);
-extern void policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allowall);
-extern const char *policy_illegal2str(Solver *solv, int illegal, Solvable *s, Solvable *rs);
-extern void policy_update_recommendsmap(Solver *solv);
-
-extern void policy_create_obsolete_index(Solver *solv);
-
-/* internal, do not use */
-extern void prune_to_best_version(Pool *pool, Queue *plist);
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/libsolv-0.6.15/src/pool.c b/libsolv-0.6.15/src/pool.c
deleted file mode 100644 (file)
index 85932bf..0000000
+++ /dev/null
@@ -1,2691 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * pool.c
- *
- * The pool contains information about solvables
- * stored optimized for memory consumption and fast retrieval.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "pool.h"
-#include "poolvendor.h"
-#include "repo.h"
-#include "poolid.h"
-#include "poolid_private.h"
-#include "poolarch.h"
-#include "util.h"
-#include "bitmap.h"
-#include "evr.h"
-
-#define SOLVABLE_BLOCK 255
-
-#undef LIBSOLV_KNOWNID_H
-#define KNOWNID_INITIALIZE
-#include "knownid.h"
-#undef KNOWNID_INITIALIZE
-
-/* create pool */
-Pool *
-pool_create(void)
-{
-  Pool *pool;
-  Solvable *s;
-
-  pool = (Pool *)solv_calloc(1, sizeof(*pool));
-
-  stringpool_init (&pool->ss, initpool_data);
-
-  /* alloc space for RelDep 0 */
-  pool->rels = solv_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
-  pool->nrels = 1;
-  memset(pool->rels, 0, sizeof(Reldep));
-
-  /* alloc space for Solvable 0 and system solvable */
-  pool->solvables = solv_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
-  pool->nsolvables = 2;
-  memset(pool->solvables, 0, 2 * sizeof(Solvable));
-
-  queue_init(&pool->vendormap);
-  queue_init(&pool->pooljobs);
-  queue_init(&pool->lazywhatprovidesq);
-
-#if defined(DEBIAN)
-  pool->disttype = DISTTYPE_DEB;
-  pool->noarchid = ARCH_ALL;
-#elif defined(ARCHLINUX)
-  pool->disttype = DISTTYPE_ARCH;
-  pool->noarchid = ARCH_ANY;
-#elif defined(HAIKU)
-  pool->disttype = DISTTYPE_HAIKU;
-  pool->noarchid = ARCH_ANY;
-  pool->obsoleteusesprovides = 1;
-#else
-  pool->disttype = DISTTYPE_RPM;
-  pool->noarchid = ARCH_NOARCH;
-#endif
-
-  /* initialize the system solvable */
-  s = pool->solvables + SYSTEMSOLVABLE;
-  s->name = SYSTEM_SYSTEM;
-  s->arch = pool->noarchid;
-  s->evr = ID_EMPTY;
-
-  pool->debugmask = SOLV_DEBUG_RESULT; /* FIXME */
-#if defined(FEDORA) || defined(MAGEIA)
-  pool->implicitobsoleteusescolors = 1;
-#endif
-#ifdef RPM5
-  pool->noobsoletesmultiversion = 1;
-  pool->forbidselfconflicts = 1;
-  pool->obsoleteusesprovides = 1;
-  pool->implicitobsoleteusesprovides = 1;
-  pool->havedistepoch = 1;
-#endif
-  return pool;
-}
-
-
-/* free all the resources of our pool */
-void
-pool_free(Pool *pool)
-{
-  int i;
-
-  pool_freewhatprovides(pool);
-  pool_freeidhashes(pool);
-  pool_freeallrepos(pool, 1);
-  solv_free(pool->id2arch);
-  solv_free(pool->id2color);
-  solv_free(pool->solvables);
-  stringpool_free(&pool->ss);
-  solv_free(pool->rels);
-  pool_setvendorclasses(pool, 0);
-  queue_free(&pool->vendormap);
-  queue_free(&pool->pooljobs);
-  queue_free(&pool->lazywhatprovidesq);
-  for (i = 0; i < POOL_TMPSPACEBUF; i++)
-    solv_free(pool->tmpspace.buf[i]);
-  for (i = 0; i < pool->nlanguages; i++)
-    free((char *)pool->languages[i]);
-  solv_free((void *)pool->languages);
-  solv_free(pool->languagecache);
-  solv_free(pool->errstr);
-  solv_free(pool->rootdir);
-  solv_free(pool);
-}
-
-void
-pool_freeallrepos(Pool *pool, int reuseids)
-{
-  int i;
-
-  pool_freewhatprovides(pool);
-  for (i = 1; i < pool->nrepos; i++)
-    if (pool->repos[i])
-      repo_freedata(pool->repos[i]);
-  pool->repos = solv_free(pool->repos);
-  pool->nrepos = 0;
-  pool->urepos = 0;
-  /* the first two solvables don't belong to a repo */
-  pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
-}
-
-int
-pool_setdisttype(Pool *pool, int disttype)
-{
-#ifdef MULTI_SEMANTICS
-  int olddisttype = pool->disttype;
-  switch(disttype)
-    {
-    case DISTTYPE_RPM:
-      pool->noarchid = ARCH_NOARCH;
-      break;
-    case DISTTYPE_DEB:
-      pool->noarchid = ARCH_ALL;
-      break;
-    case DISTTYPE_ARCH:
-    case DISTTYPE_HAIKU:
-      pool->noarchid = ARCH_ANY;
-      break;
-    default:
-      return -1;
-    }
-  pool->disttype = disttype;
-  pool->solvables[SYSTEMSOLVABLE].arch = pool->noarchid;
-  return olddisttype;
-#else
-  return pool->disttype == disttype ? disttype : -1;
-#endif
-}
-
-int
-pool_get_flag(Pool *pool, int flag)
-{
-  switch (flag)
-    {
-    case POOL_FLAG_PROMOTEEPOCH:
-      return pool->promoteepoch;
-    case POOL_FLAG_FORBIDSELFCONFLICTS:
-      return pool->forbidselfconflicts;
-    case POOL_FLAG_OBSOLETEUSESPROVIDES:
-      return pool->obsoleteusesprovides;
-    case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
-      return pool->implicitobsoleteusesprovides;
-    case POOL_FLAG_OBSOLETEUSESCOLORS:
-      return pool->obsoleteusescolors;
-    case POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS:
-      return pool->implicitobsoleteusescolors;
-    case POOL_FLAG_NOINSTALLEDOBSOLETES:
-      return pool->noinstalledobsoletes;
-    case POOL_FLAG_HAVEDISTEPOCH:
-      return pool->havedistepoch;
-    case POOL_FLAG_NOOBSOLETESMULTIVERSION:
-      return pool->noobsoletesmultiversion;
-    case POOL_FLAG_ADDFILEPROVIDESFILTERED:
-      return pool->addfileprovidesfiltered;
-    case POOL_FLAG_NOWHATPROVIDESAUX:
-      return pool->nowhatprovidesaux;
-    default:
-      break;
-    }
-  return -1;
-}
-
-int
-pool_set_flag(Pool *pool, int flag, int value)
-{
-  int old = pool_get_flag(pool, flag);
-  switch (flag)
-    {
-    case POOL_FLAG_PROMOTEEPOCH:
-      pool->promoteepoch = value;
-      break;
-    case POOL_FLAG_FORBIDSELFCONFLICTS:
-      pool->forbidselfconflicts = value;
-      break;
-    case POOL_FLAG_OBSOLETEUSESPROVIDES:
-      pool->obsoleteusesprovides = value;
-      break;
-    case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
-      pool->implicitobsoleteusesprovides = value;
-      break;
-    case POOL_FLAG_OBSOLETEUSESCOLORS:
-      pool->obsoleteusescolors = value;
-      break;
-    case POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS:
-      pool->implicitobsoleteusescolors = value;
-      break;
-    case POOL_FLAG_NOINSTALLEDOBSOLETES:
-      pool->noinstalledobsoletes = value;
-      break;
-    case POOL_FLAG_HAVEDISTEPOCH:
-      pool->havedistepoch = value;
-      break;
-    case POOL_FLAG_NOOBSOLETESMULTIVERSION:
-      pool->noobsoletesmultiversion = value;
-      break;
-    case POOL_FLAG_ADDFILEPROVIDESFILTERED:
-      pool->addfileprovidesfiltered = value;
-      break;
-    case POOL_FLAG_NOWHATPROVIDESAUX:
-      pool->nowhatprovidesaux = value;
-      break;
-    default:
-      break;
-    }
-  return old;
-}
-
-
-Id
-pool_add_solvable(Pool *pool)
-{
-  pool->solvables = solv_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
-  memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
-  return pool->nsolvables++;
-}
-
-Id
-pool_add_solvable_block(Pool *pool, int count)
-{
-  Id nsolvables = pool->nsolvables;
-  if (!count)
-    return nsolvables;
-  pool->solvables = solv_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
-  memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
-  pool->nsolvables += count;
-  return nsolvables;
-}
-
-void
-pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
-{
-  if (!count)
-    return;
-  if (reuseids && start + count == pool->nsolvables)
-    {
-      /* might want to shrink solvable array */
-      pool->nsolvables = start;
-      return;
-    }
-  memset(pool->solvables + start, 0, sizeof(Solvable) * count);
-}
-
-
-void
-pool_set_installed(Pool *pool, Repo *installed)
-{
-  if (pool->installed == installed)
-    return;
-  pool->installed = installed;
-  pool_freewhatprovides(pool);
-}
-
-static int
-pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  int r;
-  Pool *pool = dp;
-  Id oa, ob, *da, *db;
-  oa = pool->whatprovides[*(Id *)ap];
-  ob = pool->whatprovides[*(Id *)bp];
-  if (oa == ob)
-    return *(Id *)ap - *(Id *)bp;
-  da = pool->whatprovidesdata + oa;
-  db = pool->whatprovidesdata + ob;
-  while (*db)
-    if ((r = (*da++ - *db++)) != 0)
-      return r;
-  if (*da)
-    return *da;
-  return *(Id *)ap - *(Id *)bp;
-}
-
-/*
- * pool_shrink_whatprovides  - unify whatprovides data
- *
- * whatprovides_rel must be empty for this to work!
- *
- */
-static void
-pool_shrink_whatprovides(Pool *pool)
-{
-  Id i, n, id;
-  Id *sorted;
-  Id lastid, *last, *dp, *lp;
-  Offset o;
-  int r;
-
-  if (pool->ss.nstrings < 3)
-    return;
-  sorted = solv_malloc2(pool->ss.nstrings, sizeof(Id));
-  for (i = id = 0; id < pool->ss.nstrings; id++)
-    if (pool->whatprovides[id] >= 4)
-      sorted[i++] = id;
-  n = i;
-  solv_sort(sorted, n, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool);
-  last = 0;
-  lastid = 0;
-  for (i = 0; i < n; i++)
-    {
-      id = sorted[i];
-      o = pool->whatprovides[id];
-      dp = pool->whatprovidesdata + o;
-      if (last)
-       {
-         lp = last;
-         while (*dp)   
-           if (*dp++ != *lp++)
-             {
-               last = 0;
-               break;
-             }
-         if (last && *lp)
-           last = 0;
-         if (last)
-           {
-             pool->whatprovides[id] = -lastid;
-             continue;
-           }
-       }
-      last = pool->whatprovidesdata + o;
-      lastid = id;
-    }
-  solv_free(sorted);
-  dp = pool->whatprovidesdata + 4;
-  for (id = 1; id < pool->ss.nstrings; id++)
-    {
-      o = pool->whatprovides[id];
-      if (!o)
-       continue;
-      if ((Id)o < 0)
-       {
-         i = -(Id)o;
-         if (i >= id)
-           abort();
-         pool->whatprovides[id] = pool->whatprovides[i];
-         continue;
-       }
-      if (o < 4)
-       continue;
-      lp = pool->whatprovidesdata + o;
-      if (lp < dp)
-       abort();
-      pool->whatprovides[id] = dp - pool->whatprovidesdata;
-      while ((*dp++ = *lp++) != 0)
-       ;
-    }
-  o = dp - pool->whatprovidesdata;
-  POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
-  if (pool->whatprovidesdataoff == o)
-    return;
-  r = pool->whatprovidesdataoff - o;
-  pool->whatprovidesdataoff = o;
-  pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
-  if (r > pool->whatprovidesdataleft)
-    r = pool->whatprovidesdataleft;
-  memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
-}
-
-/* this gets rid of all the zeros in the aux */
-static void
-pool_shrink_whatprovidesaux(Pool *pool)
-{
-  int num = pool->whatprovidesauxoff;
-  Id id;
-  Offset newoff;
-  Id *op, *wp = pool->whatprovidesauxdata + 1;
-  int i;
-
-  for (i = 0; i < num; i++)
-    {
-      Offset o = pool->whatprovidesaux[i];
-      if (o < 2)
-       continue;
-      op = pool->whatprovidesauxdata + o;
-      pool->whatprovidesaux[i] = wp - pool->whatprovidesauxdata;
-      if (op < wp)
-       abort();
-      while ((id = *op++) != 0)
-       *wp++ = id;
-    }
-  newoff = wp - pool->whatprovidesauxdata;
-  pool->whatprovidesauxdata = solv_realloc(pool->whatprovidesauxdata, newoff * sizeof(Id));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesauxdata from %d to %d\n", pool->whatprovidesauxdataoff, newoff);
-  pool->whatprovidesauxdataoff = newoff;
-}
-
-
-/*
- * pool_createwhatprovides()
- *
- * create hashes over pool of solvables to ease provide lookups
- *
- */
-void
-pool_createwhatprovides(Pool *pool)
-{
-  int i, num, np, extra;
-  Offset off;
-  Solvable *s;
-  Id id;
-  Offset *idp, n;
-  Offset *whatprovides;
-  Id *whatprovidesdata, *dp, *whatprovidesauxdata;
-  Offset *whatprovidesaux;
-  Repo *installed = pool->installed;
-  unsigned int now;
-
-  now = solv_timems(0);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "number of solvables: %d, memory used: %d K\n", pool->nsolvables, pool->nsolvables * (int)sizeof(Solvable) / 1024);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "string memory used: %d K array + %d K data,  rel memory used: %d K array\n", pool->ss.nstrings / (1024 / (int)sizeof(Id)), pool->ss.sstrings / 1024, pool->nrels * (int)sizeof(Reldep) / 1024);
-  if (pool->ss.stringhashmask || pool->relhashmask)
-    POOL_DEBUG(SOLV_DEBUG_STATS, "string hash memory: %d K, rel hash memory : %d K\n", (pool->ss.stringhashmask + 1) / (int)(1024/sizeof(Id)), (pool->relhashmask + 1) / (int)(1024/sizeof(Id)));
-
-  pool_freeidhashes(pool);     /* XXX: should not be here! */
-  pool_freewhatprovides(pool);
-  num = pool->ss.nstrings;
-  pool->whatprovides = whatprovides = solv_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
-  pool->whatprovides_rel = solv_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
-
-  /* count providers for each name */
-  for (i = pool->nsolvables - 1; i > 0; i--)
-    {
-      Id *pp;
-      s = pool->solvables + i;
-      if (!s->provides || !s->repo || s->repo->disabled)
-       continue;
-      /* we always need the installed solvable in the whatprovides data,
-         otherwise obsoletes/conflicts on them won't work */
-      if (s->repo != installed && !pool_installable(pool, s))
-       continue;
-      pp = s->repo->idarraydata + s->provides;
-      while ((id = *pp++) != 0)
-       {
-         while (ISRELDEP(id))
-           {
-             Reldep *rd = GETRELDEP(pool, id);
-             id = rd->name;
-           }
-         whatprovides[id]++;          /* inc count of providers */
-       }
-    }
-
-  off = 4;     /* first entry is undef, second is empty list, third is system solvable  */
-  np = 0;                             /* number of names provided */
-  for (i = 0, idp = whatprovides; i < num; i++, idp++)
-    {
-      n = *idp;
-      if (!n)                          /* no providers */
-       {
-         *idp = 1;                     /* offset for empty list */
-         continue;
-       }
-      off += n;                                /* make space for all providers */
-      *idp = off++;                    /* now idp points to terminating zero */
-      np++;                            /* inc # of provider 'slots' for stats */
-    }
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "provide ids: %d\n", np);
-
-  /* reserve some space for relation data */
-  extra = 2 * pool->nrels;
-  if (extra < 256)
-    extra = 256;
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
-
-  /* alloc space for all providers + extra */
-  whatprovidesdata = solv_calloc(off + extra, sizeof(Id));
-  whatprovidesdata[2] = SYSTEMSOLVABLE;
-
-  /* alloc aux vector */
-  whatprovidesauxdata = 0;
-  if (!pool->nowhatprovidesaux)
-    {
-      pool->whatprovidesaux = whatprovidesaux = solv_calloc(num, sizeof(Offset));
-      pool->whatprovidesauxoff = num;
-      pool->whatprovidesauxdataoff = off;
-      pool->whatprovidesauxdata = whatprovidesauxdata = solv_calloc(pool->whatprovidesauxdataoff, sizeof(Id));
-    }
-
-  /* now fill data for all provides */
-  for (i = pool->nsolvables - 1; i > 0; i--)
-    {
-      Id *pp;
-      s = pool->solvables + i;
-      if (!s->provides || !s->repo || s->repo->disabled)
-       continue;
-      if (s->repo != installed && !pool_installable(pool, s))
-       continue;
-
-      /* for all provides of this solvable */
-      pp = s->repo->idarraydata + s->provides;
-      while ((id = *pp++) != 0)
-       {
-         Id auxid = id;
-         while (ISRELDEP(id))
-           {
-             Reldep *rd = GETRELDEP(pool, id);
-             id = rd->name;
-           }
-         dp = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
-         if (*dp != i)         /* don't add same solvable twice */
-           {
-             dp[-1] = i;
-             whatprovides[id]--;
-           }
-         else
-           auxid = 1;
-         if (whatprovidesauxdata)
-           whatprovidesauxdata[whatprovides[id]] = auxid;
-       }
-    }
-  if (pool->whatprovidesaux)
-    memcpy(pool->whatprovidesaux, pool->whatprovides, num * sizeof(Id));
-  pool->whatprovidesdata = whatprovidesdata;
-  pool->whatprovidesdataoff = off;
-  pool->whatprovidesdataleft = extra;
-  pool_shrink_whatprovides(pool);
-  if (pool->whatprovidesaux)
-    pool_shrink_whatprovidesaux(pool);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id)));
-  if (pool->whatprovidesaux)
-    POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovidesaux memory used: %d K id array, %d K data\n", pool->whatprovidesauxoff / (int)(1024/sizeof(Id)), pool->whatprovidesauxdataoff / (int)(1024/sizeof(Id)));
-
-  queue_empty(&pool->lazywhatprovidesq);
-  if ((!pool->addedfileprovides && pool->disttype == DISTTYPE_RPM) || pool->addedfileprovides == 1)
-    {
-      if (!pool->addedfileprovides)
-       POOL_DEBUG(SOLV_DEBUG_STATS, "WARNING: pool_addfileprovides was not called, this may result in slow operation\n");
-      /* lazyly add file provides */
-      for (i = 1; i < num; i++)
-       {
-         const char *str = pool->ss.stringspace + pool->ss.strings[i];
-         if (str[0] != '/')
-           continue;
-         if (pool->addedfileprovides == 1 && repodata_filelistfilter_matches(0, str))
-           continue;
-         /* setup lazy adding, but remember old value */
-         if (pool->whatprovides[i] > 1)
-           queue_push2(&pool->lazywhatprovidesq, i, pool->whatprovides[i]);
-         pool->whatprovides[i] = 0;
-         if (pool->whatprovidesaux)
-           pool->whatprovidesaux[i] = 0;       /* sorry */
-       }
-      POOL_DEBUG(SOLV_DEBUG_STATS, "lazywhatprovidesq size: %d entries\n", pool->lazywhatprovidesq.count / 2);
-    }
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "createwhatprovides took %d ms\n", solv_timems(now));
-}
-
-/*
- * free all of our whatprovides data
- * be careful, everything internalized with pool_queuetowhatprovides is
- * gone, too
- */
-void
-pool_freewhatprovides(Pool *pool)
-{
-  pool->whatprovides = solv_free(pool->whatprovides);
-  pool->whatprovides_rel = solv_free(pool->whatprovides_rel);
-  pool->whatprovidesdata = solv_free(pool->whatprovidesdata);
-  pool->whatprovidesdataoff = 0;
-  pool->whatprovidesdataleft = 0;
-  pool->whatprovidesaux = solv_free(pool->whatprovidesaux);
-  pool->whatprovidesauxdata = solv_free(pool->whatprovidesauxdata);
-  pool->whatprovidesauxoff = 0;
-  pool->whatprovidesauxdataoff = 0;
-}
-
-
-/******************************************************************************/
-
-/*
- * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
- *
- * used for whatprovides, jobs, learnt rules, selections
- * input: q: queue of Ids
- * returns: Offset into whatprovidesdata
- *
- */
-
-Id
-pool_ids2whatprovides(Pool *pool, Id *ids, int count)
-{
-  Offset off;
-
-  if (count == 0)                     /* queue empty -> 1 */
-    return 1;
-  if (count == 1 && *ids == SYSTEMSOLVABLE)
-    return 2;
-
-  /* extend whatprovidesdata if needed, +1 for 0-termination */
-  if (pool->whatprovidesdataleft < count + 1)
-    {
-      POOL_DEBUG(SOLV_DEBUG_STATS, "growing provides hash data...\n");
-      pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
-      pool->whatprovidesdataleft = count + 4096;
-    }
-
-  /* copy queue to next free slot */
-  off = pool->whatprovidesdataoff;
-  memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, ids, count * sizeof(Id));
-
-  /* adapt count and 0-terminate */
-  pool->whatprovidesdataoff += count;
-  pool->whatprovidesdata[pool->whatprovidesdataoff++] = 0;
-  pool->whatprovidesdataleft -= count + 1;
-
-  return (Id)off;
-}
-
-Id
-pool_queuetowhatprovides(Pool *pool, Queue *q)
-{
-  int count = q->count;
-  if (count == 0)                     /* queue empty -> 1 */
-    return 1;
-  if (count == 1 && q->elements[0] == SYSTEMSOLVABLE)
-    return 2;
-  return pool_ids2whatprovides(pool, q->elements, count);
-}
-
-
-/*************************************************************************/
-
-#if defined(MULTI_SEMANTICS)
-# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
-#elif defined(DEBIAN)
-# define EVRCMP_DEPCMP EVRCMP_COMPARE
-#else
-# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
-#endif
-
-/* check if a package's nevr matches a dependency */
-/* semi-private, called from public pool_match_nevr */
-
-int
-pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
-{
-  Reldep *rd = GETRELDEP(pool, d);
-  Id name = rd->name;
-  Id evr = rd->evr;
-  int flags = rd->flags;
-
-  if (flags > 7)
-    {
-      switch (flags)
-       {
-       case REL_ARCH:
-         if (s->arch != evr)
-           {
-             if (evr != ARCH_SRC || s->arch != ARCH_NOSRC)
-               return 0;
-           }
-         return pool_match_nevr(pool, s, name);
-       case REL_OR:
-         if (pool_match_nevr(pool, s, name))
-           return 1;
-         return pool_match_nevr(pool, s, evr);
-       case REL_AND:
-       case REL_WITH:
-         if (!pool_match_nevr(pool, s, name))
-           return 0;
-         return pool_match_nevr(pool, s, evr);
-       case REL_MULTIARCH:
-         if (evr != ARCH_ANY)
-           return 0;
-         /* XXX : need to check for Multi-Arch: allowed! */
-         return pool_match_nevr(pool, s, name);
-       default:
-         return 0;
-       }
-    }
-  if (!pool_match_nevr(pool, s, name))
-    return 0;
-  if (evr == s->evr)
-    return (flags & REL_EQ) ? 1 : 0;
-  if (!flags)
-    return 0;
-  if (flags == 7)
-    return 1;
-  switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP))
-    {
-    case -2:
-      return 1;
-    case -1:
-      return (flags & REL_LT) ? 1 : 0;
-    case 0:
-      return (flags & REL_EQ) ? 1 : 0;
-    case 1:
-      return (flags & REL_GT) ? 1 : 0;
-    case 2:
-      return (flags & REL_EQ) ? 1 : 0;
-    default:
-      break;
-    }
-  return 0;
-}
-
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-/* forward declaration */
-static int pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr);
-#endif
-
-/* match (flags, evr) against provider (pflags, pevr) */
-static inline int
-pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
-{
-  if (!pflags || !flags || pflags >= 8 || flags >= 8)
-    return 0;
-  if (flags == 7 || pflags == 7)
-    return 1;          /* rel provides every version */
-  if ((pflags & flags & (REL_LT | REL_GT)) != 0)
-    return 1;          /* both rels show in the same direction */
-  if (pevr == evr)
-    return (flags & pflags & REL_EQ) ? 1 : 0;
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-  if (ISRELDEP(pevr))
-    {
-      Reldep *rd = GETRELDEP(pool, pevr);
-      if (rd->flags == REL_COMPAT)
-       return pool_match_flags_evr_rel_compat(pool, rd, flags, evr);
-    }
-#endif
-  switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP))
-    {
-    case -2:
-      return (pflags & REL_EQ) ? 1 : 0;
-    case -1:
-      return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0;
-    case 0:
-      return (flags & pflags & REL_EQ) ? 1 : 0;
-    case 1:
-      return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0;
-    case 2:
-      return (flags & REL_EQ) ? 1 : 0;
-    default:
-      break;
-    }
-  return 0;
-}
-
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-static int
-pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr)
-{
-  /* range->name is the actual version, range->evr the backwards compatibility
-     version. If flags are '>=' or '>', we match the compatibility version
-     as well, otherwise only the actual version. */
-  if (!(flags & REL_GT) || (flags & REL_LT))
-    return pool_match_flags_evr(pool, REL_EQ, range->name, flags, evr);
-  return pool_match_flags_evr(pool, REL_LT | REL_EQ, range->name, flags, evr) &&
-         pool_match_flags_evr(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr);
-}
-#endif
-
-/* public (i.e. not inlined) version of pool_match_flags_evr */
-int
-pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr)
-{
-  return pool_match_flags_evr(pool, pflags, pevr, flags, evr);
-}
-
-/* match two dependencies (d1 = provider) */
-
-int
-pool_match_dep(Pool *pool, Id d1, Id d2)
-{
-  Reldep *rd1, *rd2;
-
-  if (d1 == d2)
-    return 1;
-  if (!ISRELDEP(d1))
-    {
-      if (!ISRELDEP(d2))
-       return 0;
-      rd2 = GETRELDEP(pool, d2);
-      return pool_match_dep(pool, d1, rd2->name);
-    }
-  rd1 = GETRELDEP(pool, d1);
-  if (!ISRELDEP(d2))
-    {
-      return pool_match_dep(pool, rd1->name, d2);
-    }
-  rd2 = GETRELDEP(pool, d2);
-  /* first match name */
-  if (!pool_match_dep(pool, rd1->name, rd2->name))
-    return 0;
-  /* name matches, check flags and evr */
-  return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
-}
-
-Id
-pool_searchlazywhatprovidesq(Pool *pool, Id d)
-{
-  int start = 0;
-  int end = pool->lazywhatprovidesq.count;
-  Id *elements;
-  if (!end)
-    return 0;
-  elements = pool->lazywhatprovidesq.elements;
-  while (end - start > 16)
-    {
-      int mid = (start + end) / 2 & ~1;
-      if (elements[mid] == d)
-       return elements[mid + 1];
-      if (elements[mid] < d)
-       start = mid + 2;
-      else
-       end = mid;
-    }
-  for (; start < end; start += 2)
-    if (elements[start] == d)
-      return elements[start + 1];
-  return 0;
-}
-
-/*
- * addstdproviders
- *
- * lazy populating of the whatprovides array, non relation case
- */
-static Id
-pool_addstdproviders(Pool *pool, Id d)
-{
-  const char *str;
-  Queue q;
-  Id qbuf[16];
-  Dataiterator di;
-  Id oldoffset;
-
-  if (pool->addedfileprovides == 2)
-    {
-      pool->whatprovides[d] = 1;
-      return 1;
-    }
-  str =  pool->ss.stringspace + pool->ss.strings[d];
-  if (*str != '/')
-    {
-      pool->whatprovides[d] = 1;
-      return 1;
-    }
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
-  for (; dataiterator_step(&di); dataiterator_skip_solvable(&di))
-    {
-      Solvable *s = pool->solvables + di.solvid;
-      /* XXX: maybe should add a provides dependency to the solvables
-       * OTOH this is only needed for rel deps that filter the provides,
-       * and those should not use filelist entries */
-      if (s->repo->disabled)
-       continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       continue;
-      queue_push(&q, di.solvid);
-    }
-  dataiterator_free(&di);
-  oldoffset = pool_searchlazywhatprovidesq(pool, d);
-  if (!q.count)
-    pool->whatprovides[d] = oldoffset ? oldoffset : 1;
-  else
-    {
-      if (oldoffset)
-       {
-         Id *oo = pool->whatprovidesdata + oldoffset;
-         int i;
-         /* unify both queues. easy, as we know both are sorted */
-         for (i = 0; i < q.count; i++)
-           {
-             if (*oo > q.elements[i])
-               continue;
-             if (*oo < q.elements[i])
-               queue_insert(&q, i, *oo);
-             oo++;
-             if (!*oo)
-               break;
-           }
-         while (*oo)
-           queue_push(&q, *oo++);
-         if (q.count == oo - (pool->whatprovidesdata + oldoffset))
-           {
-             /* end result has same size as oldoffset -> no new entries */
-             queue_free(&q);
-             pool->whatprovides[d] = oldoffset;
-             return oldoffset;
-           }
-       }
-      pool->whatprovides[d] = pool_queuetowhatprovides(pool, &q);
-    }
-  queue_free(&q);
-  return pool->whatprovides[d];
-}
-
-
-static inline int
-pool_is_kind(Pool *pool, Id name, Id kind)
-{
-  const char *n;
-  if (!kind)
-    return 1;
-  n = pool_id2str(pool, name);
-  if (kind != 1)
-    {
-      const char *kn = pool_id2str(pool, kind);
-      int knl = strlen(kn);
-      return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
-    }
-  else
-    {
-      if (*n == ':')
-       return 1;
-      while(*n >= 'a' && *n <= 'z')
-       n++;
-      return *n == ':' ? 0 : 1;
-    }
-}
-
-/*
- * addrelproviders
- *
- * add packages fulfilling the relation to whatprovides array
- *
- * some words about REL_AND and REL_IF: we assume the best case
- * here, so that you get a "potential" result if you ask for a match.
- * E.g. if you ask for "whatrequires A" and package X contains
- * "Requires: A & B", you'll get "X" as an answer.
- */
-Id
-pool_addrelproviders(Pool *pool, Id d)
-{
-  Reldep *rd;
-  Reldep *prd;
-  Queue plist;
-  Id buf[16];
-  Id name, evr, flags;
-  Id pid, *pidp;
-  Id p, *pp;
-
-  if (!ISRELDEP(d))
-    return pool_addstdproviders(pool, d);
-  rd = GETRELDEP(pool, d);
-  name = rd->name;
-  evr = rd->evr;
-  flags = rd->flags;
-  d = GETRELID(d);
-  queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
-
-  if (flags >= 8)
-    {
-      /* special relation */
-      Id wp = 0;
-      Id *pp2, *pp3;
-
-      switch (flags)
-       {
-       case REL_WITH:
-         wp = pool_whatprovides(pool, name);
-         pp2 = pool_whatprovides_ptr(pool, evr);
-         pp = pool->whatprovidesdata + wp;
-         while ((p = *pp++) != 0)
-           {
-             for (pp3 = pp2; *pp3; pp3++)
-               if (*pp3 == p)
-                 break;
-             if (*pp3)
-               queue_push(&plist, p);  /* found it */
-             else
-               wp = 0;
-           }
-         break;
-
-       case REL_AND:
-       case REL_OR:
-       case REL_COND:
-         if (flags == REL_COND)
-           {
-             if (ISRELDEP(evr))
-               {
-                 Reldep *rd2 = GETRELDEP(pool, evr);
-                 evr = rd2->flags == REL_ELSE ? rd2->evr : 0;
-               }
-             else
-               evr = 0;        /* assume cond is true */
-           }
-         wp = pool_whatprovides(pool, name);
-         if (!pool->whatprovidesdata[wp])
-           wp = evr ? pool_whatprovides(pool, evr) : 1;
-         else if (evr)
-           {
-             /* sorted merge */
-             pp2 = pool_whatprovides_ptr(pool, evr);
-             pp = pool->whatprovidesdata + wp;
-             while (*pp && *pp2)
-               {
-                 if (*pp < *pp2)
-                   queue_push(&plist, *pp++);
-                 else
-                   {
-                     if (*pp == *pp2)
-                       pp++;
-                     queue_push(&plist, *pp2++);
-                   }
-               }
-             while (*pp)
-               queue_push(&plist, *pp++);
-             while (*pp2)
-               queue_push(&plist, *pp2++);
-             /* if the number of elements did not change, we can reuse wp */
-             if (pp - (pool->whatprovidesdata + wp) != plist.count)
-               wp = 0;
-           }
-         break;
-
-       case REL_NAMESPACE:
-         if (name == NAMESPACE_OTHERPROVIDERS)
-           {
-             wp = pool_whatprovides(pool, evr);
-             break;
-           }
-         if (pool->nscallback)
-           {
-             /* ask callback which packages provide the dependency
-              * 0:  none
-              * 1:  the system (aka SYSTEMSOLVABLE)
-              * >1: set of packages, stored as offset on whatprovidesdata
-              */
-             p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
-             if (p > 1)
-               wp = p;
-             if (p == 1)
-               queue_push(&plist, SYSTEMSOLVABLE);
-           }
-         break;
-       case REL_ARCH:
-         /* small hack: make it possible to match <pkg>.src
-          * we have to iterate over the solvables as src packages do not
-          * provide anything, thus they are not indexed in our
-          * whatprovides hash */
-         if (evr == ARCH_SRC || evr == ARCH_NOSRC)
-           {
-             Solvable *s;
-             for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
-               {
-                 if (!s->repo)
-                   continue;
-                 if (s->arch != evr && s->arch != ARCH_NOSRC)
-                   continue;
-                 if (pool_disabled_solvable(pool, s))
-                   continue;
-                 if (!name || pool_match_nevr(pool, s, name))
-                   queue_push(&plist, p);
-               }
-             break;
-           }
-         if (!name)
-           {
-             FOR_POOL_SOLVABLES(p)
-               {
-                 Solvable *s = pool->solvables + p;
-                 if (s->repo != pool->installed && !pool_installable(pool, s))
-                   continue;
-                 if (s->arch == evr)
-                   queue_push(&plist, p);
-               }
-             break;
-           }
-         wp = pool_whatprovides(pool, name);
-         pp = pool->whatprovidesdata + wp;
-         while ((p = *pp++) != 0)
-           {
-             Solvable *s = pool->solvables + p;
-             if (s->arch == evr)
-               queue_push(&plist, p);
-             else
-               wp = 0;
-           }
-         break;
-       case REL_MULTIARCH:
-         if (evr != ARCH_ANY)
-           break;
-         /* XXX : need to check for Multi-Arch: allowed! */
-         wp = pool_whatprovides(pool, name);
-         break;
-       case REL_KIND:
-         /* package kind filtering */
-         if (!name)
-           {
-             FOR_POOL_SOLVABLES(p)
-               {
-                 Solvable *s = pool->solvables + p;
-                 if (s->repo != pool->installed && !pool_installable(pool, s))
-                   continue;
-                 if (pool_is_kind(pool, s->name, evr))
-                   queue_push(&plist, p);
-               }
-             break;
-           }
-         wp = pool_whatprovides(pool, name);
-         pp = pool->whatprovidesdata + wp;
-         while ((p = *pp++) != 0)
-           {
-             Solvable *s = pool->solvables + p;
-             if (pool_is_kind(pool, s->name, evr))
-               queue_push(&plist, p);
-             else
-               wp = 0;
-           }
-         break;
-       case REL_FILECONFLICT:
-         pp = pool_whatprovides_ptr(pool, name);
-         while ((p = *pp++) != 0)
-           {
-             Id origd = MAKERELDEP(d);
-             Solvable *s = pool->solvables + p;
-             if (!s->provides)
-               continue;
-             pidp = s->repo->idarraydata + s->provides;
-             while ((pid = *pidp++) != 0)
-               if (pid == origd)
-                 break;
-             if (pid)
-               queue_push(&plist, p);
-           }
-         break;
-       default:
-         break;
-       }
-      if (wp)
-       {
-         /* we can reuse an existing entry */
-         queue_free(&plist);
-         pool->whatprovides_rel[d] = wp;
-         return wp;
-       }
-    }
-  else if (flags)
-    {
-      Id *ppaux = 0;
-      /* simple version comparison relation */
-#if 0
-      POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
-#endif
-      pp = pool_whatprovides_ptr(pool, name);
-      if (!ISRELDEP(name) && name < pool->whatprovidesauxoff)
-       ppaux = pool->whatprovidesaux[name] ? pool->whatprovidesauxdata + pool->whatprovidesaux[name] : 0;
-      while (ISRELDEP(name))
-       {
-          rd = GETRELDEP(pool, name);
-         name = rd->name;
-       }
-      while ((p = *pp++) != 0)
-       {
-         Solvable *s = pool->solvables + p;
-         if (ppaux)
-           {
-             pid = *ppaux++;
-             if (pid && pid != 1)
-               {
-#if 0
-                 POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: aux hit %d %s\n", p, pool_dep2str(pool, pid));
-#endif
-                 if (!ISRELDEP(pid))
-                   {
-                     if (pid != name)
-                       continue;               /* wrong provides name */
-                     if (pool->disttype == DISTTYPE_DEB)
-                       continue;               /* unversioned provides can never match versioned deps */
-                   }
-                 else
-                   {
-                     prd = GETRELDEP(pool, pid);
-                     if (prd->name != name)
-                       continue;               /* wrong provides name */
-                     /* right package, both deps are rels. check flags/evr */
-                     if (!pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
-                       continue;
-                   }
-                 queue_push(&plist, p);
-                 continue;
-               }
-           }
-         if (!s->provides)
-           {
-             /* no provides - check nevr */
-             if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
-               queue_push(&plist, p);
-             continue;
-           }
-         /* solvable p provides name in some rels */
-         pidp = s->repo->idarraydata + s->provides;
-         while ((pid = *pidp++) != 0)
-           {
-             if (!ISRELDEP(pid))
-               {
-                 if (pid != name)
-                   continue;           /* wrong provides name */
-                 if (pool->disttype == DISTTYPE_DEB)
-                   continue;           /* unversioned provides can never match versioned deps */
-                 break;
-               }
-             prd = GETRELDEP(pool, pid);
-             if (prd->name != name)
-               continue;               /* wrong provides name */
-             /* right package, both deps are rels. check flags/evr */
-             if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
-               break;  /* matches */
-           }
-         if (!pid)
-           continue;   /* none of the providers matched */
-         queue_push(&plist, p);
-       }
-      /* make our system solvable provide all unknown rpmlib() stuff */
-      if (plist.count == 0 && !strncmp(pool_id2str(pool, name), "rpmlib(", 7))
-       queue_push(&plist, SYSTEMSOLVABLE);
-    }
-  /* add providers to whatprovides */
-#if 0
-  POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
-#endif
-  pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
-  queue_free(&plist);
-
-  return pool->whatprovides_rel[d];
-}
-
-void
-pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
-{
-  int nrels = pool->nrels;
-  Id d;
-  Reldep *rd;
-
-  if (!pool->whatprovides_rel)
-    return;
-  for (d = 1, rd = pool->rels + d; d < nrels; d++, rd++)
-    {
-      if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
-       continue;
-      if (ns && rd->name != ns)
-       continue;
-      if (evr && rd->evr != evr)
-       continue;
-      pool->whatprovides_rel[d] = 0;
-    }
-}
-
-/* intersect dependencies in keyname with dep, return list of matching packages */
-void
-pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
-{
-  Id p;
-
-  queue_empty(q);
-  FOR_POOL_SOLVABLES(p)
-    {
-      Solvable *s = pool->solvables + p;
-      if (s->repo->disabled)
-       continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       continue;
-      if (solvable_matchesdep(s, keyname, dep, marker))
-       queue_push(q, p);
-    }
-}
-
-/*************************************************************************/
-
-void
-pool_debug(Pool *pool, int type, const char *format, ...)
-{
-  va_list args;
-  char buf[1024];
-
-  if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0)
-    {
-      if ((pool->debugmask & type) == 0)
-       return;
-    }
-  va_start(args, format);
-  if (!pool->debugcallback)
-    {
-      if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0 && !(pool->debugmask & SOLV_DEBUG_TO_STDERR))
-        vprintf(format, args);
-      else
-        vfprintf(stderr, format, args);
-      return;
-    }
-  vsnprintf(buf, sizeof(buf), format, args);
-  va_end(args);
-  pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
-}
-
-int
-pool_error(Pool *pool, int ret, const char *format, ...)
-{
-  va_list args;
-  int l;
-  va_start(args, format);
-  if (!pool->errstr)
-    {
-      pool->errstra = 1024;
-      pool->errstr = solv_malloc(pool->errstra);
-    }
-  if (!*format)
-    {
-      *pool->errstr = 0;
-      l = 0;
-    }
-  else
-    l = vsnprintf(pool->errstr, pool->errstra, format, args);
-  va_end(args);
-  if (l >= 0 && l + 1 > pool->errstra)
-    {
-      pool->errstra = l + 256;
-      pool->errstr = solv_realloc(pool->errstr, pool->errstra);
-      va_start(args, format);
-      l = vsnprintf(pool->errstr, pool->errstra, format, args);
-      va_end(args);
-    }
-  if (l < 0)
-    strcpy(pool->errstr, "unknown error");
-  if (pool->debugmask & SOLV_ERROR)
-    pool_debug(pool, SOLV_ERROR, "%s\n", pool->errstr);
-  return ret;
-}
-
-char *
-pool_errstr(Pool *pool)
-{
-  return pool->errstr ? pool->errstr : "no error";
-}
-
-void
-pool_setdebuglevel(Pool *pool, int level)
-{
-  int mask = SOLV_DEBUG_RESULT;
-  if (level > 0)
-    mask |= SOLV_DEBUG_STATS|SOLV_DEBUG_ANALYZE|SOLV_DEBUG_UNSOLVABLE|SOLV_DEBUG_SOLVER|SOLV_DEBUG_TRANSACTION|SOLV_ERROR;
-  if (level > 1)
-    mask |= SOLV_DEBUG_JOB|SOLV_DEBUG_SOLUTIONS|SOLV_DEBUG_POLICY;
-  if (level > 2)
-    mask |= SOLV_DEBUG_PROPAGATE;
-  if (level > 3)
-    mask |= SOLV_DEBUG_RULE_CREATION;
-  mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR;      /* keep bit */
-  pool->debugmask = mask;
-}
-
-void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata)
-{
-  pool->debugcallback = debugcallback;
-  pool->debugcallbackdata = debugcallbackdata;
-}
-
-void pool_setdebugmask(Pool *pool, int mask)
-{
-  pool->debugmask = mask;
-}
-
-void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata)
-{
-  pool->loadcallback = cb;
-  pool->loadcallbackdata = loadcbdata;
-}
-
-void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata)
-{
-  pool->nscallback = cb;
-  pool->nscallbackdata = nscbdata;
-}
-
-/*************************************************************************/
-
-struct searchfiles {
-  Id *ids;
-  int nfiles;
-  Map seen;
-};
-
-#define SEARCHFILES_BLOCK 127
-
-static void
-pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
-{
-  Id dep, sid;
-  const char *s;
-  struct searchfiles *csf;
-
-  while ((dep = *ida++) != 0)
-    {
-      csf = sf;
-      while (ISRELDEP(dep))
-       {
-         Reldep *rd;
-         sid = pool->ss.nstrings + GETRELID(dep);
-         if (MAPTST(&csf->seen, sid))
-           {
-             dep = 0;
-             break;
-           }
-         MAPSET(&csf->seen, sid);
-         rd = GETRELDEP(pool, dep);
-         if (rd->flags < 8)
-           dep = rd->name;
-         else if (rd->flags == REL_NAMESPACE)
-           {
-             if (rd->name == NAMESPACE_SPLITPROVIDES)
-               {
-                 csf = isf;
-                 if (!csf || MAPTST(&csf->seen, sid))
-                   {
-                     dep = 0;
-                     break;
-                   }
-                 MAPSET(&csf->seen, sid);
-               }
-             dep = rd->evr;
-           }
-         else if (rd->flags == REL_FILECONFLICT)
-           {
-             dep = 0;
-             break;
-           }
-         else
-           {
-             Id ids[2];
-             ids[0] = rd->name;
-             ids[1] = 0;
-             pool_addfileprovides_dep(pool, ids, csf, isf);
-             dep = rd->evr;
-           }
-       }
-      if (!dep)
-       continue;
-      if (MAPTST(&csf->seen, dep))
-       continue;
-      MAPSET(&csf->seen, dep);
-      s = pool_id2str(pool, dep);
-      if (*s != '/')
-       continue;
-      if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s))
-       continue;       /* skip non-standard locations csf == isf: installed case */
-      csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
-      csf->ids[csf->nfiles++] = dep;
-    }
-}
-
-struct addfileprovides_cbdata {
-  int nfiles;
-  Id *ids;
-  char **dirs;
-  char **names;
-
-  Id *dids;
-
-  Map providedids;
-
-  Map useddirs;
-};
-
-static int
-addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
-{
-  struct addfileprovides_cbdata *cbd = cbdata;
-  int i;
-
-  if (!cbd->useddirs.size)
-    {
-      map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
-      if (!cbd->dirs)
-       {
-         cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *));
-         cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *));
-         for (i = 0; i < cbd->nfiles; i++)
-           {
-             char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i]));
-             cbd->dirs[i] = s;
-             s = strrchr(s, '/');
-             *s = 0;
-             cbd->names[i] = s + 1;
-           }
-       }
-      for (i = 0; i < cbd->nfiles; i++)
-       {
-         Id did;
-         if (MAPTST(&cbd->providedids, cbd->ids[i]))
-           {
-             cbd->dids[i] = 0;
-             continue;
-           }
-         did = repodata_str2dir(data, cbd->dirs[i], 0);
-         cbd->dids[i] = did;
-         if (did)
-           MAPSET(&cbd->useddirs, did);
-       }
-      repodata_free_dircache(data);
-    }
-  if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
-    return 0;
-  for (i = 0; i < cbd->nfiles; i++)
-    if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str))
-      s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
-  return 0;
-}
-
-static void
-pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
-{
-  Id p;
-  Repodata *data;
-  Repo *repo;
-  Queue fileprovidesq;
-  int i, j, repoid, repodataid;
-  int provstart, provend;
-  Map donemap;
-  int ndone, incomplete;
-
-  if (!pool->urepos)
-    return;
-
-  cbd->nfiles = sf->nfiles;
-  cbd->ids = sf->ids;
-  cbd->dirs = 0;
-  cbd->names = 0;
-  cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
-  map_init(&cbd->providedids, pool->ss.nstrings);
-
-  repoid = 1;
-  repo = repoonly ? repoonly : pool->repos[repoid];
-  map_init(&donemap, pool->nsolvables);
-  queue_init(&fileprovidesq);
-  provstart = provend = 0;
-  for (;;)
-    {
-      if (!repo || repo->disabled)
-       {
-         if (repoonly || ++repoid == pool->nrepos)
-           break;
-         repo = pool->repos[repoid];
-         continue;
-       }
-      ndone = 0;
-      FOR_REPODATAS(repo, repodataid, data)
-       {
-         if (ndone >= repo->nsolvables)
-           break;
-
-         if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
-           {
-             map_empty(&cbd->providedids);
-             for (i = 0; i < fileprovidesq.count; i++)
-               MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
-             provstart = data->start;
-             provend = data->end;
-             for (i = 0; i < cbd->nfiles; i++)
-               if (!MAPTST(&cbd->providedids, cbd->ids[i]))
-                 break;
-             if (i == cbd->nfiles)
-               {
-                 /* great! no need to search files */
-                 for (p = data->start; p < data->end; p++)
-                   if (pool->solvables[p].repo == repo)
-                     {
-                       if (MAPTST(&donemap, p))
-                         continue;
-                       MAPSET(&donemap, p);
-                       ndone++;
-                     }
-                 continue;
-               }
-           }
-
-         if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
-           continue;
-
-         if (data->start < provstart || data->end > provend)
-           {
-             map_empty(&cbd->providedids);
-             provstart = provend = 0;
-           }
-
-         /* check if the data is incomplete */
-         incomplete = 0;
-         if (data->state == REPODATA_AVAILABLE)
-           {
-             for (j = 1; j < data->nkeys; j++)
-               if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-                 break;
-             if (j < data->nkeys)
-               {
-#if 0
-                 for (i = 0; i < cbd->nfiles; i++)
-                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
-                     printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i]));
-#endif
-                 for (i = 0; i < cbd->nfiles; i++)
-                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
-                     break;
-                 if (i < cbd->nfiles)
-                   incomplete = 1;
-               }
-           }
-
-         /* do the search */
-         map_init(&cbd->useddirs, 0);
-         for (p = data->start; p < data->end; p++)
-           if (pool->solvables[p].repo == repo)
-             {
-               if (MAPTST(&donemap, p))
-                 continue;
-               repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
-               if (!incomplete)
-                 {
-                   MAPSET(&donemap, p);
-                   ndone++;
-                 }
-             }
-         map_free(&cbd->useddirs);
-       }
-
-      if (repoonly || ++repoid == pool->nrepos)
-       break;
-      repo = pool->repos[repoid];
-    }
-  map_free(&donemap);
-  queue_free(&fileprovidesq);
-  map_free(&cbd->providedids);
-  if (cbd->dirs)
-    {
-      for (i = 0; i < cbd->nfiles; i++)
-       solv_free(cbd->dirs[i]);
-      cbd->dirs = solv_free(cbd->dirs);
-      cbd->names = solv_free(cbd->names);
-    }
-}
-
-void
-pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
-{
-  Solvable *s;
-  Repo *installed, *repo;
-  struct searchfiles sf, isf, *isfp;
-  struct addfileprovides_cbdata cbd;
-  int i;
-  unsigned int now;
-
-  installed = pool->installed;
-  now = solv_timems(0);
-  memset(&sf, 0, sizeof(sf));
-  map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
-  memset(&isf, 0, sizeof(isf));
-  map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
-  pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2;
-
-  if (idq)
-    queue_empty(idq);
-  if (idqinst)
-    queue_empty(idqinst);
-  isfp = installed ? &isf : 0;
-  for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
-    {
-      repo = s->repo;
-      if (!repo)
-       continue;
-      if (s->obsoletes)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
-      if (s->conflicts)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
-      if (s->requires)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
-      if (s->recommends)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
-      if (s->suggests)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
-      if (s->supplements)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
-      if (s->enhances)
-        pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
-    }
-  map_free(&sf.seen);
-  map_free(&isf.seen);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
-  cbd.dids = 0;
-  if (sf.nfiles)
-    {
-#if 0
-      for (i = 0; i < sf.nfiles; i++)
-       POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
-#endif
-      pool_addfileprovides_search(pool, &cbd, &sf, 0);
-      if (idq)
-        for (i = 0; i < sf.nfiles; i++)
-         queue_push(idq, sf.ids[i]);
-      if (idqinst)
-        for (i = 0; i < sf.nfiles; i++)
-         queue_push(idqinst, sf.ids[i]);
-      solv_free(sf.ids);
-    }
-  if (isf.nfiles)
-    {
-#if 0
-      for (i = 0; i < isf.nfiles; i++)
-       POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
-#endif
-      if (installed)
-        pool_addfileprovides_search(pool, &cbd, &isf, installed);
-      if (installed && idqinst)
-        for (i = 0; i < isf.nfiles; i++)
-         queue_pushunique(idqinst, isf.ids[i]);
-      solv_free(isf.ids);
-    }
-  solv_free(cbd.dids);
-  pool_freewhatprovides(pool); /* as we have added provides */
-  POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
-}
-
-void
-pool_addfileprovides(Pool *pool)
-{
-  pool_addfileprovides_queue(pool, 0, 0);
-}
-
-void
-pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata)
-{
-  if (p)
-    {
-      if (pool->solvables[p].repo)
-        repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
-      return;
-    }
-  /* FIXME: obey callback return value! */
-  for (p = 1; p < pool->nsolvables; p++)
-    if (pool->solvables[p].repo)
-      repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
-}
-
-void
-pool_clear_pos(Pool *pool)
-{
-  memset(&pool->pos, 0, sizeof(pool->pos));
-}
-
-
-void
-pool_set_languages(Pool *pool, const char **languages, int nlanguages)
-{
-  int i;
-
-  pool->languagecache = solv_free(pool->languagecache);
-  pool->languagecacheother = 0;
-  for (i = 0; i < pool->nlanguages; i++)
-    free((char *)pool->languages[i]);
-  pool->languages = solv_free((void *)pool->languages);
-  pool->nlanguages = nlanguages;
-  if (!nlanguages)
-    return;
-  pool->languages = solv_calloc(nlanguages, sizeof(const char **));
-  for (i = 0; i < pool->nlanguages; i++)
-    pool->languages[i] = solv_strdup(languages[i]);
-}
-
-Id
-pool_id2langid(Pool *pool, Id id, const char *lang, int create)
-{
-  const char *n;
-  char buf[256], *p;
-  int l;
-
-  if (!lang || !*lang)
-    return id;
-  n = pool_id2str(pool, id);
-  l = strlen(n) + strlen(lang) + 2;
-  if (l > sizeof(buf))
-    p = solv_malloc(strlen(n) + strlen(lang) + 2);
-  else
-    p = buf;
-  sprintf(p, "%s:%s", n, lang);
-  id = pool_str2id(pool, p, create);
-  if (p != buf)
-    free(p);
-  return id;
-}
-
-char *
-pool_alloctmpspace(Pool *pool, int len)
-{
-  int n = pool->tmpspace.n;
-  if (!len)
-    return 0;
-  if (len > pool->tmpspace.len[n])
-    {
-      pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
-      pool->tmpspace.len[n] = len + 32;
-    }
-  pool->tmpspace.n = (n + 1) % POOL_TMPSPACEBUF;
-  return pool->tmpspace.buf[n];
-}
-
-static char *
-pool_alloctmpspace_free(Pool *pool, const char *space, int len)
-{
-  if (space)
-    {
-      int n, oldn;
-      n = oldn = pool->tmpspace.n;
-      for (;;)
-       {
-         if (!n--)
-           n = POOL_TMPSPACEBUF - 1;
-         if (n == oldn)
-           break;
-         if (pool->tmpspace.buf[n] != space)
-           continue;
-         if (len > pool->tmpspace.len[n])
-           {
-             pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
-             pool->tmpspace.len[n] = len + 32;
-           }
-          return pool->tmpspace.buf[n];
-       }
-    }
-  return 0;
-}
-
-void
-pool_freetmpspace(Pool *pool, const char *space)
-{
-  int n = pool->tmpspace.n;
-  if (!space)
-    return;
-  n = (n + (POOL_TMPSPACEBUF - 1)) % POOL_TMPSPACEBUF;
-  if (pool->tmpspace.buf[n] == space)
-    pool->tmpspace.n = n;
-}
-
-char *
-pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
-{
-  int l1, l2, l3;
-  char *s, *str;
-  l1 = str1 ? strlen(str1) : 0;
-  l2 = str2 ? strlen(str2) : 0;
-  l3 = str3 ? strlen(str3) : 0;
-  s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
-  if (l1)
-    {
-      strcpy(s, str1);
-      s += l1;
-    }
-  if (l2)
-    {
-      strcpy(s, str2);
-      s += l2;
-    }
-  if (l3)
-    {
-      strcpy(s, str3);
-      s += l3;
-    }
-  *s = 0;
-  return str;
-}
-
-char *
-pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3)
-{
-  int l1, l2, l3;
-  char *s, *str;
-
-  l1 = str1 ? strlen(str1) : 0;
-  l2 = str2 ? strlen(str2) : 0;
-  l3 = str3 ? strlen(str3) : 0;
-  str = pool_alloctmpspace_free(pool, str1, l1 + l2 + l3 + 1);
-  if (str)
-    str1 = str;
-  else
-    str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
-  s = str;
-  if (l1)
-    {
-      if (s != str1)
-        strcpy(s, str1);
-      s += l1;
-    }
-  if (l2)
-    {
-      strcpy(s, str2);
-      s += l2;
-    }
-  if (l3)
-    {
-      strcpy(s, str3);
-      s += l3;
-    }
-  *s = 0;
-  return str;
-}
-
-const char *
-pool_bin2hex(Pool *pool, const unsigned char *buf, int len)
-{
-  char *s;
-  if (!len)
-    return "";
-  s = pool_alloctmpspace(pool, 2 * len + 1);
-  solv_bin2hex(buf, len, s);
-  return s;
-}
-
-/*******************************************************************/
-
-struct mptree {
-  Id sibling;
-  Id child;
-  const char *comp;
-  int compl;
-  Id mountpoint;
-};
-
-struct ducbdata {
-  DUChanges *mps;
-  struct mptree *mptree;
-  int addsub;
-  int hasdu;
-
-  Id *dirmap;
-  int nmap;
-  Repodata *olddata;
-};
-
-
-static int
-solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
-{
-  struct ducbdata *cbd = cbdata;
-  Id mp;
-
-  if (data != cbd->olddata)
-    {
-      Id dn, mp, comp, *dirmap, *dirs;
-      int i, compl;
-      const char *compstr;
-      struct mptree *mptree;
-
-      /* create map from dir to mptree */
-      cbd->dirmap = solv_free(cbd->dirmap);
-      cbd->nmap = 0;
-      dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id));
-      mptree = cbd->mptree;
-      mp = 0;
-      for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
-       {
-         comp = *dirs++;
-         if (comp <= 0)
-           {
-             mp = dirmap[-comp];
-             continue;
-           }
-         if (mp < 0)
-           {
-             /* unconnected */
-             dirmap[dn] = mp;
-             continue;
-           }
-         if (!mptree[mp].child)
-           {
-             dirmap[dn] = -mp;
-             continue;
-           }
-         if (data->localpool)
-           compstr = stringpool_id2str(&data->spool, comp);
-         else
-           compstr = pool_id2str(data->repo->pool, comp);
-         compl = strlen(compstr);
-         for (i = mptree[mp].child; i; i = mptree[i].sibling)
-           if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
-             break;
-         dirmap[dn] = i ? i : -mp;
-       }
-      /* change dirmap to point to mountpoint instead of mptree */
-      for (dn = 0; dn < data->dirpool.ndirs; dn++)
-       {
-         mp = dirmap[dn];
-         dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
-       }
-      cbd->dirmap = dirmap;
-      cbd->nmap = data->dirpool.ndirs;
-      cbd->olddata = data;
-    }
-  cbd->hasdu = 1;
-  if (value->id < 0 || value->id >= cbd->nmap)
-    return 0;
-  mp = cbd->dirmap[value->id];
-  if (mp < 0)
-    return 0;
-  if (cbd->addsub > 0)
-    {
-      cbd->mps[mp].kbytes += value->num;
-      cbd->mps[mp].files += value->num2;
-    }
-  else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD))
-    {
-      cbd->mps[mp].kbytes -= value->num;
-      cbd->mps[mp].files -= value->num2;
-    }
-  return 0;
-}
-
-static void
-propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
-{
-  int i;
-  if (mptree[pos].mountpoint == -1)
-    mptree[pos].mountpoint = mountpoint;
-  else
-    mountpoint = mptree[pos].mountpoint;
-  for (i = mptree[pos].child; i; i = mptree[i].sibling)
-    propagate_mountpoints(mptree, i, mountpoint);
-}
-
-#define MPTREE_BLOCK 15
-
-static struct mptree *
-create_mptree(DUChanges *mps, int nmps)
-{
-  int i, nmptree;
-  struct mptree *mptree;
-  int pos, compl;
-  int mp;
-  const char *p, *path, *compstr;
-
-  mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
-
-  /* our root node */
-  mptree[0].sibling = 0;
-  mptree[0].child = 0;
-  mptree[0].comp = 0;
-  mptree[0].compl = 0;
-  mptree[0].mountpoint = -1;
-  nmptree = 1;
-
-  /* create component tree */
-  for (mp = 0; mp < nmps; mp++)
-    {
-      mps[mp].kbytes = 0;
-      mps[mp].files = 0;
-      pos = 0;
-      path = mps[mp].path;
-      while(*path == '/')
-       path++;
-      while (*path)
-       {
-         if ((p = strchr(path, '/')) == 0)
-           {
-             compstr = path;
-             compl = strlen(compstr);
-             path += compl;
-           }
-         else
-           {
-             compstr = path;
-             compl = p - path;
-             path = p + 1;
-             while(*path == '/')
-               path++;
-           }
-          for (i = mptree[pos].child; i; i = mptree[i].sibling)
-           if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
-             break;
-         if (!i)
-           {
-             /* create new node */
-             mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
-             i = nmptree++;
-             mptree[i].sibling = mptree[pos].child;
-             mptree[i].child = 0;
-             mptree[i].comp = compstr;
-             mptree[i].compl = compl;
-             mptree[i].mountpoint = -1;
-             mptree[pos].child = i;
-           }
-         pos = i;
-       }
-      mptree[pos].mountpoint = mp;
-    }
-
-  propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
-
-#if 0
-  for (i = 0; i < nmptree; i++)
-    {
-      printf("#%d sibling: %d\n", i, mptree[i].sibling);
-      printf("#%d child: %d\n", i, mptree[i].child);
-      printf("#%d comp: %s\n", i, mptree[i].comp);
-      printf("#%d compl: %d\n", i, mptree[i].compl);
-      printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
-    }
-#endif
-
-  return mptree;
-}
-
-void
-pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
-{
-  struct mptree *mptree;
-  struct ducbdata cbd;
-  Solvable *s;
-  int i, sp;
-  Map ignoredu;
-  Repo *oldinstalled = pool->installed;
-  int haveonlyadd = 0;
-
-  map_init(&ignoredu, 0);
-  mptree = create_mptree(mps, nmps);
-
-  for (i = 0; i < nmps; i++)
-    if ((mps[i].flags & DUCHANGES_ONLYADD) != 0)
-      haveonlyadd = 1;
-  cbd.mps = mps;
-  cbd.dirmap = 0;
-  cbd.nmap = 0;
-  cbd.olddata = 0;
-  cbd.mptree = mptree;
-  cbd.addsub = 1;
-  for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
-    {
-      if (!s->repo || (oldinstalled && s->repo == oldinstalled))
-       continue;
-      if (!MAPTST(installedmap, sp))
-       continue;
-      cbd.hasdu = 0;
-      repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
-      if (!cbd.hasdu && oldinstalled)
-       {
-         Id op, opp;
-         int didonlyadd = 0;
-         /* no du data available, ignore data of all installed solvables we obsolete */
-         if (!ignoredu.size)
-           map_grow(&ignoredu, oldinstalled->end - oldinstalled->start);
-         FOR_PROVIDES(op, opp, s->name)
-           {
-             Solvable *s2 = pool->solvables + op;
-             if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
-               continue;
-             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
-               continue;
-             if (op >= oldinstalled->start && op < oldinstalled->end)
-               {
-                 MAPSET(&ignoredu, op - oldinstalled->start);
-                 if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
-                   {
-                     repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
-                     cbd.addsub = -1;
-                     repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
-                     cbd.addsub = 1;
-                     didonlyadd = 1;
-                   }
-               }
-           }
-         if (s->obsoletes)
-           {
-             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-             while ((obs = *obsp++) != 0)
-               FOR_PROVIDES(op, opp, obs)
-                 {
-                   Solvable *s2 = pool->solvables + op;
-                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
-                     continue;
-                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
-                     continue;
-                   if (op >= oldinstalled->start && op < oldinstalled->end)
-                     {
-                       MAPSET(&ignoredu, op - oldinstalled->start);
-                       if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
-                         {
-                           repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
-                           cbd.addsub = -1;
-                           repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
-                           cbd.addsub = 1;
-                           didonlyadd = 1;
-                         }
-                     }
-                 }
-           }
-       }
-    }
-  cbd.addsub = -1;
-  if (oldinstalled)
-    {
-      /* assumes we allways have du data for installed solvables */
-      FOR_REPO_SOLVABLES(oldinstalled, sp, s)
-       {
-         if (MAPTST(installedmap, sp))
-           continue;
-         if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
-           continue;
-         repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
-       }
-    }
-  map_free(&ignoredu);
-  solv_free(cbd.dirmap);
-  solv_free(mptree);
-}
-
-int
-pool_calc_installsizechange(Pool *pool, Map *installedmap)
-{
-  Id sp;
-  Solvable *s;
-  int change = 0;
-  Repo *oldinstalled = pool->installed;
-
-  for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
-    {
-      if (!s->repo || (oldinstalled && s->repo == oldinstalled))
-       continue;
-      if (!MAPTST(installedmap, sp))
-       continue;
-      change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
-    }
-  if (oldinstalled)
-    {
-      FOR_REPO_SOLVABLES(oldinstalled, sp, s)
-       {
-         if (MAPTST(installedmap, sp))
-           continue;
-         change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
-       }
-    }
-  return change;
-}
-
-/* map:
- *  1: installed
- *  2: conflicts with installed
- *  8: interesting (only true if installed)
- * 16: undecided
- */
-
-static inline Id dep2name(Pool *pool, Id dep)
-{
-  while (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      dep = rd->name;
-    }
-  return dep;
-}
-
-static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con)
-{
-  Id p, pp;
-  Solvable *sn = pool->solvables + n;
-
-  FOR_PROVIDES(p, pp, sn->name)
-    {
-      Solvable *s = pool->solvables + p;
-      if (s->name != sn->name || s->arch != sn->arch)
-        continue;
-      if ((map[p] & 9) != 9)
-        continue;
-      if (pool_match_nevr(pool, pool->solvables + p, con))
-       continue;
-      return 1;                /* found installed package that doesn't conflict */
-    }
-  return 0;
-}
-
-static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap)
-{
-  Id p, pp;
-  int r = 0;
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (p == SYSTEMSOLVABLE)
-        return 1;      /* always boring, as never constraining */
-      if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
-       continue;
-      if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
-       if (providedbyinstalled_multiversion(pool, map, p, dep))
-         continue;
-      if ((map[p] & 9) == 9)
-       return 9;
-      r |= map[p] & 17;
-    }
-  return r;
-}
-
-/*
- * pool_trivial_installable - calculate if a set of solvables is
- * trivial installable without any other installs/deinstalls of
- * packages not belonging to the set.
- *
- * the state is returned in the result queue:
- * 1:  solvable is installable without any other package changes
- * 0:  solvable is not installable
- * -1: solvable is installable, but doesn't constrain any installed packages
- */
-
-void
-pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap)
-{
-  int i, r, m, did;
-  Id p, *dp, con, *conp, req, *reqp;
-  unsigned char *map;
-  Solvable *s;
-
-  map = solv_calloc(pool->nsolvables, 1);
-  for (p = 1; p < pool->nsolvables; p++)
-    {
-      if (!MAPTST(installedmap, p))
-       continue;
-      map[p] |= 9;
-      s = pool->solvables + p;
-      if (!s->conflicts)
-       continue;
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-       {
-         dp = pool_whatprovides_ptr(pool, con);
-         for (; *dp; dp++)
-           map[p] |= 2;        /* XXX: self conflict ? */
-       }
-    }
-  for (i = 0; i < pkgs->count; i++)
-    map[pkgs->elements[i]] = 16;
-
-  for (i = 0, did = 0; did < pkgs->count; i++, did++)
-    {
-      if (i == pkgs->count)
-       i = 0;
-      p = pkgs->elements[i];
-      if ((map[p] & 16) == 0)
-       continue;
-      if ((map[p] & 2) != 0)
-       {
-         map[p] = 2;
-         continue;
-       }
-      s = pool->solvables + p;
-      m = 1;
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)
-           {
-             if (req == SOLVABLE_PREREQMARKER)
-               continue;
-             r = providedbyinstalled(pool, map, req, 0, 0);
-             if (!r)
-               {
-                 /* decided and miss */
-                 map[p] = 2;
-                 did = 0;
-                 break;
-               }
-             if (r == 16)
-               break;  /* undecided */
-             m |= r;   /* 1 | 9 | 17 */
-           }
-         if (req)
-           continue;
-         if ((m & 9) == 9)
-           m = 9;
-       }
-      if (s->conflicts)
-       {
-         int ispatch = 0;      /* see solver.c patch handling */
-
-         if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
-           ispatch = 1;
-         conp = s->repo->idarraydata + s->conflicts;
-         while ((con = *conp++) != 0)
-           {
-             if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0)
-               {
-                 map[p] = 2;
-                 did = 0;
-                 break;
-               }
-             if ((m == 1 || m == 17) && ISRELDEP(con))
-               {
-                 con = dep2name(pool, con);
-                 if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0)
-                   m = 9;
-               }
-           }
-         if (con)
-           continue;   /* found a conflict */
-       }
-#if 0
-      if (s->repo && s->repo != oldinstalled)
-       {
-         Id p2, obs, *obsp, *pp;
-         Solvable *s2;
-         if (s->obsoletes)
-           {
-             obsp = s->repo->idarraydata + s->obsoletes;
-             while ((obs = *obsp++) != 0)
-               {
-                 if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
-                   {
-                     map[p] = 2;
-                     break;
-                   }
-               }
-             if (obs)
-               continue;
-           }
-         FOR_PROVIDES(p2, pp, s->name)
-           {
-             s2 = pool->solvables + p2;
-             if (s2->name == s->name && (map[p2] & 1) != 0)
-               {
-                 map[p] = 2;
-                 break;
-               }
-           }
-         if (p2)
-           continue;
-       }
-#endif
-      if (m != map[p])
-       {
-         map[p] = m;
-         did = 0;
-       }
-    }
-  queue_free(res);
-  queue_init_clone(res, pkgs);
-  for (i = 0; i < pkgs->count; i++)
-    {
-      m = map[pkgs->elements[i]];
-      if ((m & 9) == 9)
-       r = 1;
-      else if (m & 1)
-       r = -1;
-      else
-       r = 0;
-      res->elements[i] = r;
-    }
-  free(map);
-}
-
-void
-pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
-{
-  pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0);
-}
-
-const char *
-pool_lookup_str(Pool *pool, Id entry, Id keyname)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_str(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
-  if (entry <= 0)
-    return 0;
-  return solvable_lookup_str(pool->solvables + entry, keyname);
-}
-
-Id
-pool_lookup_id(Pool *pool, Id entry, Id keyname)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_id(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
-  if (entry <= 0)
-    return 0;
-  return solvable_lookup_id(pool->solvables + entry, keyname);
-}
-
-unsigned long long
-pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_num(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, notfound);
-  if (entry <= 0)
-    return notfound;
-  return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
-}
-
-int
-pool_lookup_void(Pool *pool, Id entry, Id keyname)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_void(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
-  if (entry <= 0)
-    return 0;
-  return solvable_lookup_void(pool->solvables + entry, keyname);
-}
-
-const unsigned char *
-pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_bin_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
-  if (entry <= 0)
-    return 0;
-  return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
-}
-
-const char *
-pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
-  if (entry <= 0)
-    return 0;
-  return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
-}
-
-int
-pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q)
-{
-  if (entry == SOLVID_POS && pool->pos.repo)
-    return repo_lookup_idarray(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, q);
-  if (entry <= 0)
-    return 0;
-  return solvable_lookup_idarray(pool->solvables + entry, keyname, q);
-}
-
-const char *
-pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp)
-{
-  const char *loc;
-  if (medianrp)
-    *medianrp = 0;
-  if (entry != SOLVID_POS)
-    return 0;
-  loc = pool_lookup_str(pool, entry, DELTA_LOCATION_DIR);
-  loc = pool_tmpjoin(pool, loc, loc ? "/" : 0, pool_lookup_str(pool, entry, DELTA_LOCATION_NAME));
-  loc = pool_tmpappend(pool, loc, "-", pool_lookup_str(pool, entry, DELTA_LOCATION_EVR));
-  loc = pool_tmpappend(pool, loc, ".", pool_lookup_str(pool, entry, DELTA_LOCATION_SUFFIX));
-  return loc;
-}
-
-static void
-add_new_provider(Pool *pool, Id id, Id p)
-{
-  Queue q;
-  Id *pp;
-
-  while (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      id = rd->name;
-    }
-
-  queue_init(&q);
-  for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++)
-    {
-      if (*pp == p)
-       {
-         queue_free(&q);
-         return;
-       }
-      if (*pp > p)
-       {
-         queue_push(&q, p);
-         p = 0;
-       }
-      queue_push(&q, *pp);
-    }
-  if (p)
-    queue_push(&q, p);
-  pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
-  if (id < pool->whatprovidesauxoff)
-    pool->whatprovidesaux[id] = 0;     /* sorry */
-  queue_free(&q);
-}
-
-void
-pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
-{
-  int hadhashes = pool->relhashtbl ? 1 : 0;
-  Solvable *s;
-  Id fn, p, q, md5;
-  Id id;
-  int i;
-
-  if (!conflicts->count)
-    return;
-  for (i = 0; i < conflicts->count; i += 6)
-    {
-      fn = conflicts->elements[i];
-      p = conflicts->elements[i + 1];
-      md5 = conflicts->elements[i + 2];
-      q = conflicts->elements[i + 4];
-      id = pool_rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
-      s = pool->solvables + p;
-      if (!s->repo)
-       continue;
-      s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
-      if (pool->whatprovides)
-       add_new_provider(pool, fn, p);
-      if (pool->whatprovides_rel)
-       pool->whatprovides_rel[GETRELID(id)] = 0;       /* clear cache */
-      s = pool->solvables + q;
-      if (!s->repo)
-       continue;
-      s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
-    }
-  if (!hadhashes)
-    pool_freeidhashes(pool);
-}
-
-char *
-pool_prepend_rootdir(Pool *pool, const char *path)
-{
-  if (!path)
-    return 0;
-  if (!pool->rootdir)
-    return solv_strdup(path);
-  return solv_dupjoin(pool->rootdir, "/", *path == '/' ? path + 1 : path);
-}
-
-const char *
-pool_prepend_rootdir_tmp(Pool *pool, const char *path)
-{
-  if (!path)
-    return 0;
-  if (!pool->rootdir)
-    return path;
-  return pool_tmpjoin(pool, pool->rootdir, "/", *path == '/' ? path + 1 : path);
-}
-
-void
-pool_set_rootdir(Pool *pool, const char *rootdir)
-{
-  solv_free(pool->rootdir);
-  pool->rootdir = solv_strdup(rootdir);
-}
-
-const char *
-pool_get_rootdir(Pool *pool)
-{
-  return pool->rootdir;
-}
-
-/* only used in libzypp */
-void
-pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *))
-{
-  pool->custom_vendorcheck = vendorcheck;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/src/pool.h b/libsolv-0.6.15/src/pool.h
deleted file mode 100644 (file)
index 4a2089d..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * pool.h
- *
- */
-
-#ifndef LIBSOLV_POOL_H
-#define LIBSOLV_POOL_H
-
-#include <stdio.h>
-
-#include "solvversion.h"
-#include "pooltypes.h"
-#include "poolid.h"
-#include "solvable.h"
-#include "bitmap.h"
-#include "queue.h"
-#include "strpool.h"
-
-/* well known ids */
-#include "knownid.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* well known solvable */
-#define SYSTEMSOLVABLE         1
-
-
-/* how many strings to maintain (round robin) */
-#define POOL_TMPSPACEBUF 16
-
-/*----------------------------------------------- */
-
-struct _Repo;
-struct _Repodata;
-struct _Repokey;
-struct _KeyValue;
-
-typedef struct _Datapos {
-  struct _Repo *repo;
-  Id solvid;
-  Id repodataid;
-  Id schema;
-  Id dp;
-} Datapos;
-
-struct _Pool_tmpspace {
-  char *buf[POOL_TMPSPACEBUF];
-  int   len[POOL_TMPSPACEBUF];
-  int   n;
-};
-
-struct _Pool {
-  void *appdata;               /* application private pointer */
-
-  struct _Stringpool ss;
-
-  Reldep *rels;                        /* table of rels: Id -> Reldep */
-  int nrels;                   /* number of unique rels */
-
-  struct _Repo **repos;
-  int nrepos;                  /* repos allocated */
-  int urepos;                  /* repos in use */
-
-  struct _Repo *installed;     /* packages considered installed */
-
-  Solvable *solvables;
-  int nsolvables;              /* solvables allocated */
-
-  const char **languages;
-  int nlanguages;
-
-  /* package manager type, deb/rpm */
-  int disttype;
-
-  Id *id2arch;                 /* map arch ids to scores */
-  unsigned char *id2color;     /* map arch ids to colors */
-  Id lastarch;                 /* last valid entry in id2arch/id2color */
-
-  Queue vendormap;             /* map vendor to vendorclasses mask */
-  const char **vendorclasses;  /* vendor equivalence classes */
-
-  /* providers data, as two-step indirect list
-   * whatprovides[Id] -> Offset into whatprovidesdata for name
-   * whatprovidesdata[Offset] -> 0-terminated list of solvables providing Id
-   */
-  Offset *whatprovides;                /* Offset to providers of a specific name, Id -> Offset  */
-  Offset *whatprovides_rel;    /* Offset to providers of a specific relation, Id -> Offset  */
-
-  Id *whatprovidesdata;                /* Ids of solvable providing Id */
-  Offset whatprovidesdataoff;  /* next free slot within whatprovidesdata */
-  int whatprovidesdataleft;    /* number of 'free slots' within whatprovidesdata */
-
-  /* If nonzero, then consider only the solvables with Ids set in this
-     bitmap for solving.  If zero, consider all solvables.  */
-  Map *considered;
-
-  /* callback for REL_NAMESPACE dependencies handled by the application  */
-  Id (*nscallback)(struct _Pool *, void *data, Id name, Id evr);
-  void *nscallbackdata;
-
-  /* debug mask and callback */
-  int  debugmask;
-  void (*debugcallback)(struct _Pool *, void *data, int type, const char *str);
-  void *debugcallbackdata;
-
-  /* load callback */
-  int (*loadcallback)(struct _Pool *, struct _Repodata *, void *);
-  void *loadcallbackdata;
-
-  /* search position */
-  Datapos pos;
-
-  Queue pooljobs;              /* fixed jobs, like USERINSTALLED/MULTIVERSION */
-
-#ifdef LIBSOLV_INTERNAL
-  /* flags to tell the library how the installed package manager works */
-  int promoteepoch;            /* true: missing epoch is replaced by epoch of dependency   */
-  int havedistepoch;           /* true: thr release part in the evr may contain a distepoch suffix */
-  int obsoleteusesprovides;    /* true: obsoletes are matched against provides, not names */
-  int implicitobsoleteusesprovides;    /* true: implicit obsoletes due to same name are matched against provides, not names */
-  int obsoleteusescolors;      /* true: obsoletes check arch color */
-  int implicitobsoleteusescolors;      /* true: implicit obsoletes check arch color */
-  int noinstalledobsoletes;    /* true: ignore obsoletes of installed packages */
-  int forbidselfconflicts;     /* true: packages which conflict with itself are not installable */
-  int noobsoletesmultiversion; /* true: obsoletes are ignored for multiversion installs */
-
-  Id noarchid;                 /* ARCH_NOARCH, ARCH_ALL, ARCH_ANY, ... */
-
-  /* hash for rel unification */
-  Hashtable relhashtbl;                /* hashtable: (name,evr,op)Hash -> Id */
-  Hashval relhashmask;
-
-  Id *languagecache;
-  int languagecacheother;
-
-  /* our tmp space string space */
-  struct _Pool_tmpspace tmpspace;
-
-  char *errstr;                        /* last error string */
-  int errstra;                 /* allocated space for errstr */
-
-  char *rootdir;
-
-  int (*custom_vendorcheck)(struct _Pool *, Solvable *, Solvable *);
-
-  int addfileprovidesfiltered; /* 1: only use filtered file list for addfileprovides */
-  int addedfileprovides;       /* true: application called addfileprovides */
-  Queue lazywhatprovidesq;     /* queue to store old whatprovides offsets */
-  int nowhatprovidesaux;       /* don't allocate and use the whatprovides aux helper */
-  Offset *whatprovidesaux;
-  Offset whatprovidesauxoff;
-  Id *whatprovidesauxdata;
-  Offset whatprovidesauxdataoff;
-
-#endif
-};
-
-#define DISTTYPE_RPM   0
-#define DISTTYPE_DEB   1
-#define DISTTYPE_ARCH   2
-#define DISTTYPE_HAIKU  3
-
-#define SOLV_FATAL                     (1<<0)
-#define SOLV_ERROR                     (1<<1)
-#define SOLV_WARN                      (1<<2)
-#define SOLV_DEBUG_STATS               (1<<3)
-#define SOLV_DEBUG_RULE_CREATION       (1<<4)
-#define SOLV_DEBUG_PROPAGATE           (1<<5)
-#define SOLV_DEBUG_ANALYZE             (1<<6)
-#define SOLV_DEBUG_UNSOLVABLE          (1<<7)
-#define SOLV_DEBUG_SOLUTIONS           (1<<8)
-#define SOLV_DEBUG_POLICY              (1<<9)
-#define SOLV_DEBUG_RESULT              (1<<10)
-#define SOLV_DEBUG_JOB                 (1<<11)
-#define SOLV_DEBUG_SOLVER              (1<<12)
-#define SOLV_DEBUG_TRANSACTION         (1<<13)
-
-#define SOLV_DEBUG_TO_STDERR           (1<<30)
-
-#define POOL_FLAG_PROMOTEEPOCH                         1
-#define POOL_FLAG_FORBIDSELFCONFLICTS                  2
-#define POOL_FLAG_OBSOLETEUSESPROVIDES                 3
-#define POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES         4
-#define POOL_FLAG_OBSOLETEUSESCOLORS                   5
-#define POOL_FLAG_NOINSTALLEDOBSOLETES                 6
-#define POOL_FLAG_HAVEDISTEPOCH                                7
-#define POOL_FLAG_NOOBSOLETESMULTIVERSION              8
-#define POOL_FLAG_ADDFILEPROVIDESFILTERED              9
-#define POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS           10
-#define POOL_FLAG_NOWHATPROVIDESAUX                    11
-
-/* ----------------------------------------------- */
-
-
-/* mark dependencies with relation by setting bit31 */
-
-#define MAKERELDEP(id) ((id) | 0x80000000)
-#define ISRELDEP(id) (((id) & 0x80000000) != 0)
-#define GETRELID(id) ((id) ^ 0x80000000)                               /* returns Id */
-#define GETRELDEP(pool, id) ((pool)->rels + ((id) ^ 0x80000000))       /* returns Reldep* */
-
-#define REL_GT         1
-#define REL_EQ         2
-#define REL_LT         4
-
-#define REL_AND                16
-#define REL_OR         17
-#define REL_WITH       18
-#define REL_NAMESPACE  19
-#define REL_ARCH       20
-#define REL_FILECONFLICT       21
-#define REL_COND       22
-#define REL_COMPAT     23
-#define REL_KIND       24      /* for filters only */
-#define REL_MULTIARCH  25      /* debian multiarch annotation */
-#define REL_ELSE       26      /* only as evr part of REL_COND */
-
-#if !defined(__GNUC__) && !defined(__attribute__)
-# define __attribute__(x)
-#endif
-
-extern Pool *pool_create(void);
-extern void pool_free(Pool *pool);
-extern void pool_freeallrepos(Pool *pool, int reuseids);
-
-extern void pool_setdebuglevel(Pool *pool, int level);
-extern int  pool_setdisttype(Pool *pool, int disttype);
-extern int  pool_set_flag(Pool *pool, int flag, int value);
-extern int  pool_get_flag(Pool *pool, int flag);
-
-extern void pool_debug(Pool *pool, int type, const char *format, ...) __attribute__((format(printf, 3, 4)));
-extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata);
-extern void pool_setdebugmask(Pool *pool, int mask);
-extern void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata);
-extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata);
-extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
-
-extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct _Pool *, Solvable *, Solvable *));
-
-
-extern char *pool_alloctmpspace(Pool *pool, int len);
-extern void  pool_freetmpspace(Pool *pool, const char *space);
-extern char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3);
-extern char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
-extern const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
-
-extern void pool_set_installed(Pool *pool, struct _Repo *repo);
-
-extern int  pool_error(Pool *pool, int ret, const char *format, ...) __attribute__((format(printf, 3, 4)));
-extern char *pool_errstr(Pool *pool);
-
-extern void pool_set_rootdir(Pool *pool, const char *rootdir);
-extern const char *pool_get_rootdir(Pool *pool);
-extern char *pool_prepend_rootdir(Pool *pool, const char *dir);
-extern const char *pool_prepend_rootdir_tmp(Pool *pool, const char *dir);
-
-/**
- * Solvable management
- */
-extern Id pool_add_solvable(Pool *pool);
-extern Id pool_add_solvable_block(Pool *pool, int count);
-
-extern void pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids);
-static inline Solvable *pool_id2solvable(const Pool *pool, Id p)
-{
-  return pool->solvables + p;
-}
-
-extern const char *pool_solvable2str(Pool *pool, Solvable *s);
-static inline const char *pool_solvid2str(Pool *pool, Id p)
-{
-  return pool_solvable2str(pool, pool->solvables + p);
-}
-
-void pool_set_languages(Pool *pool, const char **languages, int nlanguages);
-Id pool_id2langid(Pool *pool, Id id, const char *lang, int create);
-
-int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap);
-int solvable_trivial_installable_repo(Solvable *s, struct _Repo *installed, Map *multiversionmap);
-int solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap);
-int solvable_is_irrelevant_patch(Solvable *s, Map *installedmap);
-
-void pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap);
-
-int pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr);
-int pool_match_dep(Pool *pool, Id d1, Id d2);
-
-/* semi private, used in pool_match_nevr */
-int pool_match_nevr_rel(Pool *pool, Solvable *s, Id d);
-
-static inline int pool_match_nevr(Pool *pool, Solvable *s, Id d)
-{
-  if (!ISRELDEP(d))
-    return d == s->name;
-  else
-    return pool_match_nevr_rel(pool, s, d);
-}
-
-
-/**
- * Prepares a pool for solving
- */
-extern void pool_createwhatprovides(Pool *pool);
-extern void pool_addfileprovides(Pool *pool);
-extern void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst);
-extern void pool_freewhatprovides(Pool *pool);
-extern Id pool_queuetowhatprovides(Pool *pool, Queue *q);
-extern Id pool_ids2whatprovides(Pool *pool, Id *ids, int count);
-extern Id pool_searchlazywhatprovidesq(Pool *pool, Id d);
-
-extern Id pool_addrelproviders(Pool *pool, Id d);
-
-static inline Id pool_whatprovides(Pool *pool, Id d)
-{
-  if (!ISRELDEP(d))
-    {
-      if (pool->whatprovides[d])
-       return pool->whatprovides[d];
-    }
-  else
-    {
-      Id v = GETRELID(d);
-      if (pool->whatprovides_rel[v])
-       return pool->whatprovides_rel[v];
-    }
-  return pool_addrelproviders(pool, d);
-}
-
-static inline Id *pool_whatprovides_ptr(Pool *pool, Id d)
-{
-  Id off = pool_whatprovides(pool, d);
-  return pool->whatprovidesdata + off;
-}
-
-void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
-
-/* search the pool. the following filters are available:
- *   p     - search just this solvable
- *   key   - search only this key
- *   match - key must match this string
- */
-void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata);
-
-void pool_clear_pos(Pool *pool);
-
-
-#define DUCHANGES_ONLYADD      1
-
-typedef struct _DUChanges {
-  const char *path;
-  int kbytes;
-  int files;
-  int flags;
-} DUChanges;
-
-void pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps);
-int pool_calc_installsizechange(Pool *pool, Map *installedmap);
-void pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res);
-void pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap);
-
-const char *pool_lookup_str(Pool *pool, Id entry, Id keyname);
-Id pool_lookup_id(Pool *pool, Id entry, Id keyname);
-unsigned long long pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound);
-int pool_lookup_void(Pool *pool, Id entry, Id keyname);
-const unsigned char *pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep);
-int pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q);
-const char *pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep);
-const char *pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp);
-
-void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts);
-
-
-
-/* loop over all providers of d */
-#define FOR_PROVIDES(v, vp, d)                                                 \
-  for (vp = pool_whatprovides(pool, d) ; (v = pool->whatprovidesdata[vp++]) != 0; )
-
-/* loop over all repositories */
-#define FOR_REPOS(repoid, r)                                           \
-  for (repoid = 1; repoid < pool->nrepos; repoid++)                    \
-    if ((r = pool->repos[repoid]) == 0)                                        \
-      continue;                                                                \
-    else
-
-#define FOR_POOL_SOLVABLES(p)                                          \
-  for (p = 2; p < pool->nsolvables; p++)                               \
-    if (pool->solvables[p].repo == 0)                                  \
-      continue;                                                                \
-    else
-
-#ifdef ENABLE_COMPS
-#define ISCONDDEP(id) (ISRELDEP(id) && (GETRELDEP(pool, id))->flags == REL_COND)
-#define MODIFYCONDDEP(id, tst) do { Reldep *condrd = GETRELDEP(pool, id); Id condp, condpp; FOR_PROVIDES(condrd->evr, condp, condpp) if (tst) break; id = condp ? condrd->name : 0;} while(0)
-#endif
-
-#define POOL_DEBUG(type, ...) do {if ((pool->debugmask & (type)) != 0) pool_debug(pool, (type), __VA_ARGS__);} while (0)
-#define IF_POOLDEBUG(type) if ((pool->debugmask & (type)) != 0)
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* LIBSOLV_POOL_H */
diff --git a/libsolv-0.6.15/src/poolarch.c b/libsolv-0.6.15/src/poolarch.c
deleted file mode 100644 (file)
index 788646b..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * poolarch.c
- *
- * create architecture policies
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "pool.h"
-#include "poolid.h"
-#include "poolarch.h"
-#include "util.h"
-
-static const char *archpolicies[] = {
-#if defined(FEDORA) || defined(MAGEIA)
-  "x86_64",    "x86_64:athlon:i686:i586:i486:i386",
-#else
-  "x86_64",    "x86_64:i686:i586:i486:i386",
-#endif
-  "i686",      "i686:i586:i486:i386",
-  "i586",      "i586:i486:i386",
-  "i486",      "i486:i386",
-  "i386",      "i386",
-  "s390x",     "s390x:s390",
-  "s390",      "s390",
-  "ppc64le",    "ppc64le",
-  "ppc64",     "ppc64:ppc",
-  "ppc",       "ppc",
-  "ppc64p7",   "ppc64p7:ppc64:ppc",
-  "ia64",      "ia64:i686:i586:i486:i386",
-  "aarch64",   "aarch64",
-  "armv6hl",   "armv6hl",
-  "armv7hnl",  "armv7hnl:armv7hl:armv6hl",
-  "armv7hl",   "armv7hl:armv6hl",
-  "armv7l",    "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
-  "armv6l",    "armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
-  "armv5tejl", "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
-  "armv5tel",  "armv5tel:armv5l:armv4tl:armv4l:armv3l",
-  "armv5tl",   "armv5l:armv4tl:armv4l:armv3l",
-  "armv5l",    "armv5l:armv4tl:armv4l:armv3l",
-  "armv4tl",   "armv4tl:armv4l:armv3l",
-  "armv4l",    "armv4l:armv3l",
-  "armv3l",    "armv3l",
-  "sh3",       "sh3",
-  "sh4",       "sh4",
-  "sh4a",      "sh4a:sh4",
-  "sparc64v",  "sparc64v:sparc64:sparcv9v:sparcv9:sparcv8:sparc",
-  "sparc64",   "sparc64:sparcv9:sparcv8:sparc",
-  "sparcv9v",  "sparcv9v:sparcv9:sparcv8:sparc",
-  "sparcv9",   "sparcv9:sparcv8:sparc",
-  "sparcv8",   "sparcv8:sparc",
-  "sparc",     "sparc",
-  "mips",      "mips",
-  "mipsel",    "mipsel",
-  "mips64",    "mips64",
-  "mips64el",  "mips64el",
-  "m68k",      "m68k",
-#if defined(FEDORA) || defined(MAGEIA)
-  "ia32e",     "ia32e:x86_64:athlon:i686:i586:i486:i386",
-  "athlon",    "athlon:i686:i586:i486:i386",
-  "amd64",     "amd64:x86_64:athlon:i686:i586:i486:i386",
-  "geode",     "geode:i586:i486:i386",
-  "ppc64iseries", "ppc64iseries:ppc64:ppc",
-  "ppc64pseries", "ppc64pseries:ppc64:ppc",
-#endif
-  0
-};
-
-void
-pool_setarch(Pool *pool, const char *arch)
-{
-  if (arch)
-    {
-      int i;
-
-      /* convert arch to known policy */
-      for (i = 0; archpolicies[i]; i += 2)
-       if (!strcmp(archpolicies[i], arch))
-         break;
-      if (archpolicies[i])
-       arch = archpolicies[i + 1];
-      else
-       arch = "";
-    }
-  pool_setarchpolicy(pool, arch);
-}
-
-/*
- * we support three relations:
- *
- * a = b   both architectures a and b are treated as equivalent
- * a > b   a is considered a "better" architecture, the solver
- *         should change from a to b, but must not change from b to a
- * a : b   a is considered a "better" architecture, the solver
- *         must not change the architecture from a to b or b to a
- */
-void
-pool_setarchpolicy(Pool *pool, const char *arch)
-{
-  unsigned int score = 0x10001;
-  size_t l;
-  char d;
-  Id *id2arch;
-  Id id, lastarch;
-
-  pool->id2arch = solv_free(pool->id2arch);
-  pool->id2color = solv_free(pool->id2color);
-  if (!arch)
-    {
-      pool->lastarch = 0;
-      return;
-    }
-  id = pool->noarchid;
-  lastarch = id + 255;
-  id2arch = solv_calloc(lastarch + 1, sizeof(Id));
-  id2arch[id] = 1;     /* the "noarch" class */
-
-  d = 0;
-  while (*arch)
-    {
-      l = strcspn(arch, ":=>");
-      if (l)
-       {
-         id = pool_strn2id(pool, arch, l, 1);
-         if (id > lastarch)
-           {
-             id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id));
-             memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id));
-             lastarch = id + 255;
-           }
-         if (id2arch[id] == 0)
-           {
-             if (d == ':')
-               score += 0x10000;
-             else if (d == '>')
-               score += 0x00001;
-             id2arch[id] = score;
-           }
-       }
-      arch += l;
-      if ((d = *arch++) == 0)
-       break;
-    }
-  pool->id2arch = id2arch;
-  pool->lastarch = lastarch;
-}
-
-unsigned char
-pool_arch2color_slow(Pool *pool, Id arch)
-{
-  const char *s;
-  unsigned char color;
-
-  if (arch > pool->lastarch)
-    return ARCHCOLOR_ALL;
-  if (!pool->id2color)
-    pool->id2color = solv_calloc(pool->lastarch + 1, 1);
-  s = pool_id2str(pool, arch);
-  if (arch == ARCH_NOARCH || arch == ARCH_ALL || arch == ARCH_ANY)
-    color = ARCHCOLOR_ALL;
-  else if (!strcmp(s, "s390x") || strstr(s, "64"))
-    color = ARCHCOLOR_64;
-  else
-    color = ARCHCOLOR_32;
-  pool->id2color[arch] = color;
-  return color;
-}
-
diff --git a/libsolv-0.6.15/src/poolarch.h b/libsolv-0.6.15/src/poolarch.h
deleted file mode 100644 (file)
index 3fe5f02..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef LIBSOLV_POOLARCH_H
-#define LIBSOLV_POOLARCH_H
-
-#include "pool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void pool_setarch(Pool *, const char *);
-extern void pool_setarchpolicy(Pool *, const char *);
-extern unsigned char pool_arch2color_slow(Pool *pool, Id arch);
-
-#define ARCHCOLOR_32    1
-#define ARCHCOLOR_64    2
-#define ARCHCOLOR_ALL   255
-
-static inline unsigned char pool_arch2color(Pool *pool, Id arch)
-{
-  if (arch > pool->lastarch)
-    return ARCHCOLOR_ALL;
-  if (pool->id2color && pool->id2color[arch])
-    return pool->id2color[arch];
-  return pool_arch2color_slow(pool, arch);
-}
-
-static inline int pool_colormatch(Pool *pool, Solvable *s1, Solvable *s2)
-{
-  if (s1->arch == s2->arch)
-    return 1;
-  if ((pool_arch2color(pool, s1->arch) & pool_arch2color(pool, s2->arch)) != 0)
-    return 1;
-  return 0;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_POOLARCH_H */
diff --git a/libsolv-0.6.15/src/poolid.c b/libsolv-0.6.15/src/poolid.c
deleted file mode 100644 (file)
index 2138c42..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * poolid.c
- *
- * Id management
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "pool.h"
-#include "poolid.h"
-#include "poolid_private.h"
-#include "util.h"
-
-
-/* intern string into pool, return id */
-
-Id
-pool_str2id(Pool *pool, const char *str, int create)
-{
-  int oldnstrings = pool->ss.nstrings;
-  Id id = stringpool_str2id(&pool->ss, str, create);
-  if (create && pool->whatprovides && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0)
-    {
-      /* grow whatprovides array */
-      pool->whatprovides = solv_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset));
-      memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
-    }
-  return id;
-}
-
-Id
-pool_strn2id(Pool *pool, const char *str, unsigned int len, int create)
-{
-  int oldnstrings = pool->ss.nstrings;
-  Id id = stringpool_strn2id(&pool->ss, str, len, create);
-  if (create && pool->whatprovides && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0)
-    {
-      /* grow whatprovides array */
-      pool->whatprovides = solv_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset));
-      memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
-    }
-  return id;
-}
-
-Id
-pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create)
-{
-  Hashval h, hh, hashmask;
-  int i;
-  Id id;
-  Hashtable hashtbl;
-  Reldep *ran;
-
-  hashmask = pool->relhashmask;
-  hashtbl = pool->relhashtbl;
-  ran = pool->rels;
-
-  /* extend hashtable if needed */
-  if ((Hashval)pool->nrels * 2 > hashmask)
-    {
-      solv_free(pool->relhashtbl);
-      pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK);
-      pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
-      /* rehash all rels into new hashtable */
-      for (i = 1; i < pool->nrels; i++)
-       {
-         h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
-         hh = HASHCHAIN_START;
-         while (hashtbl[h])
-           h = HASHCHAIN_NEXT(h, hh, hashmask);
-         hashtbl[h] = i;
-       }
-    }
-
-  /* compute hash and check for match */
-  h = relhash(name, evr, flags) & hashmask;
-  hh = HASHCHAIN_START;
-  while ((id = hashtbl[h]) != 0)
-    {
-      if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
-       break;
-      h = HASHCHAIN_NEXT(h, hh, hashmask);
-    }
-  if (id)
-    return MAKERELDEP(id);
-
-  if (!create)
-    return ID_NULL;
-
-  id = pool->nrels++;
-  /* extend rel space if needed */
-  pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK);
-  hashtbl[h] = id;
-  ran = pool->rels + id;
-  ran->name = name;
-  ran->evr = evr;
-  ran->flags = flags;
-
-  /* extend whatprovides_rel if needed */
-  if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0)
-    {
-      pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset));
-      memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
-    }
-  return MAKERELDEP(id);
-}
-
-
-/* Id -> String
- * for rels (returns name only) and strings
- */
-const char *
-pool_id2str(const Pool *pool, Id id)
-{
-  while (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      id = rd->name;
-    }
-  return pool->ss.stringspace + pool->ss.strings[id];
-}
-
-static const char *rels[] = {
-  " ! ",
-  " > ",
-  " = ",
-  " >= ",
-  " < ",
-  " <> ",
-  " <= ",
-  " <=> "
-};
-
-
-/* get operator for RelId */
-const char *
-pool_id2rel(const Pool *pool, Id id)
-{
-  Reldep *rd;
-  if (!ISRELDEP(id))
-    return "";
-  rd = GETRELDEP(pool, id);
-  switch (rd->flags)
-    {
-    /* debian special cases < and > */
-    /* haiku special cases <> (maybe we should use != for the others as well */
-    case 0: case REL_EQ: case REL_GT | REL_EQ:
-    case REL_LT | REL_EQ: case REL_LT | REL_EQ | REL_GT:
-#if !defined(DEBIAN) && !defined(MULTI_SEMANTICS)
-    case REL_LT: case REL_GT:
-#endif
-#if !defined(HAIKU) && !defined(MULTI_SEMANTICS)
-    case REL_LT | REL_GT:
-#endif
-      return rels[rd->flags];
-#if defined(DEBIAN) || defined(MULTI_SEMANTICS)
-    case REL_GT:
-      return pool->disttype == DISTTYPE_DEB ? " >> " : rels[rd->flags];
-    case REL_LT:
-      return pool->disttype == DISTTYPE_DEB ? " << " : rels[rd->flags];
-#endif
-#if defined(HAIKU) || defined(MULTI_SEMANTICS)
-    case REL_LT | REL_GT:
-      return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags];
-#endif
-    case REL_AND:
-      return " & ";
-    case REL_OR:
-      return " | ";
-    case REL_WITH:
-      return " + ";
-    case REL_NAMESPACE:
-      return " NAMESPACE ";    /* actually not used in dep2str */
-    case REL_ARCH:
-      return ".";
-    case REL_MULTIARCH:
-      return ":";
-    case REL_FILECONFLICT:
-      return " FILECONFLICT ";
-    case REL_COND:
-      return " IF ";
-    case REL_COMPAT:
-      return " compat >= ";
-    case REL_KIND:
-      return " KIND ";
-    case REL_ELSE:
-      return " ELSE ";
-    default:
-      break;
-    }
-  return " ??? ";
-}
-
-
-/* get e:v.r for Id */
-const char *
-pool_id2evr(const Pool *pool, Id id)
-{
-  Reldep *rd;
-  if (!ISRELDEP(id))
-    return "";
-  rd = GETRELDEP(pool, id);
-  if (ISRELDEP(rd->evr))
-    return "(REL)";
-  return pool->ss.stringspace + pool->ss.strings[rd->evr];
-}
-
-static int
-dep2strlen(const Pool *pool, Id id)
-{
-  int l = 0;
-
-  while (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      /* add 2 for parens */
-      l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id));
-      id = rd->evr;
-    }
-  return l + strlen(pool->ss.stringspace + pool->ss.strings[id]);
-}
-
-static void
-dep2strcpy(const Pool *pool, char *p, Id id, int oldrel)
-{
-  while (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH)
-       if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH)
-         if (oldrel != rd->flags)
-           {
-             *p++ = '(';
-             dep2strcpy(pool, p, rd->name, rd->flags);
-             p += strlen(p);
-             strcpy(p, pool_id2rel(pool, id));
-             p += strlen(p);
-             dep2strcpy(pool, p, rd->evr, rd->flags);
-             strcat(p, ")");
-             return;
-           }
-      if (rd->flags == REL_KIND)
-       {
-         dep2strcpy(pool, p, rd->evr, rd->flags);
-         p += strlen(p);
-         *p++ = ':';
-         id = rd->name;
-         oldrel = rd->flags;
-         continue;
-       }
-      dep2strcpy(pool, p, rd->name, rd->flags);
-      p += strlen(p);
-      if (rd->flags == REL_NAMESPACE)
-       {
-         *p++ = '(';
-         dep2strcpy(pool, p, rd->evr, rd->flags);
-         strcat(p, ")");
-         return;
-       }
-      if (rd->flags == REL_FILECONFLICT)
-       {
-         *p = 0;
-         return;
-       }
-      strcpy(p, pool_id2rel(pool, id));
-      p += strlen(p);
-      id = rd->evr;
-      oldrel = rd->flags;
-    }
-  strcpy(p, pool->ss.stringspace + pool->ss.strings[id]);
-}
-
-const char *
-pool_dep2str(Pool *pool, Id id)
-{
-  char *p;
-  if (!ISRELDEP(id))
-    return pool->ss.stringspace + pool->ss.strings[id];
-  p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1);
-  dep2strcpy(pool, p, id, 0);
-  return p;
-}
-
-void
-pool_shrink_strings(Pool *pool)
-{
-  stringpool_shrink(&pool->ss);
-}
-
-void
-pool_shrink_rels(Pool *pool)
-{
-  pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
-}
-
-/* free all hash tables */
-void
-pool_freeidhashes(Pool *pool)
-{
-  stringpool_freehash(&pool->ss);
-  pool->relhashtbl = solv_free(pool->relhashtbl);
-  pool->relhashmask = 0;
-}
-
-/* EOF */
diff --git a/libsolv-0.6.15/src/poolid.h b/libsolv-0.6.15/src/poolid.h
deleted file mode 100644 (file)
index 2363595..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * poolid.h
- *
- */
-
-#ifndef LIBSOLV_POOLID_H
-#define LIBSOLV_POOLID_H
-
-#include "pooltypes.h"
-#include "hash.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*-----------------------------------------------
- * Ids with relation
- */
-
-typedef struct _Reldep {
-  Id name;             /* "package" */
-  Id evr;              /* "0:42-3" */
-  int flags;           /* operation/relation, see REL_x in pool.h */
-} Reldep;
-
-extern Id pool_str2id(Pool *pool, const char *, int);
-extern Id pool_strn2id(Pool *pool, const char *, unsigned int, int);
-extern Id pool_rel2id(Pool *pool, Id, Id, int, int);
-extern const char *pool_id2str(const Pool *pool, Id);
-extern const char *pool_id2rel(const Pool *pool, Id);
-extern const char *pool_id2evr(const Pool *pool, Id);
-extern const char *pool_dep2str(Pool *pool, Id); /* might alloc tmpspace */
-
-extern void pool_shrink_strings(Pool *pool);
-extern void pool_shrink_rels(Pool *pool);
-extern void pool_freeidhashes(Pool *pool);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_POOLID_H */
diff --git a/libsolv-0.6.15/src/poolid_private.h b/libsolv-0.6.15/src/poolid_private.h
deleted file mode 100644 (file)
index 43ff50d..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * poolid_private.h
- *
- */
-
-#ifndef LIBSOLV_POOLID_PRIVATE_H
-#define LIBSOLV_POOLID_PRIVATE_H
-
-/* the size of all buffers is incremented in blocks
- * these are the block values (increment values) for the
- * rel hashtable
- */
-#define REL_BLOCK              1023    /* hashtable for relations */
-#define WHATPROVIDES_BLOCK     1023
-
-#endif /* LIBSOLV_POOLID_PRIVATE_H */
diff --git a/libsolv-0.6.15/src/pooltypes.h b/libsolv-0.6.15/src/pooltypes.h
deleted file mode 100644 (file)
index 64a3b87..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * pooltypes.h
- *
- */
-
-#ifndef LIBSOLV_POOLTYPES_H
-#define LIBSOLV_POOLTYPES_H
-
-/* format version number for .solv files */
-#define SOLV_VERSION_0 0
-#define SOLV_VERSION_1 1
-#define SOLV_VERSION_2 2
-#define SOLV_VERSION_3 3
-#define SOLV_VERSION_4 4
-#define SOLV_VERSION_5 5
-#define SOLV_VERSION_6 6
-#define SOLV_VERSION_7 7
-#define SOLV_VERSION_8 8
-
-#define SOLV_FLAG_PREFIX_POOL 4
-#define SOLV_FLAG_SIZE_BYTES  8
-
-struct _Stringpool;
-typedef struct _Stringpool Stringpool;
-
-struct _Pool;
-typedef struct _Pool Pool;
-
-/* identifier for string values */
-typedef int Id;                /* must be signed!, since negative Id is used in solver rules to denote negation */
-
-/* offset value, e.g. used to 'point' into the stringspace */
-typedef unsigned int Offset;
-
-#endif /* LIBSOLV_POOLTYPES_H */
diff --git a/libsolv-0.6.15/src/poolvendor.c b/libsolv-0.6.15/src/poolvendor.c
deleted file mode 100644 (file)
index ec25f9d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* we need FNM_CASEFOLD */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <fnmatch.h>
-
-#include "pool.h"
-#include "poolid.h"
-#include "poolvendor.h"
-#include "util.h"
-
-/*
- *  const char *vendorsclasses[] = {
- *    "!openSUSE Build Service*",
- *    "SUSE*",
- *    "openSUSE*",
- *    "SGI*",
- *    "Novell*",
- *    "Silicon Graphics*",
- *    "Jpackage Project*",
- *    "ATI Technologies Inc.*",
- *    "Nvidia*",
- *    0,
- *    0,
- *  };
- */
-
-/* allows for 32 different vendor classes */
-
-Id pool_vendor2mask(Pool *pool, Id vendor)
-{
-  const char *vstr;
-  int i;
-  Id mask, m;
-  const char **v, *vs;
-
-  if (vendor == 0 || !pool->vendorclasses)
-    return 0;
-  for (i = 0; i < pool->vendormap.count; i += 2)
-    if (pool->vendormap.elements[i] == vendor)
-      return pool->vendormap.elements[i + 1];
-  vstr = pool_id2str(pool, vendor);
-  m = 1;
-  mask = 0;
-  for (v = pool->vendorclasses; ; v++)
-    {
-      vs = *v;
-      if (vs == 0)     /* end of block? */
-       {
-         v++;
-         if (*v == 0)
-           break;
-         if (m == (1 << 31))
-           break;      /* sorry, out of bits */
-         m <<= 1;      /* next vendor equivalence class */
-       }
-      if (fnmatch(*vs == '!' ? vs + 1 : vs, vstr, FNM_CASEFOLD) == 0)
-       {
-         if (*vs != '!')
-           mask |= m;
-         while (v[1])  /* forward to next block */
-           v++;
-       }
-    }
-  queue_push(&pool->vendormap, vendor);
-  queue_push(&pool->vendormap, mask);
-  return mask;
-}
-
-void
-pool_setvendorclasses(Pool *pool, const char **vendorclasses)
-{
-  int i;
-  const char **v;
-
-  if (pool->vendorclasses)
-    {
-      for (v = pool->vendorclasses; v[0] || v[1]; v++)
-       solv_free((void *)*v);
-      pool->vendorclasses = solv_free((void *)pool->vendorclasses);
-    }
-  if (!vendorclasses || !vendorclasses[0])
-    return;
-  for (v = vendorclasses; v[0] || v[1]; v++)
-    ;
-  pool->vendorclasses = solv_calloc(v - vendorclasses + 2, sizeof(const char *));
-  for (v = vendorclasses, i = 0; v[0] || v[1]; v++, i++)
-    pool->vendorclasses[i] = *v ? solv_strdup(*v) : 0;
-  pool->vendorclasses[i++] = 0;
-  pool->vendorclasses[i] = 0;
-  queue_empty(&pool->vendormap);
-}
-
-void
-pool_addvendorclass(Pool *pool, const char **vendorclass)
-{
-  int i, j;
-
-  if (!vendorclass || !vendorclass[0])
-    return;
-  for (j = 1; vendorclass[j]; j++)
-    ;
-  i = 0;
-  if (pool->vendorclasses)
-    {
-      for (i = 0; pool->vendorclasses[i] || pool->vendorclasses[i + 1]; i++)
-       ;
-      if (i)
-        i++;
-    }
-  pool->vendorclasses = solv_realloc2((void *)pool->vendorclasses, i + j + 2, sizeof(const char *));
-  for (j = 0; vendorclass[j]; j++)
-    pool->vendorclasses[i++] = solv_strdup(vendorclass[j]);
-  pool->vendorclasses[i++] = 0;
-  pool->vendorclasses[i] = 0;
-  queue_empty(&pool->vendormap);
-}
diff --git a/libsolv-0.6.15/src/poolvendor.h b/libsolv-0.6.15/src/poolvendor.h
deleted file mode 100644 (file)
index 873e090..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef LIBSOLV_POOLVENDOR_H
-#define LIBSOLV_POOLVENDOR_H
-
-#include "pool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-Id pool_vendor2mask(Pool *pool, Id vendor);
-void pool_setvendorclasses(Pool *pool, const char **vendorclasses);
-void pool_addvendorclass(Pool *pool, const char **vendorclass);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_POOLVENDOR_H */
diff --git a/libsolv-0.6.15/src/problems.c b/libsolv-0.6.15/src/problems.c
deleted file mode 100644 (file)
index b57d980..0000000
+++ /dev/null
@@ -1,1220 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * problems.c
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "solver.h"
-#include "solver_private.h"
-#include "bitmap.h"
-#include "pool.h"
-#include "util.h"
-#include "evr.h"
-#include "solverdebug.h"
-
-
-/**********************************************************************************/
-
-/* a problem is an item on the solver's problem list. It can either be >0, in that
- * case it is a update/infarch/dup rule, or it can be <0, which makes it refer to a job
- * consisting of multiple job rules.
- */
-
-void
-solver_disableproblem(Solver *solv, Id v)
-{
-  Rule *r;
-  int i;
-  Id *jp;
-
-  if (v > 0)
-    {
-      if (v >= solv->infarchrules && v < solv->infarchrules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_disablerule(solv, solv->rules + v);
-         return;
-       }
-      if (v >= solv->duprules && v < solv->duprules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_disablerule(solv, solv->rules + v);
-         return;
-       }
-      solver_disablerule(solv, solv->rules + v);
-#if 0
-      /* XXX: doesn't work */
-      if (v >= solv->updaterules && v < solv->updaterules_end)
-       {
-         /* enable feature rule if we disabled the update rule */
-         r = solv->rules + (v - solv->updaterules + solv->featurerules);
-         if (r->p)
-           solver_enablerule(solv, r);
-       }
-#endif
-      return;
-    }
-  v = -(v + 1);
-  jp = solv->ruletojob.elements;
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
-    if (*jp == v)
-      solver_disablerule(solv, r);
-}
-
-/*-------------------------------------------------------------------
- * enableproblem
- */
-
-void
-solver_enableproblem(Solver *solv, Id v)
-{
-  Rule *r;
-  int i;
-  Id *jp;
-
-  if (v > 0)
-    {
-      if (v >= solv->infarchrules && v < solv->infarchrules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_enablerule(solv, solv->rules + v);
-         return;
-       }
-      if (v >= solv->duprules && v < solv->duprules_end)
-       {
-         Pool *pool = solv->pool;
-         Id name = pool->solvables[-solv->rules[v].p].name;
-         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
-           v--;
-         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
-           solver_enablerule(solv, solv->rules + v);
-         return;
-       }
-      if (v >= solv->featurerules && v < solv->featurerules_end)
-       {
-         /* do not enable feature rule if update rule is enabled */
-         r = solv->rules + (v - solv->featurerules + solv->updaterules);
-         if (r->d >= 0)
-           return;
-       }
-      solver_enablerule(solv, solv->rules + v);
-      if (v >= solv->updaterules && v < solv->updaterules_end)
-       {
-         /* disable feature rule when enabling update rule */
-         r = solv->rules + (v - solv->updaterules + solv->featurerules);
-         if (r->p)
-           solver_disablerule(solv, r);
-       }
-      return;
-    }
-  v = -(v + 1);
-  jp = solv->ruletojob.elements;
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
-    if (*jp == v)
-      solver_enablerule(solv, r);
-}
-
-
-/*-------------------------------------------------------------------
- * enable weak rules
- *
- * Reenable all disabled weak rules (marked in weakrulemap)
- *
- */
-
-static void
-enableweakrules(Solver *solv)
-{
-  int i;
-  Rule *r;
-
-  if (!solv->weakrulemap.size)
-    return;
-  for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
-    {
-      if (r->d >= 0) /* already enabled? */
-       continue;
-      if (!MAPTST(&solv->weakrulemap, i))
-       continue;
-      solver_enablerule(solv, r);
-    }
-  /* make sure broken orphan rules stay disabled */
-  if (solv->brokenorphanrules)
-    for (i = 0; i < solv->brokenorphanrules->count; i++)
-      solver_disablerule(solv, solv->rules + solv->brokenorphanrules->elements[i]);
-}
-
-
-/*-------------------------------------------------------------------
- *
- * refine_suggestion
- *
- * at this point, all rules that led to conflicts are disabled.
- * we re-enable all rules of a problem set but rule "sug", then
- * continue to disable more rules until there as again a solution.
- */
-
-/* FIXME: think about conflicting assertions */
-
-static void
-refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essentialok)
-{
-  Pool *pool = solv->pool;
-  int i, j;
-  Id v;
-  Queue disabled;
-  int disabledcnt;
-
-  IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-    {
-      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion start\n");
-      for (i = 0; problem[i]; i++)
-       {
-         if (problem[i] == sug)
-           POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "=> ");
-         solver_printproblem(solv, problem[i]);
-       }
-    }
-  queue_empty(refined);
-  if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
-    return;
-  queue_init(&disabled);
-  queue_push(refined, sug);
-
-  /* re-enable all problem rules with the exception of "sug"(gestion) */
-  solver_reset(solv);
-
-  for (i = 0; problem[i]; i++)
-    if (problem[i] != sug)
-      solver_enableproblem(solv, problem[i]);
-
-  if (sug < 0)
-    solver_reenablepolicyrules(solv, -sug);
-  else if (sug >= solv->updaterules && sug < solv->updaterules_end)
-    {
-      /* enable feature rule */
-      Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
-      if (r->p)
-       solver_enablerule(solv, r);
-    }
-
-  enableweakrules(solv);
-
-  for (;;)
-    {
-      int njob, nfeature, nupdate, pass;
-      queue_empty(&solv->problems);
-      solver_reset(solv);
-      solver_run_sat(solv, 0, 0);
-
-      if (!solv->problems.count)
-       {
-         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no more problems!\n");
-         break;                /* great, no more problems */
-       }
-      disabledcnt = disabled.count;
-      /* start with 1 to skip over proof index */
-      njob = nfeature = nupdate = 0;
-      for (pass = 0; pass < 2; pass++)
-       {
-         for (i = 1; i < solv->problems.count - 1; i++)
-           {
-             /* ignore solutions in refined */
-             v = solv->problems.elements[i];
-             if (v == 0)
-               break;  /* end of problem reached */
-             if (sug != v)
-               {
-                 /* check if v is in the given problems list
-                  * we allow disabling all problem rules *after* sug in
-                  * pass 2, to prevent getting the same solution twice */
-                 for (j = 0; problem[j]; j++)
-                   if (problem[j] == v || (pass && problem[j] == sug))
-                     break;
-                 if (problem[j] == v)
-                   continue;
-               }
-             if (v >= solv->featurerules && v < solv->featurerules_end)
-               nfeature++;
-             else if (v > 0)
-               nupdate++;
-             else
-               {
-                 if (!essentialok && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
-                   continue;   /* not that one! */
-                 njob++;
-               }
-             queue_push(&disabled, v);
-           }
-         if (disabled.count != disabledcnt)
-           break;
-       }
-      if (disabled.count == disabledcnt)
-       {
-         /* no solution found, this was an invalid suggestion! */
-         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no solution found!\n");
-         refined->count = 0;
-         break;
-       }
-      if (!njob && nupdate && nfeature)
-       {
-         /* got only update rules, filter out feature rules */
-         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
-         for (i = j = disabledcnt; i < disabled.count; i++)
-           {
-             v = disabled.elements[i];
-             if (v < solv->featurerules || v >= solv->featurerules_end)
-               disabled.elements[j++] = v;
-           }
-         disabled.count = j;
-         nfeature = 0;
-       }
-      if (disabled.count == disabledcnt + 1)
-       {
-         /* just one suggestion, add it to refined list */
-         v = disabled.elements[disabledcnt];
-         if (!nfeature && v != sug)
-           queue_push(refined, v);     /* do not record feature rules */
-         solver_disableproblem(solv, v);
-         if (v >= solv->updaterules && v < solv->updaterules_end)
-           {
-             Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
-             if (r->p)
-               solver_enablerule(solv, r);     /* enable corresponding feature rule */
-           }
-         if (v < 0)
-           solver_reenablepolicyrules(solv, -v);
-       }
-      else
-       {
-         /* more than one solution, disable all */
-         /* do not push anything on refine list, as we do not know which solution to choose */
-         /* thus, the user will get another problem if he selects this solution, where he
-           * can choose the right one */
-         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "more than one solution found:\n");
-             for (i = disabledcnt; i < disabled.count; i++)
-               solver_printproblem(solv, disabled.elements[i]);
-           }
-         for (i = disabledcnt; i < disabled.count; i++)
-           {
-             v = disabled.elements[i];
-             solver_disableproblem(solv, v);
-             if (v >= solv->updaterules && v < solv->updaterules_end)
-               {
-                 Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
-                 if (r->p)
-                   solver_enablerule(solv, r);
-               }
-           }
-       }
-    }
-  /* all done, get us back into the same state as before */
-  /* enable refined rules again */
-  for (i = 0; i < disabled.count; i++)
-    solver_enableproblem(solv, disabled.elements[i]);
-  queue_free(&disabled);
-  /* reset policy rules */
-  for (i = 0; problem[i]; i++)
-    solver_enableproblem(solv, problem[i]);
-  solver_disablepolicyrules(solv);
-  /* disable problem rules again */
-  for (i = 0; problem[i]; i++)
-    solver_disableproblem(solv, problem[i]);
-  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion end\n");
-}
-
-
-/*-------------------------------------------------------------------
- * sorting helper for problems
- *
- * bring update rules before job rules
- * make essential job rules last
- */
-
-static int
-problems_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Queue *job = dp;
-  Id a = *(Id *)ap, b = *(Id *)bp;
-  if (a < 0 && b > 0)
-    return 1;
-  if (a > 0 && b < 0)
-    return -1;
-  if (a < 0 && b < 0)
-    {
-      int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
-      int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
-      int x = af - bf;
-      if (x)
-       return x;
-    }
-  return a - b;
-}
-
-/*
- * convert a solution rule into a job modifier
- */
-static void
-convertsolution(Solver *solv, Id why, Queue *solutionq)
-{
-  Pool *pool = solv->pool;
-  if (why < 0)
-    {
-      why = -why;
-      if (why < solv->pooljobcnt)
-       {
-         queue_push(solutionq, SOLVER_SOLUTION_POOLJOB);
-         queue_push(solutionq, why);
-       }
-      else
-       {
-         queue_push(solutionq, SOLVER_SOLUTION_JOB);
-         queue_push(solutionq, why - solv->pooljobcnt);
-       }
-      return;
-    }
-  if (why >= solv->infarchrules && why < solv->infarchrules_end)
-    {
-      Id p, name;
-      /* infarch rule, find replacement */
-      assert(solv->rules[why].p < 0);
-      name = pool->solvables[-solv->rules[why].p].name;
-      while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
-       why--;
-      p = 0;
-      for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
-       if (solv->decisionmap[-solv->rules[why].p] > 0)
-         {
-           p = -solv->rules[why].p;
-           break;
-         }
-      if (!p)
-       return;         /* false alarm */
-      queue_push(solutionq, SOLVER_SOLUTION_INFARCH);
-      queue_push(solutionq, p);
-      return;
-    }
-  if (why >= solv->duprules && why < solv->duprules_end)
-    {
-      Id p, name;
-      /* dist upgrade rule, find replacement */
-      assert(solv->rules[why].p < 0);
-      name = pool->solvables[-solv->rules[why].p].name;
-      while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
-       why--;
-      p = 0;
-      for (; why < solv->duprules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
-       if (solv->decisionmap[-solv->rules[why].p] > 0)
-         {
-           p = -solv->rules[why].p;
-           break;
-         }
-      if (!p)
-       return;         /* false alarm */
-      queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
-      queue_push(solutionq, p);
-      return;
-    }
-  if (why >= solv->updaterules && why < solv->updaterules_end)
-    {
-      /* update rule, find replacement package */
-      Id p, pp, rp = 0;
-      Rule *rr;
-
-      /* check if this is a false positive, i.e. the update rule is fulfilled */
-      rr = solv->rules + why;
-      FOR_RULELITERALS(p, pp, rr)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         return;       /* false alarm */
-
-      p = solv->installed->start + (why - solv->updaterules);
-      if (solv->dupmap_all && solv->rules[why].p != p && solv->decisionmap[p] > 0)
-       {
-         /* distupgrade case, allow to keep old package */
-         queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
-         queue_push(solutionq, p);
-         return;
-       }
-      if (solv->decisionmap[p] > 0)
-       return;         /* false alarm, turned out we can keep the package */
-      rr = solv->rules + solv->featurerules + (why - solv->updaterules);
-      if (!rr->p)
-       rr = solv->rules + why;
-      if (rr->w2)
-       {
-         int mvrp = 0;         /* multi-version replacement */
-         FOR_RULELITERALS(rp, pp, rr)
-           {
-             if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
-               {
-                 mvrp = rp;
-                 if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp)))
-                   break;
-               }
-           }
-         if (!rp && mvrp)
-           {
-             /* found only multi-version replacements */
-             /* have to split solution into two parts */
-             queue_push(solutionq, p);
-             queue_push(solutionq, mvrp);
-           }
-       }
-      queue_push(solutionq, p);
-      queue_push(solutionq, rp);
-      return;
-    }
-  if (why >= solv->bestrules && why < solv->bestrules_end)
-    {
-      int mvrp;
-      Id p, pp, rp = 0;
-      Rule *rr;
-      /* check false positive */
-      rr = solv->rules + why;
-      FOR_RULELITERALS(p, pp, rr)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         return;       /* false alarm */
-      /* check update/feature rule */
-      p = solv->bestrules_pkg[why - solv->bestrules];
-      if (p < 0)
-       {
-         /* install job */
-         queue_push(solutionq, 0);
-         queue_push(solutionq, solv->ruletojob.elements[-p - solv->jobrules] + 1);
-         return;
-       }
-      if (solv->decisionmap[p] > 0)
-       {
-         /* disable best rule by keeping the old package */
-         queue_push(solutionq, SOLVER_SOLUTION_BEST);
-         queue_push(solutionq, p);
-         return;
-       }
-      rr = solv->rules + solv->featurerules + (p - solv->installed->start);
-      if (!rr->p)
-       rr = solv->rules + solv->updaterules + (p - solv->installed->start);
-      mvrp = 0;                /* multi-version replacement */
-      FOR_RULELITERALS(rp, pp, rr)
-       if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
-         {
-           mvrp = rp;
-           if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp)))
-             break;
-         }
-      if (!rp && mvrp)
-       {
-         queue_push(solutionq, SOLVER_SOLUTION_BEST);  /* split, see above */
-         queue_push(solutionq, mvrp);
-         queue_push(solutionq, p);
-         queue_push(solutionq, 0);
-         return;
-       }
-      if (rp)
-       {
-         queue_push(solutionq, SOLVER_SOLUTION_BEST);
-         queue_push(solutionq, rp);
-       }
-      return;
-    }
-}
-
-/*
- * convert problem data into a form usable for refining.
- * Returns the number of problems.
- */
-int
-solver_prepare_solutions(Solver *solv)
-{
-  int i, j = 1, idx;
-
-  if (!solv->problems.count)
-    return 0;
-  queue_empty(&solv->solutions);
-  queue_push(&solv->solutions, 0);     /* dummy so idx is always nonzero */
-  idx = solv->solutions.count;
-  queue_push(&solv->solutions, -1);    /* unrefined */
-  /* proofidx stays in position, thus we start with 1 */
-  for (i = 1; i < solv->problems.count; i++)
-    {
-      Id p = solv->problems.elements[i];
-      queue_push(&solv->solutions, p);
-      if (p)
-        continue;
-      /* end of problem reached */
-      solv->problems.elements[j++] = idx;
-      if (i + 1 >= solv->problems.count)
-        break;
-      /* start another problem */
-      solv->problems.elements[j++] = solv->problems.elements[++i];  /* copy proofidx */
-      idx = solv->solutions.count;
-      queue_push(&solv->solutions, -1);        /* unrefined */
-    }
-  solv->problems.count = j;
-  return j / 2;
-}
-
-/*
- * refine the simple solution rule list provided by
- * the solver into multiple lists of job modifiers.
- */
-static void
-create_solutions(Solver *solv, int probnr, int solidx)
-{
-  Pool *pool = solv->pool;
-  Queue redoq;
-  Queue problem, solution, problems_save, branches_save;
-  int i, j, nsol;
-  int essentialok;
-  unsigned int now;
-  int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0;
-  Id extraflags = -1;
-  int decisioncnt_update;
-  int decisioncnt_keep;
-  int decisioncnt_resolve;
-  int decisioncnt_weak;
-  int decisioncnt_orphan;
-
-  now = solv_timems(0);
-  queue_init(&redoq);
-  /* save decisionq, decisionq_why, decisionmap, and decisioncnt */
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      Id p = solv->decisionq.elements[i];
-      queue_push(&redoq, p);
-      queue_push(&redoq, solv->decisionq_why.elements[i]);
-      queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
-    }
-  decisioncnt_update = solv->decisioncnt_update;
-  decisioncnt_keep = solv->decisioncnt_keep;
-  decisioncnt_resolve = solv->decisioncnt_resolve;
-  decisioncnt_weak = solv->decisioncnt_weak;
-  decisioncnt_orphan = solv->decisioncnt_orphan;
-
-  /* save problems queue */
-  problems_save = solv->problems;
-  memset(&solv->problems, 0, sizeof(solv->problems));
-
-  /* save branches queue */
-  branches_save = solv->problems;
-  memset(&solv->branches, 0, sizeof(solv->branches));
-
-  /* extract problem from queue */
-  queue_init(&problem);
-  for (i = solidx + 1; i < solv->solutions.count; i++)
-    {
-      Id v = solv->solutions.elements[i];
-      if (!v)
-       break;
-      queue_push(&problem, v);
-      if (v < 0)
-       extraflags &= solv->job.elements[-v - 1];
-    }
-  if (extraflags == -1)
-    extraflags = 0;
-  if (problem.count > 1)
-    solv_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
-  queue_push(&problem, 0);     /* mark end for refine_suggestion */
-  problem.count--;
-#if 0
-  for (i = 0; i < problem.count; i++)
-    printf("PP %d %d\n", i, problem.elements[i]);
-#endif
-
-  /* refine each solution element */
-  nsol = 0;
-  essentialok = 0;
-  queue_init(&solution);
-  for (i = 0; i < problem.count; i++)
-    {
-      int solstart = solv->solutions.count;
-      refine_suggestion(solv, problem.elements, problem.elements[i], &solution, essentialok);
-      queue_push(&solv->solutions, 0); /* reserve room for number of elements */
-      for (j = 0; j < solution.count; j++)
-       convertsolution(solv, solution.elements[j], &solv->solutions);
-      if (solv->solutions.count == solstart + 1)
-       {
-         solv->solutions.count--;      /* this one did not work out */
-         if (nsol || i + 1 < problem.count)
-           continue;                   /* got one or still hope */
-         if (!essentialok)
-           {
-             /* nothing found, start over */
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "nothing found, re-run with essentialok = 1\n");
-             essentialok = 1;
-             i = -1;
-             continue;
-           }
-         /* this is bad, we found no solution */
-         /* for now just offer a rule */
-         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "nothing found, already did essentialok, fake it\n");
-         queue_push(&solv->solutions, 0);
-         for (j = 0; j < problem.count; j++)
-           {
-             convertsolution(solv, problem.elements[j], &solv->solutions);
-             if (solv->solutions.count > solstart + 1)
-               break;
-           }
-         if (solv->solutions.count == solstart + 1)
-           {
-             solv->solutions.count--;
-             continue;         /* sorry */
-           }
-       }
-      /* patch in number of solution elements */
-      solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
-      queue_push(&solv->solutions, 0); /* add end marker */
-      queue_push(&solv->solutions, 0); /* add end marker */
-      queue_push(&solv->solutions, problem.elements[i]);       /* just for bookkeeping */
-      queue_push(&solv->solutions, extraflags & SOLVER_CLEANDEPS);     /* our extraflags */
-      solv->solutions.elements[solidx + 1 + nsol++] = solstart;
-    }
-  solv->solutions.elements[solidx + 1 + nsol] = 0;     /* end marker */
-  solv->solutions.elements[solidx] = nsol;
-  queue_free(&problem);
-  queue_free(&solution);
-
-  /* restore decisions */
-  memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
-  queue_empty(&solv->decisionq);
-  queue_empty(&solv->decisionq_why);
-  for (i = 0; i < redoq.count; i += 3)
-    {
-      Id p = redoq.elements[i];
-      queue_push(&solv->decisionq, p);
-      queue_push(&solv->decisionq_why, redoq.elements[i + 1]);
-      solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
-    }
-  queue_free(&redoq);
-  solv->decisioncnt_update = decisioncnt_update;
-  solv->decisioncnt_keep = decisioncnt_keep;
-  solv->decisioncnt_resolve = decisioncnt_resolve;
-  solv->decisioncnt_weak = decisioncnt_weak;
-  solv->decisioncnt_orphan = decisioncnt_orphan;
-
-  /* restore problems */
-  queue_free(&solv->problems);
-  solv->problems = problems_save;
-
-  /* restore branches */
-  queue_free(&solv->branches);
-  solv->branches = branches_save;
-
-  if (solv->cleandeps_mistakes)
-    {
-      if (oldmistakes)
-       queue_truncate(solv->cleandeps_mistakes, oldmistakes);
-      else
-       {
-         queue_free(solv->cleandeps_mistakes);
-         solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
-       }
-    }
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "create_solutions for problem #%d took %d ms\n", probnr, solv_timems(now));
-}
-
-
-/**************************************************************************/
-
-unsigned int
-solver_problem_count(Solver *solv)
-{
-  return solv->problems.count / 2;
-}
-
-Id
-solver_next_problem(Solver *solv, Id problem)
-{
-  if (!problem)
-    return solv->problems.count ? 1 : 0;
-  return (problem + 1) * 2 - 1 < solv->problems.count ? problem + 1 : 0;
-}
-
-unsigned int
-solver_solution_count(Solver *solv, Id problem)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  if (solv->solutions.elements[solidx] < 0)
-    create_solutions(solv, problem, solidx);
-  return solv->solutions.elements[solidx];
-}
-
-Id
-solver_next_solution(Solver *solv, Id problem, Id solution)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  if (solv->solutions.elements[solidx] < 0)
-    create_solutions(solv, problem, solidx);
-  return solv->solutions.elements[solidx + solution + 1] ? solution + 1 : 0;
-}
-
-unsigned int
-solver_solutionelement_count(Solver *solv, Id problem, Id solution)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  solidx = solv->solutions.elements[solidx + solution];
-  return solv->solutions.elements[solidx];
-}
-
-Id
-solver_solutionelement_internalid(Solver *solv, Id problem, Id solution)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  solidx = solv->solutions.elements[solidx + solution];
-  return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 3];
-}
-
-Id
-solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  solidx = solv->solutions.elements[solidx + solution];
-  return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 4];
-}
-
-
-/*
- *  return the next item of the proposed solution
- *  here are the possibilities for p / rp and what
- *  the solver expects the application to do:
- *    p                             rp
- *  -------------------------------------------------------
- *    SOLVER_SOLUTION_INFARCH       pkgid
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *    SOLVER_SOLUTION_DISTUPGRADE   pkgid
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *    SOLVER_SOLUTION_BEST          pkgid
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *    SOLVER_SOLUTION_JOB           jobidx
- *    -> remove job (jobidx - 1, jobidx) from job queue
- *    SOLVER_SOLUTION_POOLJOB       jobidx
- *    -> remove job (jobidx - 1, jobidx) from pool job queue
- *    pkgid (> 0)                   0
- *    -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
- *    pkgid (> 0)                   pkgid (> 0)
- *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
- *       (this will replace package p)
- *
- * Thus, the solver will either ask the application to remove
- * a specific job from the job queue, or ask to add an install/erase
- * job to it.
- *
- */
-
-Id
-solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
-{
-  Id solidx = solv->problems.elements[problem * 2 - 1];
-  solidx = solv->solutions.elements[solidx + solution];
-  if (!solidx)
-    return 0;
-  solidx += 1 + element * 2;
-  if (!solv->solutions.elements[solidx] && !solv->solutions.elements[solidx + 1])
-    return 0;
-  *p = solv->solutions.elements[solidx];
-  *rp = solv->solutions.elements[solidx + 1];
-  return element + 1;
-}
-
-void
-solver_take_solutionelement(Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job)
-{
-  int i;
-
-  if (p == SOLVER_SOLUTION_POOLJOB)
-    {
-      solv->pool->pooljobs.elements[rp - 1] = SOLVER_NOOP;
-      solv->pool->pooljobs.elements[rp] = 0;
-      return;
-    }
-  if (p == SOLVER_SOLUTION_JOB)
-    {
-      job->elements[rp - 1] = SOLVER_NOOP;
-      job->elements[rp] = 0;
-      return;
-    }
-  if (rp <= 0 && p <= 0)
-    return;    /* just in case */
-  if (rp > 0)
-    p = SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extrajobflags;
-  else
-    {
-      rp = p;
-      p = SOLVER_ERASE|SOLVER_SOLVABLE|extrajobflags;
-    }
-  for (i = 0; i < job->count; i += 2)
-    if (job->elements[i] == p && job->elements[i + 1] == rp)
-      return;
-  queue_push2(job, p, rp);
-}
-
-void
-solver_take_solution(Solver *solv, Id problem, Id solution, Queue *job)
-{
-  Id p, rp, element = 0;
-  Id extrajobflags = solver_solutionelement_extrajobflags(solv, problem, solution);
-  while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
-    solver_take_solutionelement(solv, p, rp, extrajobflags, job);
-}
-
-
-/*-------------------------------------------------------------------
- *
- * find problem rule
- */
-
-static void
-findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Map *rseen)
-{
-  Id rid, d;
-  Id lreqr, lconr, lsysr, ljobr;
-  Rule *r;
-  Id jobassert = 0;
-  int i, reqset = 0;   /* 0: unset, 1: installed, 2: jobassert, 3: assert */
-  int conset = 0;      /* 0: unset, 1: installed */
-
-  /* find us a jobassert rule */
-  for (i = idx; (rid = solv->learnt_pool.elements[i]) != 0; i++)
-    {
-      if (rid < solv->jobrules || rid >= solv->jobrules_end)
-       continue;
-      r = solv->rules + rid;
-      d = r->d < 0 ? -r->d - 1 : r->d;
-      if (!d && r->w2 == 0 && r->p > 0)
-       {
-         jobassert = r->p;
-         break;
-       }
-    }
-
-  /* the problem rules are somewhat ordered from "near to the problem" to
-   * "near to the job" */
-  lreqr = lconr = lsysr = ljobr = 0;
-  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
-    {
-      assert(rid > 0);
-      if (rid >= solv->learntrules)
-       {
-         if (MAPTST(rseen, rid - solv->learntrules))
-           continue;
-         MAPSET(rseen, rid - solv->learntrules);
-         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, rseen);
-       }
-      else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid <= solv->yumobsrules_end))
-       {
-         if (!*jobrp)
-           *jobrp = rid;
-       }
-      else if (rid >= solv->updaterules && rid < solv->updaterules_end)
-       {
-         if (!*sysrp)
-           *sysrp = rid;
-       }
-      else
-       {
-         assert(rid < solv->pkgrules_end);
-         r = solv->rules + rid;
-         d = r->d < 0 ? -r->d - 1 : r->d;
-         if (!d && r->w2 < 0)
-           {
-             /* prefer conflicts of installed packages */
-             if (solv->installed && !conset)
-               {
-                 if (r->p < 0 && (solv->pool->solvables[-r->p].repo == solv->installed ||
-                                 solv->pool->solvables[-r->w2].repo == solv->installed))
-                   {
-                     *conrp = rid;
-                     conset = 1;
-                   }
-               }
-             if (!*conrp)
-               *conrp = rid;
-           }
-         else
-           {
-             if (!d && r->w2 == 0 && reqset < 3)
-               {
-                 if (*reqrp > 0 && r->p < -1)
-                   {
-                     Id op = -solv->rules[*reqrp].p;
-                     if (op > 1 && solv->pool->solvables[op].arch != solv->pool->solvables[-r->p].arch)
-                       continue;       /* different arch, skip */
-                   }
-                 /* prefer assertions */
-                 *reqrp = rid;
-                 reqset = 3;
-               }
-             else if (jobassert && r->p == -jobassert)
-               {
-                 /* prefer rules of job assertions */
-                 *reqrp = rid;
-                 reqset = 2;
-               }
-             else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && reqset <= 1)
-               {
-                 /* prefer rules of job installed package so that the user doesn't get confused by strange packages */
-                 *reqrp = rid;
-                 reqset = 1;
-               }
-             else if (!*reqrp)
-               *reqrp = rid;
-           }
-       }
-    }
-  if (!*reqrp && lreqr)
-    *reqrp = lreqr;
-  if (!*conrp && lconr)
-    *conrp = lconr;
-  if (!*jobrp && ljobr)
-    *jobrp = ljobr;
-  if (!*sysrp && lsysr)
-    *sysrp = lsysr;
-}
-
-/*
- * find problem rule
- *
- * search for a rule that describes the problem to the
- * user. Actually a pretty hopeless task that may leave the user
- * puzzled. To get all of the needed information use
- * solver_findallproblemrules() instead.
- */
-
-Id
-solver_findproblemrule(Solver *solv, Id problem)
-{
-  Id reqr, conr, sysr, jobr;
-  Id idx = solv->problems.elements[2 * problem - 2];
-  Map rseen;
-  reqr = conr = sysr = jobr = 0;
-  map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
-  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &rseen);
-  map_free(&rseen);
-  /* check if the request is about a not-installed package requiring a installed
-   * package conflicting with the non-installed package. In that case return the conflict */
-  if (reqr && conr && solv->installed && solv->rules[reqr].p < 0 && solv->rules[conr].p < 0 && solv->rules[conr].w2 < 0)
-    {
-      Pool *pool = solv->pool;
-      Solvable *s  = pool->solvables - solv->rules[reqr].p;
-      Solvable *s1 = pool->solvables - solv->rules[conr].p;
-      Solvable *s2 = pool->solvables - solv->rules[conr].w2;
-      Id cp = 0;
-      if (s == s1 && s2->repo == solv->installed)
-       cp = -solv->rules[conr].w2;
-      else if (s == s2 && s1->repo == solv->installed)
-       cp = -solv->rules[conr].p;
-      if (cp && s1->name != s2->name && s->repo != solv->installed)
-       {
-         Id p, pp;
-         Rule *r = solv->rules + reqr;
-         FOR_RULELITERALS(p, pp, r)
-           if (p == cp)
-             return conr;
-       }
-    }
-  if (reqr)
-    return reqr;       /* some requires */
-  if (conr)
-    return conr;       /* some conflict */
-  if (sysr)
-    return sysr;       /* an update rule */
-  if (jobr)
-    return jobr;       /* a user request */
-  assert(0);
-  return 0;
-}
-
-/*-------------------------------------------------------------------*/
-
-static void
-findallproblemrules_internal(Solver *solv, Id idx, Queue *rules, Map *rseen)
-{
-  Id rid;
-  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
-    {
-      if (rid >= solv->learntrules)
-        {
-         if (MAPTST(rseen, rid - solv->learntrules))
-           continue;
-         MAPSET(rseen, rid - solv->learntrules);
-         findallproblemrules_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], rules, rseen);
-          continue;
-       }
-      queue_pushunique(rules, rid);
-    }
-}
-
-/*
- * find all problem rule
- *
- * return all rules that lead to the problem. This gives the user
- * all of the information to understand the problem, but the result
- * can be a large number of rules.
- */
-
-void
-solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
-{
-  Map rseen;
-  queue_empty(rules);
-  map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
-  findallproblemrules_internal(solv, solv->problems.elements[2 * problem - 2], rules, &rseen);
-  map_free(&rseen);
-}
-
-const char *
-solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep)
-{
-  Pool *pool = solv->pool;
-  char *s;
-  switch (type)
-    {
-    case SOLVER_RULE_DISTUPGRADE:
-      return pool_tmpjoin(pool, pool_solvid2str(pool, source), " does not belong to a distupgrade repository", 0);
-    case SOLVER_RULE_INFARCH:
-      return pool_tmpjoin(pool, pool_solvid2str(pool, source), " has inferior architecture", 0);
-    case SOLVER_RULE_UPDATE:
-      return pool_tmpjoin(pool, "problem with installed package ", pool_solvid2str(pool, source), 0);
-    case SOLVER_RULE_JOB:
-      return "conflicting requests";
-    case SOLVER_RULE_JOB_UNSUPPORTED:
-      return "unsupported request";
-    case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
-      return pool_tmpjoin(pool, "nothing provides requested ", pool_dep2str(pool, dep), 0);
-    case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
-      return pool_tmpjoin(pool, "package ", pool_dep2str(pool, dep), " does not exist");
-    case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
-      return pool_tmpjoin(pool, pool_dep2str(pool, dep), " is provided by the system", 0);
-    case SOLVER_RULE_PKG:
-      return "some dependency problem";
-    case SOLVER_RULE_BEST:
-      if (source > 0)
-        return pool_tmpjoin(pool, "cannot install the best update candidate for package ", pool_solvid2str(pool, source), 0);
-     return "cannot install the best candidate for the job";
-    case SOLVER_RULE_PKG_NOT_INSTALLABLE:
-      return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable");
-    case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
-      s = pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0);
-      return pool_tmpappend(pool, s, " needed by ", pool_solvid2str(pool, source));
-    case SOLVER_RULE_PKG_SAME_NAME:
-      s = pool_tmpjoin(pool, "cannot install both ", pool_solvid2str(pool, source), 0);
-      return pool_tmpappend(pool, s, " and ", pool_solvid2str(pool, target));
-    case SOLVER_RULE_PKG_CONFLICTS:
-      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
-      s = pool_tmpappend(pool, s, " conflicts with ", pool_dep2str(pool, dep));
-      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
-    case SOLVER_RULE_PKG_OBSOLETES:
-      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
-      s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
-      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
-    case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
-      s = pool_tmpjoin(pool, "installed package ", pool_solvid2str(pool, source), 0);
-      s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
-      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
-    case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
-      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
-      s = pool_tmpappend(pool, s, " implicitly obsoletes ", pool_dep2str(pool, dep));
-      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
-    case SOLVER_RULE_PKG_REQUIRES:
-      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " requires ");
-      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), ", but none of the providers can be installed");
-    case SOLVER_RULE_PKG_SELF_CONFLICT:
-      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " conflicts with ");
-      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), " provided by itself");
-    case SOLVER_RULE_YUMOBS:
-      s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and ");
-      s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
-      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
-    default:
-      return "bad problem rule type";
-    }
-}
-
-/* convenience function */
-const char *
-solver_problem2str(Solver *solv, Id problem)
-{
-  Id type, source, target, dep;
-  Id r = solver_findproblemrule(solv, problem);
-  if (!r)
-    return "no problem rule?";
-  type = solver_ruleinfo(solv, r, &source, &target, &dep);
-  return solver_problemruleinfo2str(solv, type, source, target, dep);
-}
-
-const char *
-solver_solutionelement2str(Solver *solv, Id p, Id rp)
-{
-  Pool *pool = solv->pool;
-  if (p == SOLVER_SOLUTION_JOB || p == SOLVER_SOLUTION_POOLJOB)
-    {
-      Id how, what;
-      if (p == SOLVER_SOLUTION_JOB)
-       rp += solv->pooljobcnt;
-      how = solv->job.elements[rp - 1];
-      what = solv->job.elements[rp];
-      return pool_tmpjoin(pool, "do not ask to ", pool_job2str(pool, how, what, 0), 0);
-    }
-  else if (p == SOLVER_SOLUTION_INFARCH)
-    {
-      Solvable *s = pool->solvables + rp;
-      if (solv->installed && s->repo == solv->installed)
-        return pool_tmpjoin(pool, "keep ", pool_solvable2str(pool, s), " despite the inferior architecture");
-      else
-        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the inferior architecture");
-    }
-  else if (p == SOLVER_SOLUTION_DISTUPGRADE)
-    {
-      Solvable *s = pool->solvables + rp;
-      if (solv->installed && s->repo == solv->installed)
-        return pool_tmpjoin(pool, "keep obsolete ", pool_solvable2str(pool, s), 0);
-      else
-        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " from excluded repository");
-    }
-  else if (p == SOLVER_SOLUTION_BEST)
-    {
-      Solvable *s = pool->solvables + rp;
-      if (solv->installed && s->repo == solv->installed)
-        return pool_tmpjoin(pool, "keep old ", pool_solvable2str(pool, s), 0);
-      else
-        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
-    }
-  else if (p > 0 && rp == 0)
-    return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
-  else if (p > 0 && rp > 0)
-    {
-      const char *sp = pool_solvid2str(pool, p);
-      const char *srp = pool_solvid2str(pool, rp);
-      const char *str = pool_tmpjoin(pool, "allow replacement of ", sp, 0);
-      return pool_tmpappend(pool, str, " with ", srp);
-    }
-  else
-    return "bad solution element";
-}
-
diff --git a/libsolv-0.6.15/src/problems.h b/libsolv-0.6.15/src/problems.h
deleted file mode 100644 (file)
index e5b2279..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * problems.h
- *
- */
-
-#ifndef LIBSOLV_PROBLEMS_H
-#define LIBSOLV_PROBLEMS_H
-
-#include "rules.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-struct _Solver;
-
-#define SOLVER_SOLUTION_JOB             (0)
-#define SOLVER_SOLUTION_DISTUPGRADE     (-1)
-#define SOLVER_SOLUTION_INFARCH         (-2)
-#define SOLVER_SOLUTION_BEST            (-3)
-#define SOLVER_SOLUTION_POOLJOB         (-4)
-
-void solver_disableproblem(struct _Solver *solv, Id v);
-void solver_enableproblem(struct _Solver *solv, Id v);
-int solver_prepare_solutions(struct _Solver *solv);
-
-unsigned int solver_problem_count(struct _Solver *solv);
-Id solver_next_problem(struct _Solver *solv, Id problem);
-unsigned int solver_solution_count(struct _Solver *solv, Id problem);
-Id solver_next_solution(struct _Solver *solv, Id problem, Id solution);
-unsigned int solver_solutionelement_count(struct _Solver *solv, Id problem, Id solution);
-Id solver_solutionelement_internalid(struct _Solver *solv, Id problem, Id solution);
-Id solver_solutionelement_extrajobflags(struct _Solver *solv, Id problem, Id solution);
-Id solver_next_solutionelement(struct _Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
-
-void solver_take_solutionelement(struct _Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job);
-void solver_take_solution(struct _Solver *solv, Id problem, Id solution, Queue *job);
-
-Id solver_findproblemrule(struct _Solver *solv, Id problem);
-void solver_findallproblemrules(struct _Solver *solv, Id problem, Queue *rules);
-
-extern const char *solver_problemruleinfo2str(struct _Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
-extern const char *solver_problem2str(struct _Solver *solv, Id problem);
-extern const char *solver_solutionelement2str(struct _Solver *solv, Id p, Id rp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libsolv-0.6.15/src/qsort_r.c b/libsolv-0.6.15/src/qsort_r.c
deleted file mode 100644 (file)
index d49049a..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * qsort taken from FreeBSD, slightly modified to match glibc's
- * argument ordering
- */
-
-/* FIXME: should use mergesort instead */
-
-/*-
- * Copyright (c) 1992, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)qsort.c    8.1 (Berkeley) 6/4/93";
-#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
-
-/* $FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.13.2.1.8.1 2010/12/21 17:10:29 kensmith Exp $ */
-
-#include <stdlib.h>
-
-typedef int             cmp_t(const void *, const void *, void *);
-static inline char     *med3(char *, char *, char *, cmp_t *, void *);
-static inline void      swapfunc(char *, char *, int, int);
-
-#ifndef min
-#define min(a, b)      (a) < (b) ? a : b
-#endif
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) {              \
-       long i = (n) / sizeof (TYPE);                   \
-       TYPE *pi = (TYPE *) (parmi);            \
-       TYPE *pj = (TYPE *) (parmj);            \
-       do {                                            \
-               TYPE    t = *pi;                \
-               *pi++ = *pj;                            \
-               *pj++ = t;                              \
-        } while (--i > 0);                             \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
-       es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static inline void
-swapfunc(a, b, n, swaptype)
-       char *a, *b;
-       int n, swaptype;
-{
-       if(swaptype <= 1)
-               swapcode(long, a, b, n)
-       else
-               swapcode(char, a, b, n)
-}
-
-#define swap(a, b)                                     \
-       if (swaptype == 0) {                            \
-               long t = *(long *)(a);                  \
-               *(long *)(a) = *(long *)(b);            \
-               *(long *)(b) = t;                       \
-       } else                                          \
-               swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n)       if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-#define        CMP(t, x, y) (cmp((x), (y), (t)))
-
-static inline char *
-med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk)
-{
-       return CMP(thunk, a, b) < 0 ?
-              (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
-              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
-}
-
-void
-solv_sort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
-{
-       char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
-       size_t d, r;
-       int cmp_result;
-       int swaptype, swap_cnt;
-
-loop:  SWAPINIT(a, es);
-       swap_cnt = 0;
-       if (n < 7) {
-               for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
-                       for (pl = pm;
-                            pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
-                            pl -= es)
-                               swap(pl, pl - es);
-               return;
-       }
-       pm = (char *)a + (n / 2) * es;
-       if (n > 7) {
-               pl = a;
-               pn = (char *)a + (n - 1) * es;
-               if (n > 40) {
-                       d = (n / 8) * es;
-                       pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
-                       pm = med3(pm - d, pm, pm + d, cmp, thunk);
-                       pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
-               }
-               pm = med3(pl, pm, pn, cmp, thunk);
-       }
-       swap(a, pm);
-       pa = pb = (char *)a + es;
-
-       pc = pd = (char *)a + (n - 1) * es;
-       for (;;) {
-               while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
-                       if (cmp_result == 0) {
-                               swap_cnt = 1;
-                               swap(pa, pb);
-                               pa += es;
-                       }
-                       pb += es;
-               }
-               while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
-                       if (cmp_result == 0) {
-                               swap_cnt = 1;
-                               swap(pc, pd);
-                               pd -= es;
-                       }
-                       pc -= es;
-               }
-               if (pb > pc)
-                       break;
-               swap(pb, pc);
-               swap_cnt = 1;
-               pb += es;
-               pc -= es;
-       }
-       if (swap_cnt == 0) {  /* Switch to insertion sort */
-               for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
-                       for (pl = pm;
-                            pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
-                            pl -= es)
-                               swap(pl, pl - es);
-               return;
-       }
-
-       pn = (char *)a + n * es;
-       r = min(pa - (char *)a, pb - pa);
-       vecswap(a, pb - r, r);
-       r = min(pd - pc, pn - pd - es);
-       vecswap(pb, pn - r, r);
-       if ((r = pb - pa) > es)
-               solv_sort(a, r / es, es, cmp, thunk);
-       if ((r = pd - pc) > es) {
-               /* Iterate rather than recurse to save stack space */
-               a = pn - r;
-               n = r / es;
-               goto loop;
-       }
-/*             qsort(pn - r, r / es, es, cmp);*/
-}
diff --git a/libsolv-0.6.15/src/queue.c b/libsolv-0.6.15/src/queue.c
deleted file mode 100644 (file)
index 37ea381..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * queue.c
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "queue.h"
-#include "util.h"
-
-#define EXTRA_SPACE 8
-#define EXTRA_SPACE_HEAD 8
-
-void
-queue_init(Queue *q)
-{
-  q->alloc = q->elements = 0;
-  q->count = q->left = 0;
-}
-
-void
-queue_init_clone(Queue *t, Queue *s)
-{
-  if (!s->elements)
-    {
-      t->alloc = t->elements = 0;
-      t->count = t->left = 0;
-      return;
-    }
-  t->alloc = t->elements = solv_malloc2(s->count + EXTRA_SPACE, sizeof(Id));
-  if (s->count)
-    memcpy(t->alloc, s->elements, s->count * sizeof(Id));
-  t->count = s->count;
-  t->left = EXTRA_SPACE;
-}
-
-void
-queue_init_buffer(Queue *q, Id *buf, int size)
-{
-  q->alloc = 0;
-  q->elements = buf;
-  q->count = 0;
-  q->left = size;
-}
-
-void
-queue_free(Queue *q)
-{
-  if (q->alloc)
-    solv_free(q->alloc);
-  q->alloc = q->elements = 0;
-  q->count = q->left = 0;
-}
-
-void
-queue_alloc_one(Queue *q)
-{
-  if (!q->alloc)
-    {
-      q->alloc = solv_malloc2(q->count + EXTRA_SPACE, sizeof(Id));
-      if (q->count)
-       memcpy(q->alloc, q->elements, q->count * sizeof(Id));
-      q->elements = q->alloc;
-      q->left = EXTRA_SPACE;
-    }
-  else if (q->alloc != q->elements)
-    {
-      int l = q->elements - q->alloc;
-      if (q->count)
-        memmove(q->alloc, q->elements, q->count * sizeof(Id));
-      q->elements -= l;
-      q->left += l;
-    }
-  else
-    {
-      q->elements = q->alloc = solv_realloc2(q->alloc, q->count + EXTRA_SPACE, sizeof(Id));
-      q->left = EXTRA_SPACE;
-    }
-}
-
-/* make room for an element in front of queue */
-void
-queue_alloc_one_head(Queue *q)
-{
-  int l;
-  if (!q->alloc || !q->left)
-    queue_alloc_one(q);
-  l = q->left > EXTRA_SPACE_HEAD ? EXTRA_SPACE_HEAD : q->left;
-  if (q->count)
-    memmove(q->elements + l, q->elements, q->count * sizeof(Id));
-  q->elements += l;
-  q->left -= l;
-}
-
-void
-queue_insert(Queue *q, int pos, Id id)
-{
-  queue_push(q, id);   /* make room */
-  if (pos < q->count - 1)
-    {
-      memmove(q->elements + pos + 1, q->elements + pos, (q->count - 1 - pos) * sizeof(Id));
-      q->elements[pos] = id;
-    }
-}
-
-void
-queue_delete(Queue *q, int pos)
-{
-  if (pos >= q->count)
-    return;
-  if (pos < q->count - 1)
-    memmove(q->elements + pos, q->elements + pos + 1, (q->count - 1 - pos) * sizeof(Id));
-  q->left++;
-  q->count--;
-}
-
-void
-queue_insert2(Queue *q, int pos, Id id1, Id id2)
-{
-  queue_push(q, id1);  /* make room */
-  queue_push(q, id2);  /* make room */
-  if (pos < q->count - 2)
-    {
-      memmove(q->elements + pos + 2, q->elements + pos, (q->count - 2 - pos) * sizeof(Id));
-      q->elements[pos] = id1;
-      q->elements[pos + 1] = id2;
-    }
-}
-
-void
-queue_delete2(Queue *q, int pos)
-{
-  if (pos >= q->count)
-    return;
-  if (pos == q->count - 1)
-    {
-      q->left++;
-      q->count--;
-      return;
-    }
-  if (pos < q->count - 2)
-    memmove(q->elements + pos, q->elements + pos + 2, (q->count - 2 - pos) * sizeof(Id));
-  q->left += 2;
-  q->count -= 2;
-}
-
-void
-queue_insertn(Queue *q, int pos, int n, Id *elements)
-{
-  if (n <= 0)
-    return;
-  if (pos > q->count)
-    pos = q->count;
-  if (q->left < n)
-    {
-      int off;
-      if (!q->alloc)
-       queue_alloc_one(q);
-      off = q->elements - q->alloc;
-      q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id));
-      q->elements = q->alloc + off;
-      q->left = n + EXTRA_SPACE;
-    }
-  if (pos < q->count)
-    memmove(q->elements + pos + n, q->elements + pos, (q->count - pos) * sizeof(Id));
-  if (elements)
-    memcpy(q->elements + pos, elements, n * sizeof(Id));
-  else
-    memset(q->elements + pos, 0, n * sizeof(Id));
-  q->left -= n;
-  q->count += n;
-}
-
-void
-queue_deleten(Queue *q, int pos, int n)
-{
-  if (n <= 0 || pos >= q->count)
-    return;
-  if (pos + n >= q->count)
-    n = q->count - pos;
-  else
-    memmove(q->elements + pos, q->elements + pos + n, (q->count - n - pos) * sizeof(Id));
-  q->left += n;
-  q->count -= n;
-}
-
-/* allocate room for n more elements */
-void
-queue_prealloc(Queue *q, int n)
-{
-  int off;
-  if (n <= 0 || q->left >= n)
-    return;
-  if (!q->alloc)
-    queue_alloc_one(q);
-  off = q->elements - q->alloc;
-  q->alloc = solv_realloc2(q->alloc, off + q->count + n + EXTRA_SPACE, sizeof(Id));
-  q->elements = q->alloc + off;
-  q->left = n + EXTRA_SPACE;
-}
-
diff --git a/libsolv-0.6.15/src/queue.h b/libsolv-0.6.15/src/queue.h
deleted file mode 100644 (file)
index 4785e67..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * queue.h
- *
- */
-
-#ifndef LIBSOLV_QUEUE_H
-#define LIBSOLV_QUEUE_H
-
-#include "pooltypes.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct _Queue {
-  Id *elements;                /* pointer to elements */
-  int count;           /* current number of elements in queue */
-  Id *alloc;           /* this is whats actually allocated, elements > alloc if shifted */
-  int left;            /* space left in alloc *after* elements+count */
-} Queue;
-
-
-extern void queue_alloc_one(Queue *q);         /* internal */
-extern void queue_alloc_one_head(Queue *q);    /* internal */
-
-/* clear queue */
-static inline void
-queue_empty(Queue *q)
-{
-  if (q->alloc)
-    {
-      q->left += (q->elements - q->alloc) + q->count;
-      q->elements = q->alloc;
-    }
-  else
-    q->left += q->count;
-  q->count = 0;
-}
-
-static inline Id
-queue_shift(Queue *q)
-{
-  if (!q->count)
-    return 0;
-  q->count--;
-  return *q->elements++;
-}
-
-static inline Id
-queue_pop(Queue *q)
-{
-  if (!q->count)
-    return 0;
-  q->left++;
-  return q->elements[--q->count];
-}
-
-static inline void
-queue_unshift(Queue *q, Id id)
-{
-  if (!q->alloc || q->alloc == q->elements)
-    queue_alloc_one_head(q);
-  *--q->elements = id;
-  q->count++;
-}
-
-static inline void
-queue_push(Queue *q, Id id)
-{
-  if (!q->left)
-    queue_alloc_one(q);
-  q->elements[q->count++] = id;
-  q->left--;
-}
-
-static inline void
-queue_pushunique(Queue *q, Id id)
-{
-  int i;
-  for (i = q->count; i > 0; )
-    if (q->elements[--i] == id)
-      return;
-  queue_push(q, id);
-}
-
-static inline void
-queue_push2(Queue *q, Id id1, Id id2)
-{
-  queue_push(q, id1);
-  queue_push(q, id2);
-}
-
-static inline void
-queue_truncate(Queue *q, int n)
-{
-  if (q->count > n)
-    {
-      q->left += q->count - n;
-      q->count = n;
-    }
-}
-
-extern void queue_init(Queue *q);
-extern void queue_init_buffer(Queue *q, Id *buf, int size);
-extern void queue_init_clone(Queue *t, Queue *s);
-extern void queue_free(Queue *q);
-
-extern void queue_insert(Queue *q, int pos, Id id);
-extern void queue_insert2(Queue *q, int pos, Id id1, Id id2);
-extern void queue_insertn(Queue *q, int pos, int n, Id *elements);
-extern void queue_delete(Queue *q, int pos);
-extern void queue_delete2(Queue *q, int pos);
-extern void queue_deleten(Queue *q, int pos, int n);
-extern void queue_prealloc(Queue *q, int n);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_QUEUE_H */
diff --git a/libsolv-0.6.15/src/repo.c b/libsolv-0.6.15/src/repo.c
deleted file mode 100644 (file)
index 15e7e80..0000000
+++ /dev/null
@@ -1,1823 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo.c
- *
- * Manage metadata coming from one repository
- *
- */
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <fnmatch.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-
-
-
-#include "repo.h"
-#include "pool.h"
-#include "poolid_private.h"
-#include "util.h"
-#include "chksum.h"
-
-#define IDARRAY_BLOCK     4095
-
-
-/*
- * create empty repo
- * and add to pool
- */
-
-Repo *
-repo_create(Pool *pool, const char *name)
-{
-  Repo *repo;
-
-  pool_freewhatprovides(pool);
-  repo = (Repo *)solv_calloc(1, sizeof(*repo));
-  if (!pool->nrepos)
-    {
-      pool->nrepos = 1;        /* start with repoid 1 */
-      pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *));
-    }
-  else
-    pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
-  pool->repos[pool->nrepos] = repo;
-  pool->urepos++;
-  repo->repoid = pool->nrepos++;
-  repo->name = name ? solv_strdup(name) : 0;
-  repo->pool = pool;
-  repo->start = pool->nsolvables;
-  repo->end = pool->nsolvables;
-  repo->nsolvables = 0;
-  return repo;
-}
-
-void
-repo_freedata(Repo *repo)
-{
-  int i;
-  for (i = 1; i < repo->nrepodata; i++)
-    repodata_freedata(repo->repodata + i);
-  solv_free(repo->repodata);
-  solv_free(repo->idarraydata);
-  solv_free(repo->rpmdbid);
-  solv_free(repo->lastidhash);
-  solv_free((char *)repo->name);
-  solv_free(repo);
-}
-
-/* delete all solvables and repodata blocks from this repo */
-
-void
-repo_empty(Repo *repo, int reuseids)
-{
-  Pool *pool = repo->pool;
-  Solvable *s;
-  int i;
-
-  pool_freewhatprovides(pool);
-  if (reuseids && repo->end == pool->nsolvables)
-    {
-      /* it's ok to reuse the ids. As this is the last repo, we can
-         just shrink the solvable array */
-      for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
-       if (s->repo != repo)
-         break;
-      pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids);
-      repo->end = i + 1;
-    }
-  /* zero out (i.e. free) solvables belonging to this repo */
-  for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
-    if (s->repo == repo)
-      memset(s, 0, sizeof(*s));
-  repo->end = repo->start;
-  repo->nsolvables = 0;
-
-  /* free all data belonging to this repo */
-  repo->idarraydata = solv_free(repo->idarraydata);
-  repo->idarraysize = 0;
-  repo->lastoff = 0;
-  repo->rpmdbid = solv_free(repo->rpmdbid);
-  for (i = 1; i < repo->nrepodata; i++)
-    repodata_freedata(repo->repodata + i);
-  solv_free(repo->repodata);
-  repo->repodata = 0;
-  repo->nrepodata = 0;
-}
-
-/*
- * remove repo from pool, delete solvables
- *
- */
-
-void
-repo_free(Repo *repo, int reuseids)
-{
-  Pool *pool = repo->pool;
-  int i;
-
-  if (repo == pool->installed)
-    pool->installed = 0;
-  repo_empty(repo, reuseids);
-  for (i = 1; i < pool->nrepos; i++)   /* find repo in pool */
-    if (pool->repos[i] == repo)
-      break;
-  if (i == pool->nrepos)              /* repo not in pool, return */
-    return;
-  if (i == pool->nrepos - 1 && reuseids)
-    pool->nrepos--;
-  else
-    pool->repos[i] = 0;
-  pool->urepos--;
-  repo_freedata(repo);
-}
-
-Id
-repo_add_solvable(Repo *repo)
-{
-  Id p = pool_add_solvable(repo->pool);
-  if (!repo->start || repo->start == repo->end)
-    repo->start = repo->end = p;
-  /* warning: sidedata must be extended before adapting start/end */
-  if (repo->rpmdbid)
-    repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, 1);
-  if (p < repo->start)
-    repo->start = p;
-  if (p + 1 > repo->end)
-    repo->end = p + 1;
-  repo->nsolvables++;
-  repo->pool->solvables[p].repo = repo;
-  return p;
-}
-
-Id
-repo_add_solvable_block(Repo *repo, int count)
-{
-  Id p;
-  Solvable *s;
-  if (!count)
-    return 0;
-  p = pool_add_solvable_block(repo->pool, count);
-  if (!repo->start || repo->start == repo->end)
-    repo->start = repo->end = p;
-  /* warning: sidedata must be extended before adapting start/end */
-  if (repo->rpmdbid)
-    repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
-  if (p < repo->start)
-    repo->start = p;
-  if (p + count > repo->end)
-    repo->end = p + count;
-  repo->nsolvables += count;
-  for (s = repo->pool->solvables + p; count--; s++)
-    s->repo = repo;
-  return p;
-}
-
-void
-repo_free_solvable(Repo *repo, Id p, int reuseids)
-{
-  repo_free_solvable_block(repo, p, 1, reuseids);
-}
-
-void
-repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids)
-{
-  Solvable *s;
-  Repodata *data;
-  int i;
-  if (start + count == repo->end)
-    repo->end -= count;
-  repo->nsolvables -= count;
-  for (s = repo->pool->solvables + start, i = count; i--; s++)
-    s->repo = 0;
-  pool_free_solvable_block(repo->pool, start, count, reuseids);
-  FOR_REPODATAS(repo, i, data)
-    {
-      int dstart, dend;
-      if (data->end > repo->end)
-        repodata_shrink(data, repo->end);
-      dstart = data->start > start ? data->start : start;
-      dend = data->end < start + count ? data->end : start + count;
-      if (dstart < dend)
-       {
-         if (data->attrs)
-           {
-             int j;
-             for (j = dstart; j < dend; j++)   
-               data->attrs[j - data->start] = solv_free(data->attrs[j - data->start]);
-           }
-         if (data->incoreoffset)
-           memset(data->incoreoffset + (dstart - data->start), 0, (dend - dstart) * sizeof(Id));
-       }
-    }
-}
-
-/* specialized version of repo_add_solvable_block that inserts the new solvable
- * block before the indicated repo, which gets relocated.
- * used in repo_add_rpmdb
- */
-Id
-repo_add_solvable_block_before(Repo *repo, int count, Repo *beforerepo)
-{
-  Pool *pool = repo->pool;
-  Id p;
-  Solvable *s;
-  Repodata *data;
-  int i;
-
-  if (!count || !beforerepo || beforerepo->end != pool->nsolvables || beforerepo->start == beforerepo->end)
-    return repo_add_solvable_block(repo, count);
-  p = beforerepo->start;
-  /* make sure all solvables belong to beforerepo */
-  for (i = p, s = pool->solvables + i; i < beforerepo->end; i++, s++)
-    if (s->repo && s->repo != beforerepo)
-      return repo_add_solvable_block(repo, count);
-  /* now move beforerepo to back */
-  pool_add_solvable_block(pool, count);        /* must return beforerepo->end! */
-  memmove(pool->solvables + p + count, pool->solvables + p, (beforerepo->end - p) * sizeof(Solvable));
-  memset(pool->solvables + p, 0, sizeof(Solvable) * count);
-  /* adapt repodata */
-  FOR_REPODATAS(beforerepo, i, data)
-    {
-      if (data->start < p)
-       continue;
-      data->start += count;
-      data->end += count;
-    }
-  beforerepo->start += count;
-  beforerepo->end += count;
-  /* we now have count free solvables at id p */
-  /* warning: sidedata must be extended before adapting start/end */
-  if (repo->rpmdbid)
-    repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
-  if (p < repo->start)
-    repo->start = p;
-  if (p + count > repo->end)
-    repo->end = p + count;
-  repo->nsolvables += count;
-  for (s = pool->solvables + p; count--; s++)
-    s->repo = repo;
-  return p;
-}
-
-
-/* repository sidedata is solvable data allocated on demand.
- * It is used for data that is normally not present
- * in the solvable like the rpmdbid.
- * The solvable allocation funcions need to make sure that
- * the sidedata gets extended if new solvables get added.
- */
-
-#define REPO_SIDEDATA_BLOCK 63
-
-void *
-repo_sidedata_create(Repo *repo, size_t size)
-{
-  return solv_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
-}
-
-void *
-repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
-{
-  int n = repo->end - repo->start;
-  if (p < repo->start)
-    {
-      int d = repo->start - p;
-      b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
-      memmove((char *)b + d * size, b, n * size);
-      memset(b, 0, d * size);
-      n += d;
-    }
-  if (p + count > repo->end)
-    {
-      int d = p + count - repo->end;
-      b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
-      memset((char *)b + n * size, 0, d * size);
-    }
-  return b;
-}
-
-/*
- * add Id to idarraydata used to store dependencies
- * olddeps: old array offset to extend
- * returns new array offset
- */
-
-Offset
-repo_addid(Repo *repo, Offset olddeps, Id id)
-{
-  Id *idarray;
-  int idarraysize;
-  int i;
-
-  idarray = repo->idarraydata;
-  idarraysize = repo->idarraysize;
-
-  if (!idarray)                               /* alloc idarray if not done yet */
-    {
-      idarraysize = 1;
-      idarray = solv_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
-      idarray[0] = 0;
-      repo->lastoff = 0;
-    }
-
-  if (!olddeps)                                /* no deps yet */
-    {
-      olddeps = idarraysize;
-      idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
-    }
-  else if (olddeps == repo->lastoff)   /* extend at end */
-    idarraysize--;
-  else                                 /* can't extend, copy old */
-    {
-      i = olddeps;
-      olddeps = idarraysize;
-      for (; idarray[i]; i++)
-        {
-         idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
-          idarray[idarraysize++] = idarray[i];
-        }
-      idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
-    }
-
-  idarray[idarraysize++] = id;         /* insert Id into array */
-  idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
-  idarray[idarraysize++] = 0;          /* ensure NULL termination */
-
-  repo->idarraydata = idarray;
-  repo->idarraysize = idarraysize;
-  repo->lastoff = olddeps;
-
-  return olddeps;
-}
-
-#define REPO_ADDID_DEP_HASHTHRES       64
-#define REPO_ADDID_DEP_HASHMIN         128
-
-/*
- * Optimization for packages with an excessive amount of provides/requires:
- * if the number of deps exceed a threshold, we build a hash of the already
- * seen ids.
- */
-static Offset
-repo_addid_dep_hash(Repo *repo, Offset olddeps, Id id, Id marker, int size)
-{
-  Id oid, *oidp;
-  int before;
-  Hashval h, hh;
-  Id hid;
-
-  before = 0;
-  if (marker)
-    {
-      if (marker < 0)
-       {
-         marker = -marker;
-         before = 1;
-       }
-      if (marker == id)
-       marker = 0;
-    }
-
-  /* maintain hash and lastmarkerpos */
-  if (repo->lastidhash_idarraysize != repo->idarraysize || (Hashval)size * 2 > repo->lastidhash_mask || repo->lastmarker != marker)
-    {
-      repo->lastmarkerpos = 0;
-      if (size * 2 > (Hashval)repo->lastidhash_mask)
-       {
-         repo->lastidhash_mask = mkmask(size < REPO_ADDID_DEP_HASHMIN ? REPO_ADDID_DEP_HASHMIN : size);
-         repo->lastidhash = solv_realloc2(repo->lastidhash, repo->lastidhash_mask + 1, sizeof(Id));
-       }
-      memset(repo->lastidhash, 0, (repo->lastidhash_mask + 1) * sizeof(Id));
-      for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
-       {
-         h = oid & repo->lastidhash_mask;
-         hh = HASHCHAIN_START;
-         while (repo->lastidhash[h] != 0)
-           h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
-         repo->lastidhash[h] = oid;
-         if (marker && oid == marker)
-           repo->lastmarkerpos = oidp - repo->idarraydata;
-       }
-      repo->lastmarker = marker;
-      repo->lastidhash_idarraysize = repo->idarraysize;
-    }
-
-  /* check the hash! */
-  h = id & repo->lastidhash_mask;
-  hh = HASHCHAIN_START;
-  while ((hid = repo->lastidhash[h]) != 0 && hid != id)
-    h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
-  /* put new element in hash */
-  if (!hid)
-    repo->lastidhash[h] = id;
-  else if (marker == SOLVABLE_FILEMARKER && (!before || !repo->lastmarkerpos))
-    return olddeps;
-  if (marker && !before && !repo->lastmarkerpos)
-    {
-      /* we have to add the marker first */
-      repo->lastmarkerpos = repo->idarraysize - 1;
-      olddeps = repo_addid(repo, olddeps, marker);
-      /* now put marker in hash */
-      h = marker & repo->lastidhash_mask;
-      hh = HASHCHAIN_START;
-      while (repo->lastidhash[h] != 0)
-       h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
-      repo->lastidhash[h] = marker;
-      repo->lastidhash_idarraysize = repo->idarraysize;
-    }
-  if (!hid)
-    {
-      /* new entry, insert in correct position */
-      if (marker && before && repo->lastmarkerpos)
-       {
-         /* need to add it before the marker */
-         olddeps = repo_addid(repo, olddeps, id);      /* dummy to make room */
-         memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (repo->idarraysize - repo->lastmarkerpos - 2) * sizeof(Id));
-         repo->idarraydata[repo->lastmarkerpos++] = id;
-       }
-      else
-       {
-         /* just append it to the end */
-         olddeps = repo_addid(repo, olddeps, id);
-       }
-      repo->lastidhash_idarraysize = repo->idarraysize;
-      return olddeps;
-    }
-  /* we already have it in the hash */
-  if (!marker)
-    return olddeps;
-  if (marker == SOLVABLE_FILEMARKER)
-    {
-      /* check if it is in the wrong half */
-      /* (we already made sure that "before" and "lastmarkerpos" are set, see above) */
-      for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
-       if (oid == id)
-         break;
-      if (!oid)
-       return olddeps;
-      /* yes, wrong half. copy it over */
-      memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (oidp - (repo->idarraydata + repo->lastmarkerpos)) * sizeof(Id));
-      repo->idarraydata[repo->lastmarkerpos++] = id;
-      return olddeps;
-    }
-  if (before)
-    return olddeps;
-  /* check if it is in the correct half */
-  for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
-    if (oid == id)
-      return olddeps;
-  /* nope, copy it over */
-  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
-    if (oid == id)
-      break;
-  if (!oid)
-    return olddeps;    /* should not happen */
-  memmove(oidp, oidp + 1, (repo->idarraydata + repo->idarraysize - oidp - 2) * sizeof(Id));
-  repo->idarraydata[repo->idarraysize - 2] = id;
-  repo->lastmarkerpos--;       /* marker has been moved */
-  return olddeps;
-}
-
-/*
- * add dependency (as Id) to repo, also unifies dependencies
- * olddeps = offset into idarraydata
- * marker= 0 for normal dep
- * marker > 0 add dep after marker
- * marker < 0 add dep before -marker
- * returns new start of dependency array
- */
-Offset
-repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
-{
-  Id oid, *oidp, *markerp;
-  int before;
-
-  if (!olddeps)
-    {
-      if (marker > 0)
-       olddeps = repo_addid(repo, olddeps, marker);
-      return repo_addid(repo, olddeps, id);
-    }
-
-  /* check if we should use the hash optimization */
-  if (olddeps == repo->lastoff)
-    {
-      int size = repo->idarraysize - 1 - repo->lastoff;
-      if (size >= REPO_ADDID_DEP_HASHTHRES)
-        return repo_addid_dep_hash(repo, olddeps, id, marker, size);
-    }
-
-  before = 0;
-  if (marker)
-    {
-      if (marker < 0)
-       {
-         marker = -marker;
-         before = 1;
-       }
-      if (marker == id)
-       marker = 0;
-    }
-
-  if (!marker)
-    {
-      for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
-        if (oid == id)
-         return olddeps;
-      return repo_addid(repo, olddeps, id);
-    }
-
-  markerp = 0;
-  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
-    {
-      if (oid == marker)
-       markerp = oidp;
-      else if (oid == id)
-       break;
-    }
-
-  if (oid)
-    {
-      if (marker == SOLVABLE_FILEMARKER)
-       {
-         if (!markerp || !before)
-            return olddeps;
-          /* we found it, but in the second half */
-          memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
-          *markerp = id;
-          return olddeps;
-       }
-      if (markerp || before)
-        return olddeps;
-      /* we found it, but in the first half */
-      markerp = oidp++;
-      for (; (oid = *oidp) != 0; oidp++)
-        if (oid == marker)
-          break;
-      if (!oid)
-        {
-         /* no marker in array yet */
-          oidp--;
-          if (markerp < oidp)
-            memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
-          *oidp = marker;
-          return repo_addid(repo, olddeps, id);
-        }
-      while (oidp[1])
-        oidp++;
-      memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
-      *oidp = id;
-      return olddeps;
-    }
-  /* id not yet in array */
-  if (!before && !markerp)
-    olddeps = repo_addid(repo, olddeps, marker);
-  else if (before && markerp)
-    {
-      *markerp++ = id;
-      id = *--oidp;
-      if (markerp < oidp)
-        memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
-      *markerp = marker;
-    }
-  return repo_addid(repo, olddeps, id);
-}
-
-/* return standard marker for the keyname dependency.
- * 1: return positive marker, -1: return negative marker
- */
-Id
-solv_depmarker(Id keyname, Id marker)
-{
-  if (marker != 1 && marker != -1)
-    return marker;
-  if (keyname == SOLVABLE_PROVIDES)
-    return marker < 0 ? -SOLVABLE_FILEMARKER : SOLVABLE_FILEMARKER;
-  if (keyname == SOLVABLE_REQUIRES)
-    return marker < 0 ? -SOLVABLE_PREREQMARKER : SOLVABLE_PREREQMARKER;
-  return 0;
-}
-
-/*
- * reserve Ids
- * make space for 'num' more dependencies
- * returns new start of dependency array
- *
- * reserved ids will always begin at offset idarraysize
- */
-Offset
-repo_reserve_ids(Repo *repo, Offset olddeps, int num)
-{
-  num++;       /* room for trailing ID_NULL */
-
-  if (!repo->idarraysize)             /* ensure buffer space */
-    {
-      repo->idarraysize = 1;
-      repo->idarraydata = solv_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
-      repo->idarraydata[0] = 0;
-      repo->lastoff = 1;
-      return 1;
-    }
-
-  if (olddeps && olddeps != repo->lastoff)   /* if not appending */
-    {
-      /* can't insert into idarray, this would invalidate all 'larger' offsets
-       * so create new space at end and move existing deps there.
-       * Leaving 'hole' at old position.
-       */
-
-      Id *idstart, *idend;
-      int count;
-
-      for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
-       ;
-      count = idend - idstart - 1 + num;              /* new size */
-
-      repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
-      /* move old deps to end */
-      olddeps = repo->lastoff = repo->idarraysize;
-      memcpy(repo->idarraydata + olddeps, idstart, count - num);
-      repo->idarraysize = olddeps + count - num;
-
-      return olddeps;
-    }
-
-  if (olddeps)                        /* appending */
-    repo->idarraysize--;
-
-  /* make room*/
-  repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
-
-  /* appending or new */
-  repo->lastoff = olddeps ? olddeps : repo->idarraysize;
-
-  return repo->lastoff;
-}
-
-
-/***********************************************************************/
-
-/*
- * some SUSE specific fixups, should go into a separate file
- */
-
-Offset
-repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
-{
-  Pool *pool = repo->pool;
-  Id id, idp, idl;
-  char buf[1024], *p, *dep;
-  int i, l;
-
-  if (provides)
-    {
-      for (i = provides; repo->idarraydata[i]; i++)
-       {
-         id = repo->idarraydata[i];
-         if (ISRELDEP(id))
-           continue;
-         dep = (char *)pool_id2str(pool, id);
-         if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
-           {
-             idp = 0;
-             strcpy(buf + 2, dep);
-             dep = buf + 2 + 7;
-             if ((p = strchr(dep, ':')) != 0 && p != dep)
-               {
-                 *p++ = 0;
-                 idp = pool_str2id(pool, dep, 1);
-                 dep = p;
-               }
-             id = 0;
-             while ((p = strchr(dep, ';')) != 0)
-               {
-                 if (p == dep)
-                   {
-                     dep = p + 1;
-                     continue;
-                   }
-                 *p++ = 0;
-                 idl = pool_str2id(pool, dep, 1);
-                 idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
-                 if (id)
-                   id = pool_rel2id(pool, id, idl, REL_OR, 1);
-                 else
-                   id = idl;
-                 dep = p;
-               }
-             if (dep[0] && dep[1])
-               {
-                 for (p = dep; *p && *p != ')'; p++)
-                   ;
-                 *p = 0;
-                 idl = pool_str2id(pool, dep, 1);
-                 idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
-                 if (id)
-                   id = pool_rel2id(pool, id, idl, REL_OR, 1);
-                 else
-                   id = idl;
-               }
-             if (idp)
-               id = pool_rel2id(pool, idp, id, REL_AND, 1);
-             if (id)
-               supplements = repo_addid_dep(repo, supplements, id, 0);
-           }
-         else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
-           {
-             strcpy(buf, dep);
-             p = buf + (p - dep);
-             *p++ = 0;
-             idp = pool_str2id(pool, buf, 1);
-             /* strip trailing slashes */
-             l = strlen(p);
-             while (l > 1 && p[l - 1] == '/')
-               p[--l] = 0;
-             id = pool_str2id(pool, p, 1);
-             id = pool_rel2id(pool, idp, id, REL_WITH, 1);
-             id = pool_rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
-             supplements = repo_addid_dep(repo, supplements, id, 0);
-           }
-       }
-    }
-  if (supplements)
-    {
-      for (i = supplements; repo->idarraydata[i]; i++)
-       {
-         id = repo->idarraydata[i];
-         if (ISRELDEP(id))
-           continue;
-         dep = (char *)pool_id2str(pool, id);
-         if (!strncmp(dep, "system:modalias(", 16))
-           dep += 7;
-         if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
-           {
-             strcpy(buf, dep);
-             p = strchr(buf + 9, ':');
-             if (p && p != buf + 9 && strchr(p + 1, ':'))
-               {
-                 *p++ = 0;
-                 idp = pool_str2id(pool, buf + 9, 1);
-                 p[strlen(p) - 1] = 0;
-                 id = pool_str2id(pool, p, 1);
-                 id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
-                 id = pool_rel2id(pool, idp, id, REL_AND, 1);
-               }
-             else
-               {
-                 p = buf + 9;
-                 p[strlen(p) - 1] = 0;
-                 id = pool_str2id(pool, p, 1);
-                 id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
-               }
-             if (id)
-               repo->idarraydata[i] = id;
-           }
-         else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
-           {
-             strcpy(buf, dep);
-             id = 0;
-             dep = buf + 11;
-             while ((p = strchr(dep, ':')) != 0)
-               {
-                 if (p == dep)
-                   {
-                     dep = p + 1;
-                     continue;
-                   }
-                 /* argh, allow pattern: prefix. sigh */
-                 if (p - dep == 7 && !strncmp(dep, "pattern", 7))
-                   {
-                     p = strchr(p + 1, ':');
-                     if (!p)
-                       break;
-                   }
-                 *p++ = 0;
-                 idp = pool_str2id(pool, dep, 1);
-                 if (id)
-                   id = pool_rel2id(pool, id, idp, REL_AND, 1);
-                 else
-                   id = idp;
-                 dep = p;
-               }
-             if (dep[0] && dep[1])
-               {
-                 dep[strlen(dep) - 1] = 0;
-                 idp = pool_str2id(pool, dep, 1);
-                 if (id)
-                   id = pool_rel2id(pool, id, idp, REL_AND, 1);
-                 else
-                   id = idp;
-               }
-             if (id)
-               repo->idarraydata[i] = id;
-           }
-         else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
-           {
-             strcpy(buf, dep + 11);
-             if ((p = strrchr(buf, ')')) != 0)
-               *p = 0;
-             id = pool_str2id(pool, buf, 1);
-             id = pool_rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
-             repo->idarraydata[i] = id;
-           }
-       }
-    }
-  if (freshens && repo->idarraydata[freshens])
-    {
-      Id idsupp = 0, idfresh = 0;
-      if (!supplements || !repo->idarraydata[supplements])
-       return freshens;
-      for (i = supplements; repo->idarraydata[i]; i++)
-        {
-         if (!idsupp)
-           idsupp = repo->idarraydata[i];
-         else
-           idsupp = pool_rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
-        }
-      for (i = freshens; repo->idarraydata[i]; i++)
-        {
-         if (!idfresh)
-           idfresh = repo->idarraydata[i];
-         else
-           idfresh = pool_rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
-        }
-      if (!idsupp)
-        idsupp = idfresh;
-      else
-       idsupp = pool_rel2id(pool, idsupp, idfresh, REL_AND, 1);
-      supplements = repo_addid_dep(repo, 0, idsupp, 0);
-    }
-  return supplements;
-}
-
-Offset
-repo_fix_conflicts(Repo *repo, Offset conflicts)
-{
-  char buf[1024], *p, *dep;
-  Pool *pool = repo->pool;
-  Id id;
-  int i;
-
-  if (!conflicts)
-    return conflicts;
-  for (i = conflicts; repo->idarraydata[i]; i++)
-    {
-      id = repo->idarraydata[i];
-      if (ISRELDEP(id))
-       continue;
-      dep = (char *)pool_id2str(pool, id);
-      if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2)
-       {
-         strcpy(buf, dep + 15);
-         if ((p = strchr(buf, ')')) != 0)
-           *p = 0;
-         id = pool_str2id(pool, buf, 1);
-         id = pool_rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
-         repo->idarraydata[i] = id;
-       }
-    }
-  return conflicts;
-}
-
-/***********************************************************************/
-
-struct matchdata
-{
-  Pool *pool;
-  int flags;
-  Datamatcher matcher;
-  int stop;
-  int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
-  void *callback_data;
-};
-
-int
-repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  struct matchdata *md = cbdata;
-
-  if (md->matcher.match)
-    {
-      const char *str;
-      if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0)
-       if (!datamatcher_checkbasename(&md->matcher, kv->str))
-         return 0;
-      if (!(str = repodata_stringify(md->pool, data, key, kv, md->flags)))
-       return 0;
-      if (!datamatcher_match(&md->matcher, str))
-       return 0;
-    }
-  md->stop = md->callback(md->callback_data, s, data, key, kv);
-  return md->stop;
-}
-
-
-/* list of all keys we store in the solvable */
-/* also used in the dataiterator code in repodata.c */
-Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
-  { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
-  { RPM_RPMDBID,          REPOKEY_TYPE_NUM, 0, KEY_STORAGE_SOLVABLE },
-};
-
-static void
-domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
-{
-  KeyValue kv;
-  kv.entry = 0;
-  kv.parent = 0;
-  for (; *ida && !md->stop; ida++)
-    {
-      kv.id = *ida;
-      kv.eof = ida[1] ? 0 : 1;
-      repo_matchvalue(md, s, 0, repo_solvablekeys + (keyname - SOLVABLE_NAME), &kv);
-      kv.entry++;
-    }
-}
-
-static void
-repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
-{
-  KeyValue kv;
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i, j, flags;
-  Solvable *s;
-
-  kv.parent = 0;
-  md->stop = 0;
-  if (!p)
-    {
-      for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
-       {
-         if (s->repo == repo)
-            repo_search_md(repo, p, keyname, md);
-         if (md->stop > SEARCH_NEXT_SOLVABLE)
-           break;
-       }
-      return;
-    }
-  else if (p < 0)
-    /* The callback only supports solvables, so we can't iterate over the
-       extra things.  */
-    return;
-  flags = md->flags;
-  if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
-    {
-      s = pool->solvables + p;
-      switch(keyname)
-       {
-         case 0:
-         case SOLVABLE_NAME:
-           if (s->name)
-             {
-               kv.id = s->name;
-               repo_matchvalue(md, s, 0, repo_solvablekeys + 0, &kv);
-             }
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_ARCH:
-           if (s->arch)
-             {
-               kv.id = s->arch;
-               repo_matchvalue(md, s, 0, repo_solvablekeys + 1, &kv);
-             }
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_EVR:
-           if (s->evr)
-             {
-               kv.id = s->evr;
-               repo_matchvalue(md, s, 0, repo_solvablekeys + 2, &kv);
-             }
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_VENDOR:
-           if (s->vendor)
-             {
-               kv.id = s->vendor;
-               repo_matchvalue(md, s, 0, repo_solvablekeys + 3, &kv);
-             }
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_PROVIDES:
-           if (s->provides)
-             domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_OBSOLETES:
-           if (s->obsoletes)
-             domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_CONFLICTS:
-           if (s->conflicts)
-             domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_REQUIRES:
-           if (s->requires)
-             domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_RECOMMENDS:
-           if (s->recommends)
-             domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_SUPPLEMENTS:
-           if (s->supplements)
-             domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_SUGGESTS:
-           if (s->suggests)
-             domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case SOLVABLE_ENHANCES:
-           if (s->enhances)
-             domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-         case RPM_RPMDBID:
-           if (repo->rpmdbid)
-             {
-               kv.num = repo->rpmdbid[p - repo->start];
-               kv.num2 = 0;
-               repo_matchvalue(md, s, 0, repo_solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
-             }
-           if (keyname || md->stop > SEARCH_NEXT_KEY)
-             return;
-           break;
-         default:
-           break;
-       }
-    }
-
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (p < data->start || p >= data->end)
-       continue;
-      if (keyname && !repodata_precheck_keyname(data, keyname))
-       continue;
-      if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST))
-       {
-         /* do not search filelist extensions */
-         if (data->state != REPODATA_AVAILABLE)
-           continue;
-         for (j = 1; j < data->nkeys; j++)
-           if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-             break;
-         if (j == data->nkeys)
-           continue;
-       }
-      if (data->state == REPODATA_STUB)
-       {
-         if (keyname)
-           {
-             for (j = 1; j < data->nkeys; j++)
-               if (keyname == data->keys[j].name)
-                 break;
-             if (j == data->nkeys)
-               continue;
-           }
-         /* load it */
-         if (data->loadcallback)
-           data->loadcallback(data);
-         else
-            data->state = REPODATA_ERROR;
-       }
-      if (data->state == REPODATA_ERROR)
-       continue;
-      repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
-      if (md->stop > SEARCH_NEXT_KEY)
-       break;
-    }
-}
-
-void
-repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
-{
-  struct matchdata md;
-
-  if (repo->disabled && !(flags & SEARCH_DISABLED_REPOS))
-    return;
-  memset(&md, 0, sizeof(md));
-  md.pool = repo->pool;
-  md.flags = flags;
-  md.callback = callback;
-  md.callback_data = cbdata;
-  if (match)
-    datamatcher_init(&md.matcher, match, flags);
-  repo_search_md(repo, p, keyname, &md);
-  if (match)
-    datamatcher_free(&md.matcher);
-}
-
-const char *
-repo_lookup_str(Repo *repo, Id entry, Id keyname)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  const char *str;
-
-  if (entry >= 0)
-    {
-      switch (keyname)
-       {
-       case SOLVABLE_NAME:
-         return pool_id2str(pool, pool->solvables[entry].name);
-       case SOLVABLE_ARCH:
-         return pool_id2str(pool, pool->solvables[entry].arch);
-       case SOLVABLE_EVR:
-         return pool_id2str(pool, pool->solvables[entry].evr);
-       case SOLVABLE_VENDOR:
-         return pool_id2str(pool, pool->solvables[entry].vendor);
-       }
-    }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      str = repodata_lookup_str(data, entry, keyname);
-      if (str)
-       return str;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
-  return 0;
-}
-
-
-unsigned long long
-repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  unsigned long long value;
-
-  if (entry >= 0)
-    {
-      if (keyname == RPM_RPMDBID)
-       {
-         if (repo->rpmdbid && entry >= repo->start && entry < repo->end)
-           return repo->rpmdbid[entry - repo->start];
-         return notfound;
-       }
-    }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, &value) ? value : notfound;
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      if (repodata_lookup_num(data, entry, keyname, &value))
-       return value;
-      if (repodata_lookup_type(data, entry, keyname))
-       return notfound;
-    }
-  return notfound;
-}
-
-Id
-repo_lookup_id(Repo *repo, Id entry, Id keyname)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  Id id;
-
-  if (entry >= 0)
-    {
-      switch (keyname)
-       {
-       case SOLVABLE_NAME:
-         return repo->pool->solvables[entry].name;
-       case SOLVABLE_ARCH:
-         return repo->pool->solvables[entry].arch;
-       case SOLVABLE_EVR:
-         return repo->pool->solvables[entry].evr;
-       case SOLVABLE_VENDOR:
-         return repo->pool->solvables[entry].vendor;
-       }
-    }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    {
-      Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
-      Id id = repodata_lookup_id(data, entry, keyname);
-      return data->localpool ? repodata_globalize_id(data, id, 1) : id;
-    }
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      id = repodata_lookup_id(data, entry, keyname);
-      if (id)
-       return data->localpool ? repodata_globalize_id(data, id, 1) : id;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
-  return 0;
-}
-
-static int
-lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
-{
-  Id *p;
-
-  queue_empty(q);
-  if (off)
-    for (p = repo->idarraydata + off; *p; p++)
-      queue_push(q, *p);
-  return 1;
-}
-
-int
-repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  if (entry >= 0)
-    {
-      switch (keyname)
-        {
-       case SOLVABLE_PROVIDES:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q);
-       case SOLVABLE_OBSOLETES:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q);
-       case SOLVABLE_CONFLICTS:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q);
-       case SOLVABLE_REQUIRES:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q);
-       case SOLVABLE_RECOMMENDS:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q);
-       case SOLVABLE_SUGGESTS:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q);
-       case SOLVABLE_SUPPLEMENTS:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q);
-       case SOLVABLE_ENHANCES:
-         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
-        }
-    }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    {
-      Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
-      if (repodata_lookup_idarray(data, entry, keyname, q))
-       {
-         if (data->localpool)
-           {
-             for (i = 0; i < q->count; i++)
-               q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
-           }
-         return 1;
-       }
-    }
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      if (repodata_lookup_idarray(data, entry, keyname, q))
-       {
-         if (data->localpool)
-           {
-             for (i = 0; i < q->count; i++)
-               q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
-           }
-         return 1;
-       }
-      if (repodata_lookup_type(data, entry, keyname))
-       break;
-    }
-  queue_empty(q);
-  return 0;
-}
-
-int
-repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker)
-{
-  int r = repo_lookup_idarray(repo, entry, keyname, q);
-  if (!r)
-    return 0;
-  if (marker == -1 || marker == 1)
-    marker = solv_depmarker(keyname, marker);
-  if (marker && q->count)
-    {
-      int i;
-      if (marker < 0)
-       {
-         marker = -marker;
-         for (i = 0; i < q->count; i++)
-           if (q->elements[i] == marker)
-             {
-               queue_truncate(q, i);
-               return r;
-             }
-       }
-      else
-       {
-         for (i = 0; i < q->count; i++)
-           if (q->elements[i] == marker)
-             {
-               queue_deleten(q, 0, i + 1);
-               return r;
-             }
-         queue_empty(q);
-       }
-    }
-  return r;
-}
-
-const unsigned char *
-repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  const unsigned char *chk;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, typep);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
-      if (chk)
-       return chk;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
-  *typep = 0;
-  return 0;
-}
-
-const char *
-repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
-{
-  const unsigned char *chk = repo_lookup_bin_checksum(repo, entry, keyname, typep);
-  return chk ? pool_bin2hex(repo->pool, chk, solv_chksum_len(*typep)) : 0;
-}
-
-int
-repo_lookup_void(Repo *repo, Id entry, Id keyname)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  Id type;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      type = repodata_lookup_type(data, entry, keyname);
-      if (type)
-       return type == REPOKEY_TYPE_VOID;
-    }
-  return 0;
-}
-
-Id
-repo_lookup_type(Repo *repo, Id entry, Id keyname)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  Id type;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_type(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      type = repodata_lookup_type(data, entry, keyname);
-      if (type)
-       return type == REPOKEY_TYPE_DELETED ? 0 : type;
-    }
-  return 0;
-}
-
-const void *
-repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp)
-{
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  const void *bin;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_binary(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, lenp);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      bin = repodata_lookup_binary(data, entry, keyname, lenp);
-      if (bin)
-       return bin;
-    }
-  *lenp = 0;
-  return 0;
-}
-
-/***********************************************************************/
-
-Repodata *
-repo_add_repodata(Repo *repo, int flags)
-{
-  Repodata *data;
-  int i;
-  if ((flags & REPO_USE_LOADING) != 0)
-    {
-      for (i = repo->nrepodata - 1; i > 0; i--)
-       if (repo->repodata[i].state == REPODATA_LOADING)
-         {
-           Repodata *data = repo->repodata + i;
-           /* re-init */
-           /* hack: we mis-use REPO_REUSE_REPODATA here */
-           if (!(flags & REPO_REUSE_REPODATA))
-             repodata_empty(data, (flags & REPO_LOCALPOOL) ? 1 : 0);
-           return data;
-         }
-      return 0;        /* must not create a new repodata! */
-    }
-  if ((flags & REPO_REUSE_REPODATA) != 0)
-    {
-      for (i = repo->nrepodata - 1; i > 0; i--)
-       if (repo->repodata[i].state != REPODATA_STUB)
-         return repo->repodata + i;
-    }
-  if (!repo->nrepodata)
-    {
-      repo->nrepodata = 2;      /* start with id 1 */
-      repo->repodata = solv_calloc(repo->nrepodata, sizeof(*data));
-    }
-  else
-    {
-      repo->nrepodata++;
-      repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
-    }
-  data = repo->repodata + repo->nrepodata - 1;
-  repodata_initdata(data, repo, (flags & REPO_LOCALPOOL) ? 1 : 0);
-  return data;
-}
-
-Repodata *
-repo_id2repodata(Repo *repo, Id id)
-{
-  return id ? repo->repodata + id : 0;
-}
-
-Repodata *
-repo_last_repodata(Repo *repo)
-{
-  int i;
-  for (i = repo->nrepodata - 1; i > 0; i--)
-    if (repo->repodata[i].state != REPODATA_STUB)
-      return repo->repodata + i;
-  return repo_add_repodata(repo, 0);
-}
-
-void
-repo_set_id(Repo *repo, Id p, Id keyname, Id id)
-{
-  Repodata *data;
-  if (p >= 0)
-    {
-      switch (keyname)
-       {
-       case SOLVABLE_NAME:
-         repo->pool->solvables[p].name = id;
-         return;
-       case SOLVABLE_ARCH:
-         repo->pool->solvables[p].arch = id;
-         return;
-       case SOLVABLE_EVR:
-         repo->pool->solvables[p].evr = id;
-         return;
-       case SOLVABLE_VENDOR:
-         repo->pool->solvables[p].vendor = id;
-         return;
-       }
-    }
-  data = repo_last_repodata(repo);
-  if (data->localpool)
-    id = repodata_localize_id(data, id, 1);
-  repodata_set_id(data, p, keyname, id);
-}
-
-void
-repo_set_num(Repo *repo, Id p, Id keyname, unsigned long long num)
-{
-  Repodata *data;
-  if (p >= 0)
-    {
-      if (keyname == RPM_RPMDBID)
-       {
-         if (!repo->rpmdbid)
-           repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
-         repo->rpmdbid[p - repo->start] = num;
-         return;
-       }
-    }
-  data = repo_last_repodata(repo);
-  repodata_set_num(data, p, keyname, num);
-}
-
-void
-repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
-{
-  Repodata *data;
-  if (p >= 0)
-    {
-      switch (keyname)
-       {
-       case SOLVABLE_NAME:
-       case SOLVABLE_ARCH:
-       case SOLVABLE_EVR:
-       case SOLVABLE_VENDOR:
-         repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
-         return;
-       }
-    }
-  data = repo_last_repodata(repo);
-  repodata_set_str(data, p, keyname, str);
-}
-
-void
-repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
-{
-  Repodata *data;
-  if (p >= 0)
-    {
-      switch (keyname)
-       {
-       case SOLVABLE_NAME:
-       case SOLVABLE_ARCH:
-       case SOLVABLE_EVR:
-       case SOLVABLE_VENDOR:
-         repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
-         return;
-       }
-    }
-  data = repo_last_repodata(repo);
-  repodata_set_poolstr(data, p, keyname, str);
-}
-
-void
-repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
-{
-  Repodata *data = repo_last_repodata(repo);
-  repodata_add_poolstr_array(data, p, keyname, str);
-}
-
-void
-repo_add_deparray(Repo *repo, Id p, Id keyname, Id dep, Id marker)
-{
-  Repodata *data;
-  if (marker == -1 || marker == 1)
-    marker = solv_depmarker(keyname, marker);
-  if (p >= 0)
-    {
-      Solvable *s = repo->pool->solvables + p;
-      switch (keyname)
-       {
-       case SOLVABLE_PROVIDES:
-         s->provides = repo_addid_dep(repo, s->provides, dep, marker);
-         return;
-       case SOLVABLE_OBSOLETES:
-         s->obsoletes = repo_addid_dep(repo, s->obsoletes, dep, marker);
-         return;
-       case SOLVABLE_CONFLICTS:
-         s->conflicts = repo_addid_dep(repo, s->conflicts, dep, marker);
-         return;
-       case SOLVABLE_REQUIRES:
-         s->requires = repo_addid_dep(repo, s->requires, dep, marker);
-         return;
-       case SOLVABLE_RECOMMENDS:
-         s->recommends = repo_addid_dep(repo, s->recommends, dep, marker);
-         return;
-       case SOLVABLE_SUGGESTS:
-         s->suggests = repo_addid_dep(repo, s->suggests, dep, marker);
-         return;
-       case SOLVABLE_SUPPLEMENTS:
-         s->supplements = repo_addid_dep(repo, s->supplements, dep, marker);
-         return;
-       case SOLVABLE_ENHANCES:
-         s->enhances = repo_addid_dep(repo, s->enhances, dep, marker);
-         return;
-       }
-    }
-  data = repo_last_repodata(repo);
-  repodata_add_idarray(data, p, keyname, dep);
-}
-
-void
-repo_add_idarray(Repo *repo, Id p, Id keyname, Id id)
-{
-  repo_add_deparray(repo, p, keyname, id, 0);
-}
-
-static Offset
-repo_set_idarray_solvable(Repo *repo, Queue *q)
-{
-  Offset o = 0;
-  int i;
-  for (i = 0; i < q->count; i++)
-    repo_addid_dep(repo, o, q->elements[i], 0);
-  return o;
-}
-
-void
-repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker)
-{
-  Repodata *data;
-  if (marker == -1 || marker == 1)
-    marker = solv_depmarker(keyname, marker);
-  if (marker)
-    {
-      /* complex case, splice old and new arrays */
-      int i;
-      Queue q2;
-      queue_init(&q2);
-      repo_lookup_deparray(repo, p, keyname, &q2, -marker);
-      if (marker > 0)
-       {
-         if (q->count)
-           {
-             queue_push(&q2, marker);
-             for (i = 0; i < q->count; i++)
-               queue_push(&q2, q->elements[i]);
-           }
-       }
-      else
-       {
-         if (q2.count)
-           queue_insert(&q2, 0, -marker);
-         queue_insertn(&q2, 0, q->count, q->elements);
-       }
-      repo_set_deparray(repo, p, keyname, &q2, 0);
-      queue_free(&q2);
-      return;
-    }
-  if (p >= 0)
-    {
-      Solvable *s = repo->pool->solvables + p;
-      switch (keyname)
-       {
-       case SOLVABLE_PROVIDES:
-         s->provides = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_OBSOLETES:
-         s->obsoletes = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_CONFLICTS:
-         s->conflicts = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_REQUIRES:
-         s->requires = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_RECOMMENDS:
-         s->recommends = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_SUGGESTS:
-         s->suggests = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_SUPPLEMENTS:
-         s->supplements = repo_set_idarray_solvable(repo, q);
-         return;
-       case SOLVABLE_ENHANCES:
-         s->enhances = repo_set_idarray_solvable(repo, q);
-         return;
-       }
-    }
-  data = repo_last_repodata(repo);
-  repodata_set_idarray(data, p, keyname, q);
-}
-
-void
-repo_set_idarray(Repo *repo, Id p, Id keyname, Queue *q)
-{
-  repo_set_deparray(repo, p, keyname, q, 0);
-}
-
-void
-repo_unset(Repo *repo, Id p, Id keyname)
-{
-  Repodata *data;
-  if (p >= 0)
-    {
-      Solvable *s = repo->pool->solvables + p;
-      switch (keyname)
-       {
-       case SOLVABLE_NAME:
-         s->name = 0;
-         return;
-       case SOLVABLE_ARCH:
-         s->arch = 0;
-         return;
-       case SOLVABLE_EVR:
-         s->evr = 0;
-         return;
-       case SOLVABLE_VENDOR:
-         s->vendor = 0;
-         return;
-        case RPM_RPMDBID:
-         if (repo->rpmdbid)
-           repo->rpmdbid[p - repo->start] = 0;
-         return;
-       case SOLVABLE_PROVIDES:
-         s->provides = 0;
-         return;
-       case SOLVABLE_OBSOLETES:
-         s->obsoletes = 0;
-         return;
-       case SOLVABLE_CONFLICTS:
-         s->conflicts = 0;
-         return;
-       case SOLVABLE_REQUIRES:
-         s->requires = 0;
-         return;
-       case SOLVABLE_RECOMMENDS:
-         s->recommends = 0;
-         return;
-       case SOLVABLE_SUGGESTS:
-         s->suggests = 0;
-         return;
-       case SOLVABLE_SUPPLEMENTS:
-         s->supplements = 0;
-       case SOLVABLE_ENHANCES:
-         s->enhances = 0;
-         return;
-       default:
-         break;
-       }
-    }
-  data = repo_last_repodata(repo);
-  repodata_unset(data, p, keyname);
-}
-
-void
-repo_internalize(Repo *repo)
-{
-  int i;
-  Repodata *data;
-
-  FOR_REPODATAS(repo, i, data)
-    if (data->attrs || data->xattrs)
-      repodata_internalize(data);
-}
-
-void
-repo_disable_paging(Repo *repo)
-{
-  int i;
-  Repodata *data;
-
-  FOR_REPODATAS(repo, i, data)
-    repodata_disable_paging(data);
-}
-
diff --git a/libsolv-0.6.15/src/repo.h b/libsolv-0.6.15/src/repo.h
deleted file mode 100644 (file)
index 952dbeb..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo.h
- *
- */
-
-#ifndef LIBSOLV_REPO_H
-#define LIBSOLV_REPO_H
-
-#include "pooltypes.h"
-#include "pool.h"
-#include "repodata.h"
-#include "dataiterator.h"
-#include "hash.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct _Repo {
-  const char *name;            /* name pointer */
-  Id repoid;                   /* our id */
-  void *appdata;               /* application private pointer */
-
-  Pool *pool;                  /* pool containing this repo */
-
-  int start;                   /* start of this repo solvables within pool->solvables */
-  int end;                     /* last solvable + 1 of this repo */
-  int nsolvables;              /* number of solvables repo is contributing to pool */
-
-  int disabled;                        /* ignore the solvables? */
-  int priority;                        /* priority of this repo */
-  int subpriority;             /* sub-priority of this repo, used just for sorting, not pruning */
-
-  Id *idarraydata;             /* array of metadata Ids, solvable dependencies are offsets into this array */
-  int idarraysize;
-
-  int nrepodata;               /* number of our stores..  */
-
-  Id *rpmdbid;                 /* solvable side data: rpm database id */
-
-#ifdef LIBSOLV_INTERNAL
-  Repodata *repodata;          /* our stores for non-solvable related data */
-  Offset lastoff;              /* start of last array in idarraydata */
-
-  Hashtable lastidhash;                /* hash to speed up repo_addid_dep */
-  Hashval lastidhash_mask;
-  int lastidhash_idarraysize;
-  int lastmarker;
-  Offset lastmarkerpos;
-#endif /* LIBSOLV_INTERNAL */
-} Repo;
-
-extern Repo *repo_create(Pool *pool, const char *name);
-extern void repo_free(Repo *repo, int reuseids);
-extern void repo_empty(Repo *repo, int reuseids);
-extern void repo_freedata(Repo *repo);
-extern Id repo_add_solvable(Repo *repo);
-extern Id repo_add_solvable_block(Repo *repo, int count);
-extern void repo_free_solvable(Repo *repo, Id p, int reuseids);
-extern void repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids);
-extern void *repo_sidedata_create(Repo *repo, size_t size);
-extern void *repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count);
-extern Id repo_add_solvable_block_before(Repo *repo, int count, Repo *beforerepo);
-
-extern Offset repo_addid(Repo *repo, Offset olddeps, Id id);
-extern Offset repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker);
-extern Offset repo_reserve_ids(Repo *repo, Offset olddeps, int num);
-extern Offset repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens);
-extern Offset repo_fix_conflicts(Repo *repo, Offset conflicts);
-
-static inline const char *repo_name(const Repo *repo)
-{
-  return repo->name;
-}
-
-/* those two functions are here because they need the Repo definition */
-
-static inline Repo *pool_id2repo(Pool *pool, Id repoid)
-{
-  return repoid < pool->nrepos ? pool->repos[repoid] : 0;
-}
-
-static inline int pool_disabled_solvable(const Pool *pool, Solvable *s)
-{
-  if (s->repo && s->repo->disabled)
-    return 1;
-  if (pool->considered)
-    {
-      Id id = s - pool->solvables;
-      if (!MAPTST(pool->considered, id))
-       return 1;
-    }
-  return 0;
-}
-
-static inline int pool_installable(const Pool *pool, Solvable *s)
-{
-  if (!s->arch || s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-    return 0;
-  if (s->repo && s->repo->disabled)
-    return 0;
-  if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch]))
-    return 0;
-  if (pool->considered)
-    {
-      Id id = s - pool->solvables;
-      if (!MAPTST(pool->considered, id))
-       return 0;
-    }
-  return 1;
-}
-
-/* search callback values */
-#define SEARCH_NEXT_KEY         1
-#define SEARCH_NEXT_SOLVABLE    2
-#define SEARCH_STOP             3
-#define SEARCH_ENTERSUB                -1
-
-/* standard flags used in the repo_add functions */
-#define REPO_REUSE_REPODATA            (1 << 0)
-#define REPO_NO_INTERNALIZE            (1 << 1)
-#define REPO_LOCALPOOL                 (1 << 2)
-#define REPO_USE_LOADING               (1 << 3)
-#define REPO_EXTEND_SOLVABLES          (1 << 4)
-#define REPO_USE_ROOTDIR               (1 << 5)
-#define REPO_NO_LOCATION               (1 << 6)
-
-Repodata *repo_add_repodata(Repo *repo, int flags);
-Repodata *repo_id2repodata(Repo *repo, Id id);
-Repodata *repo_last_repodata(Repo *repo);
-
-void repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata);
-
-/* returns the string value of the attribute, or NULL if not found */
-Id repo_lookup_type(Repo *repo, Id entry, Id keyname);
-const char *repo_lookup_str(Repo *repo, Id entry, Id keyname);
-/* returns the integer value of the attribute, or notfound if not found */
-unsigned long long repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound);
-Id repo_lookup_id(Repo *repo, Id entry, Id keyname);
-int repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q);
-int repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker);
-int repo_lookup_void(Repo *repo, Id entry, Id keyname);
-const char *repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep);
-const unsigned char *repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep);
-const void *repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp);
-Id solv_depmarker(Id keyname, Id marker);
-
-void repo_set_id(Repo *repo, Id p, Id keyname, Id id);
-void repo_set_num(Repo *repo, Id p, Id keyname, unsigned long long num);
-void repo_set_str(Repo *repo, Id p, Id keyname, const char *str);
-void repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str);
-void repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str);
-void repo_add_idarray(Repo *repo, Id p, Id keyname, Id id);
-void repo_add_deparray(Repo *repo, Id p, Id keyname, Id dep, Id marker);
-void repo_set_idarray(Repo *repo, Id p, Id keyname, Queue *q);
-void repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker);
-void repo_unset(Repo *repo, Id p, Id keyname);
-
-void repo_internalize(Repo *repo);
-void repo_disable_paging(Repo *repo);
-
-/* iterator macros */
-#define FOR_REPO_SOLVABLES(r, p, s)                                            \
-  for (p = (r)->start, s = (r)->pool->solvables + p; p < (r)->end; p++, s = (r)->pool->solvables + p)  \
-    if (s->repo != (r))                                                                \
-      continue;                                                                        \
-    else
-
-#ifdef LIBSOLV_INTERNAL
-#define FOR_REPODATAS(repo, rdid, data)        \
-       for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++)
-#else
-#define FOR_REPODATAS(repo, rdid, data)        \
-       for (rdid = 1; rdid < repo->nrepodata && (data = repo_id2repodata(repo, rdid)); rdid++)
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_REPO_H */
diff --git a/libsolv-0.6.15/src/repo_solv.c b/libsolv-0.6.15/src/repo_solv.c
deleted file mode 100644 (file)
index 86c851c..0000000
+++ /dev/null
@@ -1,1382 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_solv.c
- *
- * Add a repo in solv format
- *
- */
-
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "repo_solv.h"
-#include "util.h"
-
-#include "repopack.h"
-#include "repopage.h"
-
-#include "poolid_private.h"    /* WHATPROVIDES_BLOCK */
-
-#define INTERESTED_START       SOLVABLE_NAME
-#define INTERESTED_END         SOLVABLE_ENHANCES
-
-#define SOLV_ERROR_NOT_SOLV    1
-#define SOLV_ERROR_UNSUPPORTED 2
-#define SOLV_ERROR_EOF         3
-#define SOLV_ERROR_ID_RANGE    4
-#define SOLV_ERROR_OVERFLOW    5
-#define SOLV_ERROR_CORRUPT     6
-
-
-
-/*******************************************************************************
- * functions to extract data from a file handle
- */
-
-/*
- * read u32
- */
-
-static unsigned int
-read_u32(Repodata *data)
-{
-  int c, i;
-  unsigned int x = 0;
-
-  if (data->error)
-    return 0;
-  for (i = 0; i < 4; i++)
-    {
-      c = getc(data->fp);
-      if (c == EOF)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
-         return 0;
-       }
-      x = (x << 8) | c;
-    }
-  return x;
-}
-
-
-/*
- * read u8
- */
-
-static unsigned int
-read_u8(Repodata *data)
-{
-  int c;
-
-  if (data->error)
-    return 0;
-  c = getc(data->fp);
-  if (c == EOF)
-    {
-      data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
-      return 0;
-    }
-  return c;
-}
-
-
-/*
- * read Id
- */
-
-static Id
-read_id(Repodata *data, Id max)
-{
-  unsigned int x = 0;
-  int c, i;
-
-  if (data->error)
-    return 0;
-  for (i = 0; i < 5; i++)
-    {
-      c = getc(data->fp);
-      if (c == EOF)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
-         return 0;
-       }
-      if (!(c & 128))
-       {
-         x = (x << 7) | c;
-         if (max && x >= (unsigned int)max)
-           {
-             data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_id: id too large (%u/%u)", x, max);
-             return 0;
-           }
-         return x;
-       }
-      x = (x << 7) ^ c ^ 128;
-    }
-  data->error = pool_error(data->repo->pool, SOLV_ERROR_CORRUPT, "read_id: id too long");
-  return 0;
-}
-
-
-static Id *
-read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
-{
-  unsigned int x = 0;
-  int c;
-
-  if (data->error)
-    return 0;
-  for (;;)
-    {
-      c = getc(data->fp);
-      if (c == EOF)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
-         return 0;
-       }
-      if ((c & 128) != 0)
-       {
-         x = (x << 7) ^ c ^ 128;
-         continue;
-       }
-      x = (x << 6) | (c & 63);
-      if (max && x >= (unsigned int)max)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_idarray: id too large (%u/%u)", x, max);
-         return 0;
-       }
-      if (map)
-       x = map[x];
-      if (store == end)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
-         return 0;
-       }
-      *store++ = x;
-      if ((c & 64) == 0)
-       {
-         if (x == 0)   /* already have trailing zero? */
-           return store;
-         if (store == end)
-           {
-             data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
-             return 0;
-           }
-         *store++ = 0;
-         return store;
-       }
-      x = 0;
-    }
-}
-
-
-/*******************************************************************************
- * functions to extract data from memory
- */
-
-/*
- * read array of Ids
- */
-
-static inline unsigned char *
-data_read_id_max(unsigned char *dp, Id *ret, Id *map, int max, Repodata *data)
-{
-  Id x;
-  dp = data_read_id(dp, &x);
-  if (x < 0 || (max && x >= max))
-    {
-      data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_id_max: id too large (%u/%u)", x, max);
-      x = 0;
-    }
-  *ret = map ? map[x] : x;
-  return dp;
-}
-
-static unsigned char *
-data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data)
-{
-  Id *store = *storep;
-  unsigned int x = 0;
-  int c;
-
-  for (;;)
-    {
-      c = *dp++;
-      if ((c & 128) != 0)
-       {
-         x = (x << 7) ^ c ^ 128;
-         continue;
-       }
-      x = (x << 6) | (c & 63);
-      if (max && x >= (unsigned int)max)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_idarray: id too large (%u/%u)", x, max);
-         data->error = SOLV_ERROR_ID_RANGE;
-         break;
-       }
-      *store++ = x;
-      if ((c & 64) == 0)
-        break;
-      x = 0;
-    }
-  *store++ = 0;
-  *storep = store;
-  return dp;
-}
-
-static unsigned char *
-data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id marker)
-{
-  Id *store = *storep;
-  Id old = 0;
-  unsigned int x = 0;
-  int c;
-
-  for (;;)
-    {
-      c = *dp++;
-      if ((c & 128) != 0)
-       {
-         x = (x << 7) ^ c ^ 128;
-         continue;
-       }
-      x = (x << 6) | (c & 63);
-      if (x == 0)
-       {
-         if (!(c & 64))
-           break;
-          if (marker)
-           *store++ = marker;
-         old = 0;
-         continue;
-       }
-      x = old + (x - 1);
-      old = x;
-      if (max && x >= (unsigned int)max)
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_rel_idarray: id too large (%u/%u)", x, max);
-         break;
-       }
-      *store++ = map ? map[x] : x;
-      if (!(c & 64))
-        break;
-      x = 0;
-    }
-  *store++ = 0;
-  *storep = store;
-  return dp;
-}
-
-
-
-
-/*******************************************************************************
- * functions to add data to our incore memory space
- */
-
-#define INCORE_ADD_CHUNK 8192
-#define DATA_READ_CHUNK 8192
-
-static void
-incore_add_id(Repodata *data, Id sx)
-{
-  unsigned int x = (unsigned int)sx;
-  unsigned char *dp;
-  /* make sure we have at least 5 bytes free */
-  if (data->incoredatafree < 5)
-    {
-      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
-      data->incoredatafree = INCORE_ADD_CHUNK;
-    }
-  dp = data->incoredata + data->incoredatalen;
-  if (x >= (1 << 14))
-    {
-      if (x >= (1 << 28))
-       *dp++ = (x >> 28) | 128;
-      if (x >= (1 << 21))
-       *dp++ = (x >> 21) | 128;
-      *dp++ = (x >> 14) | 128;
-    }
-  if (x >= (1 << 7))
-    *dp++ = (x >> 7) | 128;
-  *dp++ = x & 127;
-  data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
-  data->incoredatalen = dp - data->incoredata;
-}
-
-static void
-incore_add_sizek(Repodata *data, unsigned int sx)
-{
-  if (sx < (1 << 22))
-    incore_add_id(data, (Id)(sx << 10));
-  else
-    {
-      if ((sx >> 25) != 0)
-       {
-         incore_add_id(data, (Id)(sx >> 25));
-         data->incoredata[data->incoredatalen - 1] |= 128;
-       }
-      incore_add_id(data, (Id)((sx << 10) | 0x80000000));
-      data->incoredata[data->incoredatalen - 5] = (sx >> 18) | 128;
-    }
-}
-
-static void
-incore_add_ideof(Repodata *data, Id sx, int eof)
-{
-  unsigned int x = (unsigned int)sx;
-  unsigned char *dp;
-  /* make sure we have at least 5 bytes free */
-  if (data->incoredatafree < 5)
-    {
-      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
-      data->incoredatafree = INCORE_ADD_CHUNK;
-    }
-  dp = data->incoredata + data->incoredatalen;
-  if (x >= (1 << 13))
-    {
-      if (x >= (1 << 27))
-       *dp++ = (x >> 27) | 128;
-      if (x >= (1 << 20))
-       *dp++ = (x >> 20) | 128;
-      *dp++ = (x >> 13) | 128;
-    }
-  if (x >= (1 << 6))
-    *dp++ = (x >> 6) | 128;
-  *dp++ = eof ? (x & 63) : (x & 63) | 64;
-  data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
-  data->incoredatalen = dp - data->incoredata;
-}
-
-static void
-incore_add_blob(Repodata *data, unsigned char *buf, int len)
-{
-  if (data->incoredatafree < (unsigned int)len)
-    {
-      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK + len);
-      data->incoredatafree = INCORE_ADD_CHUNK + len;
-    }
-  memcpy(data->incoredata + data->incoredatalen, buf, len);
-  data->incoredatafree -= len;
-  data->incoredatalen += len;
-}
-
-static void
-incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
-{
-  /* We have to map the IDs, which might also change
-     the necessary number of bytes, so we can't just copy
-     over the blob and adjust it.  */
-  for (;;)
-    {
-      Id id;
-      int eof;
-      dp = data_read_ideof(dp, &id, &eof);
-      if (id < 0 || (max && id >= max))
-       {
-         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "incore_map_idarray: id too large (%u/%u)", id, max);
-         break;
-       }
-      id = map[id];
-      incore_add_ideof(data, id, eof);
-      if (eof)
-       break;
-    }
-}
-
-#if 0
-static void
-incore_add_u32(Repodata *data, unsigned int x)
-{
-  unsigned char *dp;
-  /* make sure we have at least 4 bytes free */
-  if (data->incoredatafree < 4)
-    {
-      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
-      data->incoredatafree = INCORE_ADD_CHUNK;
-    }
-  dp = data->incoredata + data->incoredatalen;
-  *dp++ = x >> 24;
-  *dp++ = x >> 16;
-  *dp++ = x >> 8;
-  *dp++ = x;
-  data->incoredatafree -= 4;
-  data->incoredatalen += 4;
-}
-
-static void
-incore_add_u8(Repodata *data, unsigned int x)
-{
-  unsigned char *dp;
-  /* make sure we have at least 1 byte free */
-  if (data->incoredatafree < 1)
-    {
-      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + 1024);
-      data->incoredatafree = 1024;
-    }
-  dp = data->incoredata + data->incoredatalen;
-  *dp++ = x;
-  data->incoredatafree--;
-  data->incoredatalen++;
-}
-#endif
-
-
-/*******************************************************************************
- * our main function
- */
-
-/*
- * read repo from .solv file and add it to pool
- */
-
-int
-repo_add_solv(Repo *repo, FILE *fp, int flags)
-{
-  Pool *pool = repo->pool;
-  int i, l;
-  int numid, numrel, numdir, numsolv;
-  int numkeys, numschemata;
-
-  Offset sizeid;
-  Offset *str;                        /* map Id -> Offset into string space */
-  char *strsp;                        /* repo string space */
-  char *sp;                           /* pointer into string space */
-  Id *idmap;                          /* map of repo Ids to pool Ids */
-  Id id, type;
-  Hashval hashmask, h, hh;
-  Hashtable hashtbl;
-  Id name, evr, did;
-  int relflags;
-  Reldep *ran;
-  unsigned int size_idarray;
-  Id *idarraydatap, *idarraydataend;
-  Offset ido;
-  Solvable *s;
-  unsigned int solvflags;
-  unsigned int solvversion;
-  Repokey *keys;
-  Id *schemadata, *schemadatap, *schemadataend;
-  Id *schemata, key, *keyp;
-  int nentries;
-  int have_incoredata;
-  int maxsize, allsize;
-  unsigned char *buf, *bufend, *dp, *dps;
-  Id stack[3 * 5];
-  int keydepth;
-  int needchunk;       /* need a new chunk of data */
-  unsigned int now;
-  int oldnstrings = pool->ss.nstrings;
-  int oldnrels = pool->nrels;
-
-  struct _Stringpool *spool;
-
-  Repodata *parent = 0;
-  Repodata data;
-
-  int extendstart = 0, extendend = 0;  /* set in case we're extending */
-
-  now = solv_timems(0);
-
-  if ((flags & REPO_USE_LOADING) != 0)
-    {
-      /* this is a stub replace operation */
-      flags |= REPO_EXTEND_SOLVABLES;
-      /* use REPO_REUSE_REPODATA hack so that the old repodata is kept */
-      parent = repo_add_repodata(repo, flags | REPO_REUSE_REPODATA);
-      extendstart = parent->start;
-      extendend = parent->end;
-    }
-  else if (flags & REPO_EXTEND_SOLVABLES)
-    {
-      /* extend all solvables of this repo */
-      extendstart = repo->start;
-      extendend = repo->end;
-    }
-
-  memset(&data, 0, sizeof(data));
-  data.repo = repo;
-  data.fp = fp;
-  repopagestore_init(&data.store);
-
-  if (read_u32(&data) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
-     return pool_error(pool, SOLV_ERROR_NOT_SOLV, "not a SOLV file");
-  solvversion = read_u32(&data);
-  switch (solvversion)
-    {
-      case SOLV_VERSION_8:
-       break;
-      default:
-        return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
-    }
-
-  numid = (int)read_u32(&data);
-  numrel = (int)read_u32(&data);
-  numdir = (int)read_u32(&data);
-  numsolv = (int)read_u32(&data);
-  numkeys = (int)read_u32(&data);
-  numschemata = (int)read_u32(&data);
-  solvflags = read_u32(&data);
-
-  if (numid < 0 || numid >= 0x20000000)
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of ids");
-  if (numrel < 0 || numrel >= 0x20000000)
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of rels");
-  if (numdir && (numdir < 2 || numdir >= 0x20000000))
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of dirs");
-  if (numsolv < 0 || numsolv >= 0x20000000)
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of solvables");
-  if (numkeys < 0 || numkeys >= 0x20000000)
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of keys");
-  if (numschemata < 0 || numschemata >= 0x20000000)
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of schematas");
-
-  if (numrel && (flags & REPO_LOCALPOOL) != 0)
-    return pool_error(pool, SOLV_ERROR_CORRUPT, "relations are forbidden in a local pool");
-  if ((flags & REPO_EXTEND_SOLVABLES) && numsolv)
-    {
-      /* make sure that we exactly replace the stub repodata */
-      if (extendend - extendstart != numsolv)
-       return pool_error(pool, SOLV_ERROR_CORRUPT, "sub-repository solvable number does not match main repository (%d - %d)", extendend - extendstart, numsolv);
-      for (i = 0; i < numsolv; i++)
-       if (pool->solvables[extendstart + i].repo != repo)
-         return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
-    }
-
-  /*******  Part 1: string IDs  *****************************************/
-
-  sizeid = read_u32(&data);           /* size of string space */
-
-  /*
-   * read strings and Ids
-   *
-   */
-
-
-  /*
-   * alloc buffers
-   */
-
-  if (!(flags & REPO_LOCALPOOL))
-    {
-      spool = &pool->ss;
-      /* alloc max needed string buffer and string pointers, will shrink again later */
-#if 0
-      spool->stringspace = solv_realloc(spool->stringspace, spool->sstrings + sizeid + 1);
-      spool->strings = solv_realloc2(spool->strings, spool->nstrings + numid, sizeof(Offset));
-#else
-      spool->sstrings += sizeid + 1;
-      spool->nstrings += numid;
-      stringpool_shrink(spool);                /* we misuse stringpool_shrink so that the correct BLOCK factor is used */
-      spool->sstrings -= sizeid + 1;
-      spool->nstrings -= numid;
-#endif
-    }
-  else
-    {
-      data.localpool = 1;
-      spool = &data.spool;
-      spool->stringspace = solv_malloc(7 + sizeid + 1);
-      spool->strings = solv_malloc2(numid < 2 ?  2 : numid, sizeof(Offset));
-      strcpy(spool->stringspace, "<NULL>");
-      spool->sstrings = 7;
-      spool->nstrings = 1;
-      spool->strings[0] = 0;   /* <NULL> */
-    }
-
-
-  /*
-   * read string data and append to old string space
-   */
-
-  strsp = spool->stringspace + spool->sstrings;        /* append new entries */
-  if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
-    {
-      if (sizeid && fread(strsp, sizeid, 1, fp) != 1)
-       {
-         repodata_freedata(&data);
-         return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
-       }
-    }
-  else
-    {
-      unsigned int pfsize = read_u32(&data);
-      char *prefix = solv_malloc(pfsize);
-      char *pp = prefix;
-      char *old_str = 0;
-      char *dest = strsp;
-      int freesp = sizeid;
-
-      if (pfsize && fread(prefix, pfsize, 1, fp) != 1)
-       {
-         solv_free(prefix);
-         repodata_freedata(&data);
-         return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
-       }
-      for (i = 1; i < numid; i++)
-        {
-         int same = (unsigned char)*pp++;
-         size_t len = strlen(pp) + 1;
-         freesp -= same + len;
-         if (freesp < 0)
-           {
-             solv_free(prefix);
-             repodata_freedata(&data);
-             return pool_error(pool, SOLV_ERROR_OVERFLOW, "overflow while expanding strings");
-           }
-         if (same)
-           memcpy(dest, old_str, same);
-         memcpy(dest + same, pp, len);
-         pp += len;
-         old_str = dest;
-         dest += same + len;
-       }
-      solv_free(prefix);
-      if (freesp != 0)
-       {
-         repodata_freedata(&data);
-         return pool_error(pool, SOLV_ERROR_CORRUPT, "expanding strings size mismatch");
-       }
-    }
-  strsp[sizeid] = 0;                  /* make string space \0 terminated */
-  sp = strsp;
-
-  /* now merge */
-  str = spool->strings;                        /* array of offsets into strsp, indexed by Id */
-  if ((flags & REPO_LOCALPOOL) != 0)
-    {
-      /* no shared pool, thus no idmap and no unification needed */
-      idmap = 0;
-      spool->nstrings = numid < 2 ? 2 : numid; /* make sure we have at least id 0 and 1 */
-      if (*sp)
-       {
-         /* we need id 1 to be '' for directories */
-         repodata_freedata(&data);
-         return pool_error(pool, SOLV_ERROR_CORRUPT, "store strings don't start with an empty string");
-       }
-      for (i = 1; i < spool->nstrings; i++)
-       {
-         if (sp >= strsp + sizeid && numid >= 2)
-           {
-             repodata_freedata(&data);
-             return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings");
-           }
-         str[i] = sp - spool->stringspace;
-         sp += strlen(sp) + 1;
-       }
-      spool->sstrings = sp - spool->stringspace;
-    }
-  else
-    {
-      Offset oldsstrings = spool->sstrings;
-
-      /* alloc id map for name and rel Ids. this maps ids in the solv files
-       * to the ids in our pool */
-      idmap = solv_calloc(numid + numrel, sizeof(Id));
-
-      /* grow hash if needed, otherwise reuse */
-      hashmask = mkmask(spool->nstrings + numid);
-#if 0
-      POOL_DEBUG(SOLV_DEBUG_STATS, "read %d strings\n", numid);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d, old %d\n", hashmask + 1, spool->stringhashmask + 1);
-#endif
-      if (hashmask > spool->stringhashmask)
-       {
-         spool->stringhashtbl = solv_free(spool->stringhashtbl);
-         spool->stringhashmask = hashmask;
-          spool->stringhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
-         for (i = 1; i < spool->nstrings; i++)
-           {
-             h = strhash(spool->stringspace + spool->strings[i]) & hashmask;
-             hh = HASHCHAIN_START;
-             while (hashtbl[h])
-               h = HASHCHAIN_NEXT(h, hh, hashmask);
-             hashtbl[h] = i;
-           }
-       }
-      else
-       {
-         hashtbl = spool->stringhashtbl;
-         hashmask = spool->stringhashmask;
-       }
-
-      /*
-       * run over strings and merge with pool.
-       * also populate id map (maps solv Id -> pool Id)
-       */
-      for (i = 1; i < numid; i++)
-       {
-         if (sp >= strsp + sizeid)
-           {
-             solv_free(idmap);
-             spool->nstrings = oldnstrings;
-             spool->sstrings = oldsstrings;
-             stringpool_freehash(spool);
-             repodata_freedata(&data);
-             return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings %d %d", i, numid);
-           }
-         if (!*sp)                            /* empty string */
-           {
-             idmap[i] = ID_EMPTY;
-             sp++;
-             continue;
-           }
-
-         /* find hash slot */
-         h = strhash(sp) & hashmask;
-         hh = HASHCHAIN_START;
-         for (;;)
-           {
-             id = hashtbl[h];
-             if (!id)
-               break;
-             if (!strcmp(spool->stringspace + spool->strings[id], sp))
-               break;          /* already in pool */
-             h = HASHCHAIN_NEXT(h, hh, hashmask);
-           }
-
-         /* length == offset to next string */
-         l = strlen(sp) + 1;
-         if (!id)             /* end of hash chain -> new string */
-           {
-             id = spool->nstrings++;
-             hashtbl[h] = id;
-             str[id] = spool->sstrings;        /* save offset */
-             if (sp != spool->stringspace + spool->sstrings)
-               memmove(spool->stringspace + spool->sstrings, sp, l);
-             spool->sstrings += l;
-           }
-         idmap[i] = id;       /* repo relative -> pool relative */
-         sp += l;             /* next string */
-       }
-      if (hashmask > mkmask(spool->nstrings + 8192))
-       {
-         spool->stringhashtbl = solv_free(spool->stringhashtbl);
-         spool->stringhashmask = 0;
-       }
-      stringpool_shrink(spool);                /* vacuum */
-    }
-
-
-  /*******  Part 2: Relation IDs  ***************************************/
-
-  /*
-   * read RelDeps
-   *
-   */
-
-  if (numrel)
-    {
-      /* extend rels */
-      pool->rels = solv_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep));
-      ran = pool->rels;
-
-      /* grow hash if needed, otherwise reuse */
-      hashmask = mkmask(pool->nrels + numrel);
-#if 0
-      POOL_DEBUG(SOLV_DEBUG_STATS, "read %d rels\n", numrel);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d, old %d\n", hashmask + 1, pool->relhashmask + 1);
-#endif
-      if (hashmask > pool->relhashmask)
-       {
-         pool->relhashtbl = solv_free(pool->relhashtbl);
-         pool->relhashmask = hashmask;
-          pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
-         for (i = 1; i < pool->nrels; i++)
-           {
-             h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
-             hh = HASHCHAIN_START;
-             while (hashtbl[h])
-               h = HASHCHAIN_NEXT(h, hh, hashmask);
-             hashtbl[h] = i;
-           }
-       }
-      else
-       {
-         hashtbl = pool->relhashtbl;
-         hashmask = pool->relhashmask;
-       }
-
-      /*
-       * read RelDeps from repo
-       */
-      for (i = 0; i < numrel; i++)
-       {
-         name = read_id(&data, i + numid);     /* read (repo relative) Ids */
-         evr = read_id(&data, i + numid);
-         relflags = read_u8(&data);
-         name = idmap[name];           /* map to (pool relative) Ids */
-         evr = idmap[evr];
-         h = relhash(name, evr, relflags) & hashmask;
-         hh = HASHCHAIN_START;
-         for (;;)
-           {
-             id = hashtbl[h];
-             if (!id)          /* end of hash chain reached */
-               break;
-             if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == relflags)
-               break;
-             h = HASHCHAIN_NEXT(h, hh, hashmask);
-           }
-         if (!id)              /* new RelDep */
-           {
-             id = pool->nrels++;
-             hashtbl[h] = id;
-             ran[id].name = name;
-             ran[id].evr = evr;
-             ran[id].flags = relflags;
-           }
-         idmap[i + numid] = MAKERELDEP(id);   /* fill Id map */
-       }
-      if (hashmask > mkmask(pool->nrels + 4096))
-       {
-         pool->relhashtbl = solv_free(pool->relhashtbl);
-         pool->relhashmask = 0;
-       }
-      pool_shrink_rels(pool);          /* vacuum */
-    }
-
-  /* if we added ids/rels, make room in our whatprovide arrays */
-  if (!(flags & REPO_LOCALPOOL))
-    {
-      if (pool->whatprovides && oldnstrings != pool->ss.nstrings)
-       {
-         int newlen = (pool->ss.nstrings + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
-         pool->whatprovides = solv_realloc2(pool->whatprovides, newlen, sizeof(Offset));
-         memset(pool->whatprovides + oldnstrings, 0, (newlen - oldnstrings) * sizeof(Offset));
-       }
-      if (pool->whatprovides_rel && oldnrels != pool->nrels)
-       {
-         int newlen = (pool->nrels + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
-         pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, newlen, sizeof(Offset));
-         memset(pool->whatprovides_rel + oldnrels, 0, (newlen - oldnrels) * sizeof(Offset));
-       }
-    }
-
-  /*******  Part 3: Dirs  ***********************************************/
-  if (numdir)
-    {
-      data.dirpool.dirs = solv_malloc2(numdir, sizeof(Id));
-      data.dirpool.ndirs = numdir;
-      data.dirpool.dirs[0] = 0;                /* dir 0: virtual root */
-      data.dirpool.dirs[1] = 1;                /* dir 1: / */
-      for (i = 2; i < numdir; i++)
-       {
-         id = read_id(&data, i + numid);
-         if (id >= numid)
-           data.dirpool.dirs[i] = -(id - numid);
-         else if (idmap)
-           data.dirpool.dirs[i] = idmap[id];
-         else
-           data.dirpool.dirs[i] = id;
-       }
-    }
-
-  /*******  Part 4: Keys  ***********************************************/
-
-  keys = solv_calloc(numkeys, sizeof(*keys));
-  /* keys start at 1 */
-  for (i = 1; i < numkeys; i++)
-    {
-      id = read_id(&data, numid);
-      if (idmap)
-       id = idmap[id];
-      else if ((flags & REPO_LOCALPOOL) != 0)
-        id = pool_str2id(pool, stringpool_id2str(spool, id), 1);
-      type = read_id(&data, numid);
-      if (idmap)
-       type = idmap[type];
-      else if ((flags & REPO_LOCALPOOL) != 0)
-        type = pool_str2id(pool, stringpool_id2str(spool, type), 1);
-      if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_FLEXARRAY)
-       {
-         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
-         type = REPOKEY_TYPE_VOID;
-       }
-      keys[i].name = id;
-      keys[i].type = type;
-      keys[i].size = read_id(&data, keys[i].type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
-      keys[i].storage = read_id(&data, 0);
-      /* old versions used SOLVABLE for main solvable data */
-      if (keys[i].storage == KEY_STORAGE_SOLVABLE)
-       keys[i].storage = KEY_STORAGE_INCORE;
-      if (keys[i].storage != KEY_STORAGE_INCORE && keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
-       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", keys[i].storage);
-      if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
-       {
-         if (keys[i].storage != KEY_STORAGE_INCORE)
-           data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage %d", keys[i].storage);
-         keys[i].storage = KEY_STORAGE_SOLVABLE;
-       }
-      /* cannot handle rel idarrays in incore/vertical */
-      if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE)
-       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_SOLVABLE");
-      /* cannot handle mapped ids in vertical */
-      if (!(flags & REPO_LOCALPOOL) && keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
-       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "mapped ids are not supported for STORAGE_VERTICAL_OFFSET");
-
-      if (keys[i].type == REPOKEY_TYPE_CONSTANTID && idmap)
-       keys[i].size = idmap[keys[i].size];
-#if 0
-      fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool,id), pool_id2str(pool, keys[i].type),
-               keys[i].size, keys[i].storage);
-#endif
-    }
-
-  have_incoredata = 0;
-  for (i = 1; i < numkeys; i++)
-    if (keys[i].storage == KEY_STORAGE_INCORE || keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
-      have_incoredata = 1;
-
-  data.keys = keys;
-  data.nkeys = numkeys;
-  for (i = 1; i < numkeys; i++)
-    {
-      id = keys[i].name;
-      data.keybits[(id >> 3) & (sizeof(data.keybits) - 1)] |= 1 << (id & 7);
-    }
-
-  /*******  Part 5: Schemata ********************************************/
-
-  id = read_id(&data, 0);
-  schemadata = solv_calloc(id + 1, sizeof(Id));
-  schemadatap = schemadata + 1;
-  schemadataend = schemadatap + id;
-  schemata = solv_calloc(numschemata, sizeof(Id));
-  for (i = 1; i < numschemata; i++)
-    {
-      schemata[i] = schemadatap - schemadata;
-      schemadatap = read_idarray(&data, numid, 0, schemadatap, schemadataend);
-#if 0
-      Id *sp = schemadata + schemata[i];
-      fprintf(stderr, "schema %d:", i);
-      for (; *sp; sp++)
-        fprintf(stderr, " %d", *sp);
-      fprintf(stderr, "\n");
-#endif
-    }
-  data.schemata = schemata;
-  data.nschemata = numschemata;
-  data.schemadata = schemadata;
-  data.schemadatalen = schemadataend - data.schemadata;
-
-  /*******  Part 6: Data ********************************************/
-
-  idarraydatap = idarraydataend = 0;
-  size_idarray = 0;
-
-  maxsize = read_id(&data, 0);
-  allsize = read_id(&data, 0);
-  maxsize += 5;        /* so we can read the next schema of an array */
-  if (maxsize > allsize)
-    maxsize = allsize;
-
-  buf = solv_calloc(maxsize + DATA_READ_CHUNK + 4, 1); /* 4 extra bytes to detect overflows */
-  bufend = buf;
-  dp = buf;
-
-  l = maxsize;
-  if (l < DATA_READ_CHUNK)
-    l = DATA_READ_CHUNK;
-  if (l > allsize)
-    l = allsize;
-  if (!l || fread(buf, l, 1, data.fp) != 1)
-    {
-      data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
-      id = 0;
-    }
-  else
-    {
-      bufend = buf + l;
-      allsize -= l;
-      dp = data_read_id_max(dp, &id, 0, numschemata, &data);
-    }
-
-  incore_add_id(&data, 0);     /* so that incoreoffset 0 means schema 0 */
-  incore_add_id(&data, id);    /* main schema id */
-  keyp = schemadata + schemata[id];
-  data.mainschema = id;
-  for (i = 0; keyp[i]; i++)
-    ;
-  if (i)
-    data.mainschemaoffsets = solv_calloc(i, sizeof(Id));
-
-  nentries = 0;
-  keydepth = 0;
-  s = 0;
-  needchunk = 1;
-  for(;;)
-    {
-      /* make sure we have enough room */
-      if (keydepth == 0 || needchunk)
-       {
-         int left = bufend - dp;
-         /* read data chunk to dp */
-         if (data.error)
-           break;
-         if (left < 0)
-           {
-              data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
-             break;
-           }
-         if (left < maxsize)
-           {
-             if (left)
-               memmove(buf, dp, left);
-             l = maxsize - left;
-             if (l < DATA_READ_CHUNK)
-               l = DATA_READ_CHUNK;
-             if (l > allsize)
-               l = allsize;
-             if (l && fread(buf + left, l, 1, data.fp) != 1)
-               {
-                 data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
-                 break;
-               }
-             allsize -= l;
-             left += l;
-             bufend = buf + left;
-             if (allsize + left < maxsize)
-               maxsize = allsize + left;
-             dp = buf;
-           }
-         needchunk = 0;
-       }
-
-      key = *keyp++;
-#if 0
-printf("key %d at %d\n", key, (int)(keyp - 1 - schemadata));
-#endif
-      if (!key)
-       {
-         if (keydepth <= 3)
-           needchunk = 1;
-         if (nentries)
-           {
-             if (s && keydepth == 3)
-               {
-                 s++;  /* next solvable */
-                 if (have_incoredata)
-                   data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
-               }
-             id = stack[keydepth - 1];
-             if (!id)
-               {
-                 dp = data_read_id_max(dp, &id, 0, numschemata, &data);
-                 incore_add_id(&data, id);
-               }
-             keyp = schemadata + schemata[id];
-             nentries--;
-             continue;
-           }
-         if (!keydepth)
-           break;
-         --keydepth;
-         keyp = schemadata + stack[--keydepth];
-         nentries = stack[--keydepth];
-#if 0
-printf("pop flexarray %d %d\n", keydepth, nentries);
-#endif
-         if (!keydepth && s)
-           s = 0;      /* back from solvables */
-         continue;
-       }
-
-      if (keydepth == 0)
-       data.mainschemaoffsets[keyp - 1 - (schemadata + schemata[data.mainschema])] = data.incoredatalen;
-
-#if 0
-printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, keys[key].type), s);
-#endif
-      id = keys[key].name;
-      if (keys[key].storage == KEY_STORAGE_VERTICAL_OFFSET)
-       {
-         dps = dp;
-         dp = data_skip(dp, REPOKEY_TYPE_ID);
-         dp = data_skip(dp, REPOKEY_TYPE_ID);
-         incore_add_blob(&data, dps, dp - dps);        /* just record offset/size */
-         continue;
-       }
-      switch (keys[key].type)
-       {
-       case REPOKEY_TYPE_ID:
-         dp = data_read_id_max(dp, &did, idmap, numid + numrel, &data);
-         if (s && id == SOLVABLE_NAME)
-           s->name = did;
-         else if (s && id == SOLVABLE_ARCH)
-           s->arch = did;
-         else if (s && id == SOLVABLE_EVR)
-           s->evr = did;
-         else if (s && id == SOLVABLE_VENDOR)
-           s->vendor = did;
-         else if (keys[key].storage == KEY_STORAGE_INCORE)
-           incore_add_id(&data, did);
-#if 0
-         POOL_DEBUG(SOLV_DEBUG_STATS, "%s -> %s\n", pool_id2str(pool, id), pool_id2str(pool, did));
-#endif
-         break;
-       case REPOKEY_TYPE_IDARRAY:
-       case REPOKEY_TYPE_REL_IDARRAY:
-         if (!s || id < INTERESTED_START || id > INTERESTED_END)
-           {
-             dps = dp;
-             dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
-             if (keys[key].storage != KEY_STORAGE_INCORE)
-               break;
-             if (idmap)
-               incore_map_idarray(&data, dps, idmap, numid + numrel);
-             else
-               incore_add_blob(&data, dps, dp - dps);
-             break;
-           }
-         ido = idarraydatap - repo->idarraydata;
-         if (keys[key].type == REPOKEY_TYPE_IDARRAY)
-           dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
-         else if (id == SOLVABLE_REQUIRES)
-           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_PREREQMARKER);
-         else if (id == SOLVABLE_PROVIDES)
-           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_FILEMARKER);
-         else
-           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, 0);
-         if (idarraydatap > idarraydataend)
-           {
-             data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
-             break;
-           }
-         if (id == SOLVABLE_PROVIDES)
-           s->provides = ido;
-         else if (id == SOLVABLE_OBSOLETES)
-           s->obsoletes = ido;
-         else if (id == SOLVABLE_CONFLICTS)
-           s->conflicts = ido;
-         else if (id == SOLVABLE_REQUIRES)
-           s->requires = ido;
-         else if (id == SOLVABLE_RECOMMENDS)
-           s->recommends= ido;
-         else if (id == SOLVABLE_SUPPLEMENTS)
-           s->supplements = ido;
-         else if (id == SOLVABLE_SUGGESTS)
-           s->suggests = ido;
-         else if (id == SOLVABLE_ENHANCES)
-           s->enhances = ido;
-#if 0
-         POOL_DEBUG(SOLV_DEBUG_STATS, "%s ->\n", pool_id2str(pool, id));
-         for (; repo->idarraydata[ido]; ido++)
-           POOL_DEBUG(SOLV_DEBUG_STATS,"  %s\n", pool_dep2str(pool, repo->idarraydata[ido]));
-#endif
-         break;
-       case REPOKEY_TYPE_FIXARRAY:
-       case REPOKEY_TYPE_FLEXARRAY:
-         if (!keydepth)
-           needchunk = 1;
-          if (keydepth == sizeof(stack)/sizeof(*stack))
-           {
-             data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "array stack overflow");
-             break;
-           }
-         stack[keydepth++] = nentries;
-         stack[keydepth++] = keyp - schemadata;
-         stack[keydepth++] = 0;
-         dp = data_read_id_max(dp, &nentries, 0, 0, &data);
-         incore_add_id(&data, nentries);
-         if (!nentries)
-           {
-             /* zero size array? */
-             keydepth -= 2;
-             nentries = stack[--keydepth];
-             break;
-           }
-         if (keydepth == 3 && id == REPOSITORY_SOLVABLES)
-           {
-             /* horray! here come the solvables */
-             if (nentries != numsolv)
-               {
-                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "inconsistent number of solvables: %d %d", nentries, numsolv);
-                 break;
-               }
-             if (idarraydatap)
-               {
-                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "more than one solvable block");
-                 break;
-               }
-             if ((flags & REPO_EXTEND_SOLVABLES) != 0)
-               s = pool_id2solvable(pool, extendstart);
-             else
-               s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
-             data.start = s - pool->solvables;
-             data.end = data.start + numsolv;
-             repodata_extend_block(&data, data.start, numsolv);
-             for (i = 1; i < numkeys; i++)
-               {
-                 id = keys[i].name;
-                 if ((keys[i].type == REPOKEY_TYPE_IDARRAY || keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
-                     && id >= INTERESTED_START && id <= INTERESTED_END)
-                   size_idarray += keys[i].size;
-               }
-             /* allocate needed space in repo */
-             /* we add maxsize because it is an upper limit for all idarrays, thus we can't overflow */
-             repo_reserve_ids(repo, 0, size_idarray + maxsize + 1);
-             idarraydatap = repo->idarraydata + repo->idarraysize;
-             repo->idarraysize += size_idarray;
-             idarraydataend = idarraydatap + size_idarray;
-             repo->lastoff = 0;
-             if (have_incoredata)
-               data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
-           }
-         nentries--;
-         dp = data_read_id_max(dp, &id, 0, numschemata, &data);
-         incore_add_id(&data, id);
-         if (keys[key].type == REPOKEY_TYPE_FIXARRAY)
-           {
-             if (!id)
-               data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "illegal fixarray");
-             stack[keydepth - 1] = id;
-           }
-         keyp = schemadata + schemata[id];
-         break;
-       case REPOKEY_TYPE_NUM:
-         if (!(solvflags & SOLV_FLAG_SIZE_BYTES) && keys[key].storage == KEY_STORAGE_INCORE &&
-               (id == SOLVABLE_INSTALLSIZE || id == SOLVABLE_DOWNLOADSIZE || id == DELTA_DOWNLOADSIZE))
-           {
-             /* old solv file with sizes in kilos. transcode. */
-             dp = data_read_id(dp, &id);
-             incore_add_sizek(&data, (unsigned int)id);
-             break;
-           }
-         /* FALLTHROUGH */
-       default:
-         if (id == RPM_RPMDBID && s && (keys[key].type == REPOKEY_TYPE_U32 || keys[key].type == REPOKEY_TYPE_NUM))
-           {
-             if (keys[key].type == REPOKEY_TYPE_U32)
-               dp = data_read_u32(dp, (unsigned int *)&id);
-             else
-               dp = data_read_id_max(dp, &id, 0, 0, &data);
-             if (!repo->rpmdbid)
-               repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
-             repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
-             break;
-           }
-         dps = dp;
-         dp = data_skip(dp, keys[key].type);
-         if (keys[key].storage == KEY_STORAGE_INCORE)
-           incore_add_blob(&data, dps, dp - dps);
-         break;
-       }
-    }
-  /* should shrink idarraydata again */
-
-  if (keydepth)
-    data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF, depth = %d", keydepth);
-  if (!data.error)
-    {
-      if (dp > bufend)
-       data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
-    }
-  solv_free(buf);
-
-  if (data.error)
-    {
-      /* free solvables */
-      repo_free_solvable_block(repo, data.start, data.end - data.start, 1);
-      /* free id array */
-      repo->idarraysize -= size_idarray;
-      /* free incore data */
-      data.incoredata = solv_free(data.incoredata);
-      data.incoredatalen = data.incoredatafree = 0;
-    }
-
-  if (data.incoredatafree)
-    {
-      /* shrink excess size */
-      data.incoredata = solv_realloc(data.incoredata, data.incoredatalen);
-      data.incoredatafree = 0;
-    }
-  solv_free(idmap);
-
-  /* fixup the special idarray type */
-  for (i = 1; i < numkeys; i++)
-    if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
-      keys[i].type = REPOKEY_TYPE_IDARRAY;
-
-  for (i = 1; i < numkeys; i++)
-    if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
-      break;
-  if (i < numkeys && !data.error)
-    {
-      Id fileoffset = 0;
-      unsigned int pagesize;
-
-      /* we have vertical data, make it available */
-      data.verticaloffset = solv_calloc(numkeys, sizeof(Id));
-      for (i = 1; i < numkeys; i++)
-        if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
-         {
-           data.verticaloffset[i] = fileoffset;
-           fileoffset += keys[i].size;
-         }
-      data.lastverticaloffset = fileoffset;
-      pagesize = read_u32(&data);
-      if (!data.error)
-       {
-         data.error = repopagestore_read_or_setup_pages(&data.store, data.fp, pagesize, fileoffset);
-         if (data.error == SOLV_ERROR_EOF)
-           pool_error(pool, data.error, "repopagestore setup: unexpected EOF");
-         else if (data.error)
-           pool_error(pool, data.error, "repopagestore setup failed");
-       }
-    }
-  data.fp = 0; /* no longer needed */
-
-  if (data.error)
-    {
-      i = data.error;
-      repodata_freedata(&data);
-      return i;
-    }
-
-  if (parent)
-    {
-      /* overwrite stub repodata */
-      repodata_freedata(parent);
-      data.repodataid = parent->repodataid;
-      *parent = data;
-    }
-  else
-    {
-      /* make it available as new repodata */
-      if (!repo->nrepodata)
-       {
-         repo->nrepodata = 1;
-         repo->repodata = solv_calloc(2, sizeof(data));
-       }
-      else
-        repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata + 1, sizeof(data));
-      data.repodataid = repo->nrepodata;
-      repo->repodata[repo->nrepodata++] = data;
-    }
-
-  /* create stub repodata entries for all external */
-  if (!(flags & SOLV_ADD_NO_STUBS) && !parent)
-    {
-      for (key = 1 ; key < data.nkeys; key++)
-       if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY)
-         break;
-      if (key < data.nkeys)
-       repodata_create_stubs(repo->repodata + (repo->nrepodata - 1));
-    }
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_solv took %d ms\n", solv_timems(now));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data.incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
-  return 0;
-}
-
diff --git a/libsolv-0.6.15/src/repo_solv.h b/libsolv-0.6.15/src/repo_solv.h
deleted file mode 100644 (file)
index 0c66394..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_solv.h
- *
- */
-
-#ifndef LIBSOLV_REPO_SOLVE_H
-#define LIBSOLV_REPO_SOLVE_H
-
-#include <stdio.h>
-
-#include "pool.h"
-#include "repo.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int repo_add_solv(Repo *repo, FILE *fp, int flags);
-
-#define SOLV_ADD_NO_STUBS      (1 << 8)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_REPO_SOLVE_H */
diff --git a/libsolv-0.6.15/src/repo_write.c b/libsolv-0.6.15/src/repo_write.c
deleted file mode 100644 (file)
index 210636c..0000000
+++ /dev/null
@@ -1,2084 +0,0 @@
-/*
- * Copyright (c) 2007-2011, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_write.c
- *
- * Write Repo data out to a file in solv format
- *
- * See doc/README.format for a description
- * of the binary file format
- *
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include "pool.h"
-#include "util.h"
-#include "repo_write.h"
-#include "repopage.h"
-
-/*------------------------------------------------------------------*/
-/* Id map optimizations */
-
-typedef struct needid {
-  Id need;
-  Id map;
-} NeedId;
-
-
-#define RELOFF(id) (needid[0].map + GETRELID(id))
-
-/*
- * increment need Id
- * idarray: array of Ids, ID_NULL terminated
- * needid: array of Id->NeedId
- *
- * return size of array (including trailing zero)
- *
- */
-
-static void
-incneedid(Pool *pool, Id id, NeedId *needid)
-{
-  while (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      needid[RELOFF(id)].need++;
-      if (ISRELDEP(rd->evr))
-       incneedid(pool, rd->evr, needid);
-      else
-       needid[rd->evr].need++;
-      id = rd->name;
-    }
-  needid[id].need++;
-}
-
-static int
-incneedidarray(Pool *pool, Id *idarray, NeedId *needid)
-{
-  Id id;
-  int n = 0;
-
-  if (!idarray)
-    return 0;
-  while ((id = *idarray++) != 0)
-    {
-      n++;
-      while (ISRELDEP(id))
-       {
-         Reldep *rd = GETRELDEP(pool, id);
-         needid[RELOFF(id)].need++;
-         if (ISRELDEP(rd->evr))
-           incneedid(pool, rd->evr, needid);
-         else
-           needid[rd->evr].need++;
-         id = rd->name;
-       }
-      needid[id].need++;
-    }
-  return n + 1;
-}
-
-
-/*
- *
- */
-
-static int
-needid_cmp_need(const void *ap, const void *bp, void *dp)
-{
-  const NeedId *a = ap;
-  const NeedId *b = bp;
-  int r;
-  r = b->need - a->need;
-  if (r)
-    return r;
-  return a->map - b->map;
-}
-
-static int
-needid_cmp_need_s(const void *ap, const void *bp, void *dp)
-{
-  const NeedId *a = ap;
-  const NeedId *b = bp;
-  Stringpool *spool = dp;
-  const char *as;
-  const char *bs;
-
-  int r;
-  r = b->need - a->need;
-  if (r)
-    return r;
-  as = spool->stringspace + spool->strings[a->map];
-  bs = spool->stringspace + spool->strings[b->map];
-  return strcmp(as, bs);
-}
-
-
-/*------------------------------------------------------------------*/
-/* output helper routines, used for writing the header */
-/* (the data itself is accumulated in memory and written with
- * write_blob) */
-
-/*
- * unsigned 32-bit
- */
-
-static void
-write_u32(Repodata *data, unsigned int x)
-{
-  FILE *fp = data->fp;
-  if (data->error)
-    return;
-  if (putc(x >> 24, fp) == EOF ||
-      putc(x >> 16, fp) == EOF ||
-      putc(x >> 8, fp) == EOF ||
-      putc(x, fp) == EOF)
-    {
-      data->error = pool_error(data->repo->pool, -1, "write error u32: %s", strerror(errno));
-    }
-}
-
-
-/*
- * unsigned 8-bit
- */
-
-static void
-write_u8(Repodata *data, unsigned int x)
-{
-  if (data->error)
-    return;
-  if (putc(x, data->fp) == EOF)
-    {
-      data->error = pool_error(data->repo->pool, -1, "write error u8: %s", strerror(errno));
-    }
-}
-
-/*
- * data blob
- */
-
-static void
-write_blob(Repodata *data, void *blob, int len)
-{
-  if (data->error)
-    return;
-  if (len && fwrite(blob, len, 1, data->fp) != 1)
-    {
-      data->error = pool_error(data->repo->pool, -1, "write error blob: %s", strerror(errno));
-    }
-}
-
-/*
- * Id
- */
-
-static void
-write_id(Repodata *data, Id x)
-{
-  FILE *fp = data->fp;
-  if (data->error)
-    return;
-  if (x >= (1 << 14))
-    {
-      if (x >= (1 << 28))
-       putc((x >> 28) | 128, fp);
-      if (x >= (1 << 21))
-       putc((x >> 21) | 128, fp);
-      putc((x >> 14) | 128, fp);
-    }
-  if (x >= (1 << 7))
-    putc((x >> 7) | 128, fp);
-  if (putc(x & 127, fp) == EOF)
-    {
-      data->error = pool_error(data->repo->pool, -1, "write error id: %s", strerror(errno));
-    }
-}
-
-static inline void
-write_id_eof(Repodata *data, Id x, int eof)
-{
-  if (x >= 64)
-    x = (x & 63) | ((x & ~63) << 1);
-  write_id(data, x | (eof ? 0 : 64));
-}
-
-
-
-static inline void
-write_str(Repodata *data, const char *str)
-{
-  if (data->error)
-    return;
-  if (fputs(str, data->fp) == EOF || putc(0, data->fp) == EOF)
-    {
-      data->error = pool_error(data->repo->pool, -1, "write error str: %s", strerror(errno));
-    }
-}
-
-/*
- * Array of Ids
- */
-
-static void
-write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids)
-{
-  Id id;
-  if (!ids)
-    return;
-  if (!*ids)
-    {
-      write_u8(data, 0);
-      return;
-    }
-  for (;;)
-    {
-      id = *ids++;
-      if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-      if (id >= 64)
-       id = (id & 63) | ((id & ~63) << 1);
-      if (!*ids)
-       {
-         write_id(data, id);
-         return;
-       }
-      write_id(data, id | 64);
-    }
-}
-
-static int
-cmp_ids(const void *pa, const void *pb, void *dp)
-{
-  Id a = *(Id *)pa;
-  Id b = *(Id *)pb;
-  return a - b;
-}
-
-#if 0
-static void
-write_idarray_sort(Repodata *data, Pool *pool, NeedId *needid, Id *ids, Id marker)
-{
-  int len, i;
-  Id lids[64], *sids;
-
-  if (!ids)
-    return;
-  if (!*ids)
-    {
-      write_u8(data, 0);
-      return;
-    }
-  for (len = 0; len < 64 && ids[len]; len++)
-    {
-      Id id = ids[len];
-      if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-      lids[len] = id;
-    }
-  if (ids[len])
-    {
-      for (i = len + 1; ids[i]; i++)
-       ;
-      sids = solv_malloc2(i, sizeof(Id));
-      memcpy(sids, lids, 64 * sizeof(Id));
-      for (; ids[len]; len++)
-       {
-         Id id = ids[len];
-         if (needid)
-            id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-         sids[len] = id;
-       }
-    }
-  else
-    sids = lids;
-
-  /* That bloody solvable:prereqmarker needs to stay in position :-(  */
-  if (needid)
-    marker = needid[marker].need;
-  for (i = 0; i < len; i++)
-    if (sids[i] == marker)
-      break;
-  if (i > 1)
-    solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
-  if ((len - i) > 2)
-    solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
-
-  Id id, old = 0;
-
-  /* The differencing above produces many runs of ones and twos.  I tried
-     fairly elaborate schemes to RLE those, but they give only very mediocre
-     improvements in compression, as coding the escapes costs quite some
-     space.  Even if they are coded only as bits in IDs.  The best improvement
-     was about 2.7% for the whole .solv file.  It's probably better to
-     invest some complexity into sharing idarrays, than RLEing.  */
-  for (i = 0; i < len - 1; i++)
-    {
-      id = sids[i];
-    /* Ugly PREREQ handling.  A "difference" of 0 is the prereq marker,
-       hence all real differences are offsetted by 1.  Otherwise we would
-       have to handle negative differences, which would cost code space for
-       the encoding of the sign.  We loose the exact mapping of prereq here,
-       but we know the result, so we can recover from that in the reader.  */
-      if (id == marker)
-       id = old = 0;
-      else
-       {
-          id = id - old + 1;
-         old = sids[i];
-       }
-      /* XXX If difference is zero we have multiple equal elements,
-        we might want to skip writing them out.  */
-      if (id >= 64)
-       id = (id & 63) | ((id & ~63) << 1);
-      write_id(data, id | 64);
-    }
-  id = sids[i];
-  if (id == marker)
-    id = 0;
-  else
-    id = id - old + 1;
-  if (id >= 64)
-    id = (id & 63) | ((id & ~63) << 1);
-  write_id(data, id);
-  if (sids != lids)
-    solv_free(sids);
-}
-#endif
-
-
-struct extdata {
-  unsigned char *buf;
-  int len;
-};
-
-struct cbdata {
-  Repo *repo;
-  Repodata *target;
-
-  Stringpool *ownspool;
-  Dirpool *owndirpool;
-
-  Id *keymap;
-  int nkeymap;
-  Id *keymapstart;
-
-  NeedId *needid;
-
-  Id *schema;          /* schema construction space */
-  Id *sp;              /* pointer in above */
-  Id *oldschema, *oldsp;
-
-  Id *solvschemata;
-  Id *subschemata;
-  int nsubschemata;
-  int current_sub;
-
-  struct extdata *extdata;
-
-  Id *dirused;
-
-  Id vstart;
-
-  Id maxdata;
-  Id lastlen;
-
-  int doingsolvables;  /* working on solvables data */
-  int filelistmode;
-};
-
-#define NEEDED_BLOCK 1023
-#define SCHEMATA_BLOCK 31
-#define SCHEMATADATA_BLOCK 255
-#define EXTDATA_BLOCK 4095
-
-static inline void
-data_addid(struct extdata *xd, Id sx)
-{
-  unsigned int x = (unsigned int)sx;
-  unsigned char *dp;
-
-  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
-  dp = xd->buf + xd->len;
-
-  if (x >= (1 << 14))
-    {
-      if (x >= (1 << 28))
-       *dp++ = (x >> 28) | 128;
-      if (x >= (1 << 21))
-       *dp++ = (x >> 21) | 128;
-      *dp++ = (x >> 14) | 128;
-    }
-  if (x >= (1 << 7))
-    *dp++ = (x >> 7) | 128;
-  *dp++ = x & 127;
-  xd->len = dp - xd->buf;
-}
-
-static inline void
-data_addideof(struct extdata *xd, Id sx, int eof)
-{
-  unsigned int x = (unsigned int)sx;
-  unsigned char *dp;
-
-  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
-  dp = xd->buf + xd->len;
-
-  if (x >= (1 << 13))
-    {
-      if (x >= (1 << 27))
-        *dp++ = (x >> 27) | 128;
-      if (x >= (1 << 20))
-        *dp++ = (x >> 20) | 128;
-      *dp++ = (x >> 13) | 128;
-    }
-  if (x >= (1 << 6))
-    *dp++ = (x >> 6) | 128;
-  *dp++ = eof ? (x & 63) : (x & 63) | 64;
-  xd->len = dp - xd->buf;
-}
-
-static inline int
-data_addideof_len(Id sx)
-{
-  unsigned int x = (unsigned int)sx;
-  if (x >= (1 << 13))
-    {
-      if (x >= (1 << 27))
-       return 5;
-      return x >= (1 << 20) ? 4 : 3;
-    }
-  return x >= (1 << 6) ? 2 : 1;
-}
-
-static void
-data_addid64(struct extdata *xd, unsigned int x, unsigned int hx)
-{
-  if (hx)
-    {
-      if (hx > 7)
-        {
-          data_addid(xd, (Id)(hx >> 3));
-          xd->buf[xd->len - 1] |= 128;
-         hx &= 7;
-        }
-      data_addid(xd, (Id)(x | 0x80000000));
-      xd->buf[xd->len - 5] = (x >> 28) | (hx << 4) | 128;
-    }
-  else
-    data_addid(xd, (Id)x);
-}
-
-static void
-data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
-{
-  int len, i;
-  Id lids[64], *sids;
-  Id id, old;
-
-  if (!ids)
-    return;
-  if (!*ids)
-    {
-      data_addid(xd, 0);
-      return;
-    }
-  for (len = 0; len < 64 && ids[len]; len++)
-    {
-      Id id = ids[len];
-      if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-      lids[len] = id;
-    }
-  if (ids[len])
-    {
-      for (i = len + 1; ids[i]; i++)
-       ;
-      sids = solv_malloc2(i, sizeof(Id));
-      memcpy(sids, lids, 64 * sizeof(Id));
-      for (; ids[len]; len++)
-       {
-         Id id = ids[len];
-         if (needid)
-            id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-         sids[len] = id;
-       }
-    }
-  else
-    sids = lids;
-
-  /* That bloody solvable:prereqmarker needs to stay in position :-(  */
-  if (needid)
-    marker = needid[marker].need;
-  for (i = 0; i < len; i++)
-    if (sids[i] == marker)
-      break;
-  if (i > 1)
-    solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
-  if ((len - i) > 2)
-    solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
-
-  old = 0;
-
-  /* The differencing above produces many runs of ones and twos.  I tried
-     fairly elaborate schemes to RLE those, but they give only very mediocre
-     improvements in compression, as coding the escapes costs quite some
-     space.  Even if they are coded only as bits in IDs.  The best improvement
-     was about 2.7% for the whole .solv file.  It's probably better to
-     invest some complexity into sharing idarrays, than RLEing.  */
-  for (i = 0; i < len - 1; i++)
-    {
-      id = sids[i];
-    /* Ugly PREREQ handling.  A "difference" of 0 is the prereq marker,
-       hence all real differences are offsetted by 1.  Otherwise we would
-       have to handle negative differences, which would cost code space for
-       the encoding of the sign.  We loose the exact mapping of prereq here,
-       but we know the result, so we can recover from that in the reader.  */
-      if (id == marker)
-       id = old = 0;
-      else
-       {
-          id = id - old + 1;
-         old = sids[i];
-       }
-      /* XXX If difference is zero we have multiple equal elements,
-        we might want to skip writing them out.  */
-      data_addideof(xd, id, 0);
-    }
-  id = sids[i];
-  if (id == marker)
-    id = 0;
-  else
-    id = id - old + 1;
-  data_addideof(xd, id, 1);
-  if (sids != lids)
-    solv_free(sids);
-}
-
-static inline void
-data_addblob(struct extdata *xd, unsigned char *blob, int len)
-{
-  xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
-  memcpy(xd->buf + xd->len, blob, len);
-  xd->len += len;
-}
-
-static inline void
-data_addu32(struct extdata *xd, unsigned int num)
-{
-  unsigned char d[4];
-  d[0] = num >> 24;
-  d[1] = num >> 16;
-  d[2] = num >> 8;
-  d[3] = num;
-  data_addblob(xd, d, 4);
-}
-
-static Id
-putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
-{
-  const char *str = stringpool_id2str(ss, id);
-  id = stringpool_str2id(cbdata->ownspool, str, 1);
-  if (id >= cbdata->needid[0].map)
-    {
-      int oldoff = cbdata->needid[0].map;
-      int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
-      int nrels = cbdata->repo->pool->nrels;
-      cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
-      if (nrels)
-       memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
-      memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
-      cbdata->needid[0].map = newoff;
-    }
-  return id;
-}
-
-static Id
-putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
-{
-  Id compid, parent;
-
-  parent = dirpool_parent(dp, dir);
-  if (parent)
-    parent = putinowndirpool(cbdata, data, dp, parent);
-  compid = dp->dirs[dir];
-  if (cbdata->ownspool && compid > 1)
-    compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
-  return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
-}
-
-/*
- * collect usage information about the dirs
- * 1: dir used, no child of dir used
- * 2: dir used as parent of another used dir
- */
-static inline void
-setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
-{
-  if (cbdata->dirused[dir])
-    return;
-  cbdata->dirused[dir] = 1;
-  while ((dir = dirpool_parent(dp, dir)) != 0)
-    {
-      if (cbdata->dirused[dir] == 2)
-       return;
-      if (cbdata->dirused[dir])
-        {
-         cbdata->dirused[dir] = 2;
-         return;
-        }
-      cbdata->dirused[dir] = 2;
-    }
-  cbdata->dirused[0] = 2;
-}
-
-/*
- * pass 1 callback:
- * collect key/id/dirid usage information, create needed schemas
- */
-static int
-repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  Id id;
-  int rm;
-
-  if (key->name == REPOSITORY_SOLVABLES)
-    return SEARCH_NEXT_KEY;    /* we do not want this one */
-
-  /* hack: ignore some keys, see BUGS */
-  if (data->repodataid != data->repo->nrepodata - 1)
-    if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
-      return SEARCH_NEXT_KEY;
-
-  rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
-  if (!rm)
-    return SEARCH_NEXT_KEY;    /* we do not want this one */
-
-  /* record key in schema */
-  if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
-      && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
-    *cbdata->sp++ = rm;
-
-  switch(key->type)
-    {
-      case REPOKEY_TYPE_ID:
-      case REPOKEY_TYPE_IDARRAY:
-       id = kv->id;
-       if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
-         id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
-       incneedid(repo->pool, id, cbdata->needid);
-       break;
-      case REPOKEY_TYPE_DIR:
-      case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      case REPOKEY_TYPE_DIRSTRARRAY:
-       id = kv->id;
-       if (cbdata->owndirpool)
-         putinowndirpool(cbdata, data, &data->dirpool, id);
-       else
-         setdirused(cbdata, &data->dirpool, id);
-       break;
-      case REPOKEY_TYPE_FIXARRAY:
-       if (kv->eof == 0)
-         {
-           if (cbdata->oldschema)
-             {
-               cbdata->target->error = pool_error(cbdata->repo->pool, -1, "nested fixarray structs not yet implemented");
-               return SEARCH_NEXT_KEY;
-             }
-           cbdata->oldschema = cbdata->schema;
-           cbdata->oldsp = cbdata->sp;
-           cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id));
-           cbdata->sp = cbdata->schema;
-         }
-       else if (kv->eof == 1)
-         {
-           cbdata->current_sub++;
-           *cbdata->sp = 0;
-           cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
-           cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1);
-#if 0
-           fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
-#endif
-           cbdata->sp = cbdata->schema;
-         }
-       else
-         {
-           solv_free(cbdata->schema);
-           cbdata->schema = cbdata->oldschema;
-           cbdata->sp = cbdata->oldsp;
-           cbdata->oldsp = cbdata->oldschema = 0;
-         }
-       break;
-      case REPOKEY_TYPE_FLEXARRAY:
-       if (kv->entry == 0)
-         {
-           if (kv->eof != 2)
-             *cbdata->sp++ = 0;        /* mark start */
-         }
-       else
-         {
-           /* just finished a schema, rewind */
-           Id *sp = cbdata->sp - 1;
-           *sp = 0;
-           while (sp[-1])
-             sp--;
-           cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
-           cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
-           cbdata->sp = kv->eof == 2 ? sp - 1: sp;
-         }
-       break;
-      default:
-       break;
-    }
-  return 0;
-}
-
-static int
-repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  struct cbdata *cbdata = vcbdata;
-  Repo *repo = data->repo;
-
-#if 0
-  if (s)
-    fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? s - repo->pool->solvables : 0, s ? pool_id2str(repo->pool, s->name) : "", key->name, pool_id2str(repo->pool, key->name), key->type);
-#endif
-  return repo_write_collect_needed(cbdata, repo, data, key, kv);
-}
-
-
-/*
- * pass 2 callback:
- * encode all of the data into the correct buffers
- */
-
-static int
-repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  int rm;
-  Id id;
-  unsigned int u32;
-  unsigned char v[4];
-  struct extdata *xd;
-  NeedId *needid;
-
-  if (key->name == REPOSITORY_SOLVABLES)
-    return SEARCH_NEXT_KEY;
-
-  /* hack: ignore some keys, see BUGS */
-  if (data->repodataid != data->repo->nrepodata - 1)
-    if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
-      return SEARCH_NEXT_KEY;
-
-  rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
-  if (!rm)
-    return SEARCH_NEXT_KEY;    /* we do not want this one */
-
-  if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
-    {
-      xd = cbdata->extdata + rm;       /* vertical buffer */
-      if (cbdata->vstart == -1)
-        cbdata->vstart = xd->len;
-    }
-  else
-    xd = cbdata->extdata + 0;          /* incore buffer */
-  switch(key->type)
-    {
-      case REPOKEY_TYPE_VOID:
-      case REPOKEY_TYPE_CONSTANT:
-      case REPOKEY_TYPE_CONSTANTID:
-       break;
-      case REPOKEY_TYPE_ID:
-       id = kv->id;
-       if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
-         id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
-       needid = cbdata->needid;
-       id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-       data_addid(xd, id);
-       break;
-      case REPOKEY_TYPE_IDARRAY:
-       id = kv->id;
-       if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
-         id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
-       needid = cbdata->needid;
-       id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-       data_addideof(xd, id, kv->eof);
-       break;
-      case REPOKEY_TYPE_STR:
-       data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
-       break;
-      case REPOKEY_TYPE_MD5:
-       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
-       break;
-      case REPOKEY_TYPE_SHA1:
-       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
-       break;
-      case REPOKEY_TYPE_SHA224:
-       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA224);
-       break;
-      case REPOKEY_TYPE_SHA256:
-       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
-       break;
-      case REPOKEY_TYPE_SHA384:
-       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA384);
-       break;
-      case REPOKEY_TYPE_SHA512:
-       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA512);
-       break;
-      case REPOKEY_TYPE_U32:
-       u32 = kv->num;
-       v[0] = u32 >> 24;
-       v[1] = u32 >> 16;
-       v[2] = u32 >> 8;
-       v[3] = u32;
-       data_addblob(xd, v, 4);
-       break;
-      case REPOKEY_TYPE_NUM:
-       data_addid64(xd, kv->num, kv->num2);
-       break;
-      case REPOKEY_TYPE_DIR:
-       id = kv->id;
-       if (cbdata->owndirpool)
-         id = putinowndirpool(cbdata, data, &data->dirpool, id);
-       id = cbdata->dirused[id];
-       data_addid(xd, id);
-       break;
-      case REPOKEY_TYPE_BINARY:
-       data_addid(xd, kv->num);
-       if (kv->num)
-         data_addblob(xd, (unsigned char *)kv->str, kv->num);
-       break;
-      case REPOKEY_TYPE_DIRNUMNUMARRAY:
-       id = kv->id;
-       if (cbdata->owndirpool)
-         id = putinowndirpool(cbdata, data, &data->dirpool, id);
-       id = cbdata->dirused[id];
-       data_addid(xd, id);
-       data_addid(xd, kv->num);
-       data_addideof(xd, kv->num2, kv->eof);
-       break;
-      case REPOKEY_TYPE_DIRSTRARRAY:
-       id = kv->id;
-       if (cbdata->owndirpool)
-         id = putinowndirpool(cbdata, data, &data->dirpool, id);
-       id = cbdata->dirused[id];
-       if (cbdata->filelistmode > 0)
-         {
-           xd->len += data_addideof_len(id) + strlen(kv->str) + 1;
-           break;
-         }
-       data_addideof(xd, id, kv->eof);
-       data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
-       if (cbdata->filelistmode < 0)
-         return 0;
-       break;
-      case REPOKEY_TYPE_FIXARRAY:
-       if (kv->eof == 0)
-         {
-           if (kv->num)
-             {
-               data_addid(xd, kv->num);
-               data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
-#if 0
-               fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
-#endif
-             }
-         }
-       else if (kv->eof == 1)
-         {
-           cbdata->current_sub++;
-         }
-       break;
-      case REPOKEY_TYPE_FLEXARRAY:
-       if (!kv->entry)
-         data_addid(xd, kv->num);
-       if (kv->eof != 2)
-         data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
-       if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
-         {
-           if (xd->len - cbdata->lastlen > cbdata->maxdata)
-             cbdata->maxdata = xd->len - cbdata->lastlen;
-           cbdata->lastlen = xd->len;
-         }
-       break;
-      default:
-       cbdata->target->error = pool_error(cbdata->repo->pool, -1, "unknown type for %d: %d\n", key->name, key->type);
-       break;
-    }
-  if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
-    {
-      /* we can re-use old data in the blob here! */
-      data_addid(cbdata->extdata + 0, cbdata->vstart);                 /* add offset into incore data */
-      data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart);       /* add length into incore data */
-      cbdata->vstart = -1;
-    }
-  return 0;
-}
-
-static int
-repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  struct cbdata *cbdata = vcbdata;
-  return repo_write_adddata(cbdata, data, key, kv);
-}
-
-/* traverse through directory with first child "dir" */
-static int
-traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
-{
-  Id sib, child;
-  Id parent, lastn;
-
-  parent = n;
-  /* special case for '/', which has to come first */
-  if (parent == 1)
-    dirmap[n++] = 1;
-  for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
-    {
-      if (used && !used[sib])
-       continue;
-      if (sib == 1 && parent == 1)
-       continue;       /* already did that one above */
-      dirmap[n++] = sib;
-    }
-
-  /* now go through all the siblings we just added and
-   * do recursive calls on them */
-  lastn = n;
-  for (; parent < lastn; parent++)
-    {
-      sib = dirmap[parent];
-      if (used && used[sib] != 2)      /* 2: used as parent */
-       continue;
-      child = dirpool_child(dp, sib);
-      if (child)
-       {
-         dirmap[n++] = -parent;        /* start new block */
-         n = traverse_dirs(dp, dirmap, n, child, used);
-       }
-    }
-  return n;
-}
-
-static void
-write_compressed_page(Repodata *data, unsigned char *page, int len)
-{
-  int clen;
-  unsigned char cpage[REPOPAGE_BLOBSIZE];
-
-  clen = repopagestore_compress_page(page, len, cpage, len - 1);
-  if (!clen)
-    {
-      write_u32(data, len * 2);
-      write_blob(data, page, len);
-    }
-  else
-    {
-      write_u32(data, clen * 2 + 1);
-      write_blob(data, cpage, clen);
-    }
-}
-
-static Id verticals[] = {
-  SOLVABLE_AUTHORS,
-  SOLVABLE_DESCRIPTION,
-  SOLVABLE_MESSAGEDEL,
-  SOLVABLE_MESSAGEINS,
-  SOLVABLE_EULA,
-  SOLVABLE_DISKUSAGE,
-  SOLVABLE_FILELIST,
-  SOLVABLE_CHECKSUM,
-  DELTA_CHECKSUM,
-  DELTA_SEQ_NUM,
-  SOLVABLE_PKGID,
-  SOLVABLE_HDRID,
-  SOLVABLE_LEADSIGID,
-  SOLVABLE_CHANGELOG_AUTHOR,
-  SOLVABLE_CHANGELOG_TEXT,
-  0
-};
-
-static char *languagetags[] = {
-  "solvable:summary:",
-  "solvable:description:",
-  "solvable:messageins:",
-  "solvable:messagedel:",
-  "solvable:eula:",
-  0
-};
-
-int
-repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
-{
-  const char *keyname;
-  int i;
-
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  keyname = pool_id2str(repo->pool, key->name);
-  for (i = 0; languagetags[i] != 0; i++)
-    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-/*
- * return true if the repodata contains the filelist (and just
- * the filelist). The same code is used in the dataiterator. The way
- * it is used is completely wrong, of course, as having the filelist
- * key does not mean it is used for a specific solvable. Nevertheless
- * it is better to have it than to write broken solv files.
- */
-static inline int
-is_filelist_extension(Repodata *data)
-{
-  int j;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-      return 0;
-  return 1;
-}
-
-
-static int
-write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vpage, int lpage)
-{
-  unsigned char *dp = xd->buf;
-  int l = xd->len;
-  while (l)
-    {
-      int ll = REPOPAGE_BLOBSIZE - lpage;
-      if (l < ll)
-       ll = l;
-      memcpy(vpage + lpage, dp, ll);
-      dp += ll;
-      lpage += ll;
-      l -= ll;
-      if (lpage == REPOPAGE_BLOBSIZE)
-       {
-         write_compressed_page(target, vpage, lpage);
-         lpage = 0;
-       }
-    }
-  return lpage;
-}
-
-/*
- * Repo
- */
-
-/*
- * the code works the following way:
- *
- * 1) find which keys should be written
- * 2) collect usage information for keys/ids/dirids, create schema
- *    data
- * 3) use usage information to create mapping tables, so that often
- *    used ids get a lower number
- * 4) encode data into buffers using the mapping tables
- * 5) write everything to disk
- */
-int
-repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
-{
-  Pool *pool = repo->pool;
-  int i, j, n, lastfilelistn;
-  Solvable *s;
-  NeedId *needid;
-  int nstrings, nrels;
-  unsigned int sizeid;
-  unsigned int solv_flags;
-  Reldep *ran;
-  Id *idarraydata;
-
-  Id id, *sp;
-
-  Id *dirmap;
-  int ndirmap;
-  Id *keyused;
-  unsigned char *repodataused;
-  int anyrepodataused = 0;
-  int anysolvableused = 0;
-
-  struct cbdata cbdata;
-  int clonepool;
-  Repokey *key;
-  int poolusage, dirpoolusage, idused, dirused;
-  int reloff;
-
-  Repodata *data, *dirpooldata;
-
-  Repodata target;
-
-  Stringpool *spool;
-  Dirpool *dirpool;
-
-  Id mainschema;
-
-  struct extdata *xd;
-
-  Id type_constantid = REPOKEY_TYPE_CONSTANTID;
-
-
-  memset(&cbdata, 0, sizeof(cbdata));
-  cbdata.repo = repo;
-  cbdata.target = &target;
-
-  repodata_initdata(&target, repo, 1);
-
-  /* go through all repodata and find the keys we need */
-  /* also unify keys */
-  /*          keymapstart - maps repo number to keymap offset */
-  /*          keymap      - maps repo key to my key, 0 -> not used */
-
-  /* start with all KEY_STORAGE_SOLVABLE ids */
-
-  n = ID_NUM_INTERNAL;
-  FOR_REPODATAS(repo, i, data)
-    n += data->nkeys;
-  cbdata.keymap = solv_calloc(n, sizeof(Id));
-  cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
-  repodataused = solv_calloc(repo->nrepodata, 1);
-
-  clonepool = 0;
-  poolusage = 0;
-
-  /* add keys for STORAGE_SOLVABLE */
-  for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
-    {
-      Repokey keyd;
-      keyd.name = i;
-      if (i < SOLVABLE_PROVIDES)
-        keyd.type = REPOKEY_TYPE_ID;
-      else if (i < RPM_RPMDBID)
-        keyd.type = REPOKEY_TYPE_REL_IDARRAY;
-      else
-        keyd.type = REPOKEY_TYPE_NUM;
-      keyd.size = 0;
-      keyd.storage = KEY_STORAGE_SOLVABLE;
-      if (keyfilter)
-       {
-         keyd.storage = keyfilter(repo, &keyd, kfdata);
-         if (keyd.storage == KEY_STORAGE_DROPPED)
-           continue;
-         keyd.storage = KEY_STORAGE_SOLVABLE;
-       }
-      poolusage = 1;
-      clonepool = 1;
-      cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
-    }
-
-  if (repo->nsolvables)
-    {
-      Repokey keyd;
-      keyd.name = REPOSITORY_SOLVABLES;
-      keyd.type = REPOKEY_TYPE_FLEXARRAY;
-      keyd.size = 0;
-      keyd.storage = KEY_STORAGE_INCORE;
-      cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
-    }
-
-  dirpoolusage = 0;
-
-  spool = 0;
-  dirpool = 0;
-  dirpooldata = 0;
-  n = ID_NUM_INTERNAL;
-  lastfilelistn = 0;
-  FOR_REPODATAS(repo, i, data)
-    {
-      cbdata.keymapstart[i] = n;
-      cbdata.keymap[n++] = 0;  /* key 0 */
-      idused = 0;
-      dirused = 0;
-      if (keyfilter)
-       {
-         Repokey keyd;
-         /* check if we want this repodata */
-         memset(&keyd, 0, sizeof(keyd));
-         keyd.name = 1;
-         keyd.type = 1;
-         keyd.size = i;
-         if (keyfilter(repo, &keyd, kfdata) == -1)
-           continue;
-       }
-      for (j = 1; j < data->nkeys; j++, n++)
-       {
-         key = data->keys + j;
-         if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
-           {
-             cbdata.keymap[n] = cbdata.keymap[key->name];
-             continue;
-           }
-         if (key->type == REPOKEY_TYPE_DELETED)
-           {
-             cbdata.keymap[n] = 0;
-             continue;
-           }
-         if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool)
-           {
-             Repokey keyd = *key;
-             keyd.size = repodata_globalize_id(data, key->size, 1);
-             id = repodata_key2id(&target, &keyd, 0);
-           }
-         else
-           id = repodata_key2id(&target, key, 0);
-         if (!id)
-           {
-             Repokey keyd = *key;
-             keyd.storage = KEY_STORAGE_INCORE;
-             if (keyd.type == REPOKEY_TYPE_CONSTANTID)
-               keyd.size = repodata_globalize_id(data, key->size, 1);
-             else if (keyd.type != REPOKEY_TYPE_CONSTANT)
-               keyd.size = 0;
-             if (keyfilter)
-               {
-                 keyd.storage = keyfilter(repo, &keyd, kfdata);
-                 if (keyd.storage == KEY_STORAGE_DROPPED)
-                   {
-                     cbdata.keymap[n] = 0;
-                     continue;
-                   }
-               }
-             id = repodata_key2id(&target, &keyd, 1);
-           }
-         cbdata.keymap[n] = id;
-         /* load repodata if not already loaded */
-         if (data->state == REPODATA_STUB)
-           {
-             if (data->loadcallback)
-               data->loadcallback(data);
-             else
-               data->state = REPODATA_ERROR;
-             if (data->state != REPODATA_ERROR)
-               {
-                 /* redo this repodata! */
-                 j = 0;
-                 n = cbdata.keymapstart[i];
-                 continue;
-               }
-           }
-         if (data->state == REPODATA_ERROR)
-           {
-             /* too bad! */
-             cbdata.keymap[n] = 0;
-             continue;
-           }
-
-         repodataused[i] = 1;
-         anyrepodataused = 1;
-         if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID ||
-              key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
-           idused = 1;
-         else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
-           {
-             idused = 1;       /* dirs also use ids */
-             dirused = 1;
-           }
-         if (key->type == REPOKEY_TYPE_DIRSTRARRAY && key->name == SOLVABLE_FILELIST)
-           {
-             /* is this a file list extension */
-             if (is_filelist_extension(data))
-               {
-                 /* hmm, we have a file list extension. Kill filelist of other repodata.
-                  * XXX: this is wrong, as the extension does not need to cover all
-                  * solvables of the other repodata */
-                 if (lastfilelistn)
-                   cbdata.keymap[lastfilelistn] = 0;
-               }
-             else
-               lastfilelistn = n;
-           }
-       }
-      if (idused)
-       {
-         if (data->localpool)
-           {
-             if (poolusage)
-               poolusage = 3;  /* need own pool */
-             else
-               {
-                 poolusage = 2;
-                 spool = &data->spool;
-               }
-           }
-         else
-           {
-             if (poolusage == 0)
-               poolusage = 1;
-             else if (poolusage != 1)
-               poolusage = 3;  /* need own pool */
-           }
-       }
-      if (dirused)
-       {
-         if (dirpoolusage)
-           dirpoolusage = 3;   /* need own dirpool */
-         else
-           {
-             dirpoolusage = 2;
-             dirpool = &data->dirpool;
-             dirpooldata = data;
-           }
-       }
-    }
-  cbdata.nkeymap = n;
-
-  /* 0: no pool needed at all */
-  /* 1: use global pool */
-  /* 2: use repodata local pool */
-  /* 3: need own pool */
-  if (poolusage == 3)
-    {
-      spool = &target.spool;
-      /* hack: reuse global pool data so we don't have to map pool ids */
-      if (clonepool)
-       {
-         stringpool_free(spool);
-         stringpool_clone(spool, &pool->ss);
-       }
-      cbdata.ownspool = spool;
-    }
-  else if (poolusage == 0 || poolusage == 1)
-    {
-      poolusage = 1;
-      spool = &pool->ss;
-    }
-
-  if (dirpoolusage == 3)
-    {
-      dirpool = &target.dirpool;
-      dirpooldata = 0;
-      cbdata.owndirpool = dirpool;
-    }
-  else if (dirpool)
-    cbdata.dirused = solv_calloc(dirpool->ndirs, sizeof(Id));
-
-
-/********************************************************************/
-#if 0
-fprintf(stderr, "poolusage: %d\n", poolusage);
-fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
-fprintf(stderr, "nkeys: %d\n", target.nkeys);
-for (i = 1; i < target.nkeys; i++)
-  fprintf(stderr, "  %2d: %s[%d] %d %d %d\n", i, pool_id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage);
-#endif
-
-  /* copy keys if requested */
-  if (keyq)
-    {
-      queue_empty(keyq);
-      for (i = 1; i < target.nkeys; i++)
-       queue_push2(keyq, target.keys[i].name, target.keys[i].type);
-    }
-
-  if (poolusage > 1)
-    {
-      /* put all the keys we need in our string pool */
-      /* put mapped ids right into target.keys */
-      for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
-       {
-         key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
-         if (key->type == REPOKEY_TYPE_CONSTANTID)
-           {
-             key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
-             type_constantid = key->type;
-             key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
-           }
-         else
-           key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
-       }
-      if (poolusage == 2)
-       stringpool_freehash(spool);     /* free some mem */
-    }
-
-
-/********************************************************************/
-
-  /* set needed count of all strings and rels,
-   * find which keys are used in the solvables
-   * put all strings in own spool
-   */
-
-  reloff = spool->nstrings;
-  if (poolusage == 3)
-    reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
-
-  needid = calloc(reloff + pool->nrels, sizeof(*needid));
-  needid[0].map = reloff;
-
-  cbdata.needid = needid;
-  cbdata.schema = solv_calloc(target.nkeys, sizeof(Id));
-  cbdata.sp = cbdata.schema;
-  cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));
-
-  /* create main schema */
-  cbdata.sp = cbdata.schema;
-  /* collect all other data from all repodatas */
-  /* XXX: merge arrays of equal keys? */
-  FOR_REPODATAS(repo, j, data)
-    {
-      if (!repodataused[j])
-       continue;
-      repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
-    }
-  sp = cbdata.sp;
-  /* add solvables if needed (may revert later) */
-  if (repo->nsolvables)
-    {
-      *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
-      target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
-    }
-  *sp = 0;
-  mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
-
-  idarraydata = repo->idarraydata;
-
-  anysolvableused = 0;
-  cbdata.doingsolvables = 1;
-  for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
-    {
-      if (s->repo != repo)
-       continue;
-
-      /* set schema info, keep in sync with further down */
-      sp = cbdata.schema;
-      if (cbdata.keymap[SOLVABLE_NAME])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_NAME];
-         needid[s->name].need++;
-       }
-      if (cbdata.keymap[SOLVABLE_ARCH])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_ARCH];
-         needid[s->arch].need++;
-       }
-      if (cbdata.keymap[SOLVABLE_EVR])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_EVR];
-         needid[s->evr].need++;
-       }
-      if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_VENDOR];
-         needid[s->vendor].need++;
-       }
-      if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
-        {
-          *sp++ = cbdata.keymap[SOLVABLE_PROVIDES];
-         target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid);
-       }
-      if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES];
-         target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
-       }
-      if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS];
-         target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
-       }
-      if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_REQUIRES];
-         target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid);
-       }
-      if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS];
-         target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid);
-       }
-      if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS];
-         target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid);
-       }
-      if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS];
-         target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid);
-       }
-      if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_ENHANCES];
-         target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid);
-       }
-      if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
-       {
-          *sp++ = cbdata.keymap[RPM_RPMDBID];
-         target.keys[cbdata.keymap[RPM_RPMDBID]].size++;
-       }
-      cbdata.sp = sp;
-
-      if (anyrepodataused)
-       {
-         FOR_REPODATAS(repo, j, data)
-           {
-             if (!repodataused[j])
-               continue;
-             if (i < data->start || i >= data->end)
-               continue;
-             repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
-             needid = cbdata.needid;
-           }
-       }
-      *cbdata.sp = 0;
-      cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1);
-      if (cbdata.solvschemata[n])
-       anysolvableused = 1;
-      n++;
-    }
-  cbdata.doingsolvables = 0;
-  assert(n == repo->nsolvables);
-
-  if (repo->nsolvables && !anysolvableused)
-    {
-      /* strip off solvable from the main schema */
-      target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0;
-      sp = cbdata.schema;
-      for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++)
-       {
-         *sp = target.schemadata[target.schemata[mainschema] + i];
-         if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES])
-           sp++;
-       }
-      assert(target.schemadatalen == target.schemata[mainschema] + i + 1);
-      *sp = 0;
-      target.schemadatalen = target.schemata[mainschema];
-      target.nschemata--;
-      repodata_free_schemahash(&target);
-      mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
-    }
-
-/********************************************************************/
-
-  /* remove unused keys */
-  keyused = solv_calloc(target.nkeys, sizeof(Id));
-  for (i = 1; i < (int)target.schemadatalen; i++)
-    keyused[target.schemadata[i]] = 1;
-  keyused[0] = 0;
-  for (n = i = 1; i < target.nkeys; i++)
-    {
-      if (!keyused[i])
-       continue;
-      keyused[i] = n;
-      if (i != n)
-       {
-         target.keys[n] = target.keys[i];
-         if (keyq)
-           {
-             keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2];
-             keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1];
-           }
-       }
-      n++;
-    }
-  target.nkeys = n;
-  if (keyq)
-    queue_truncate(keyq, 2 * n - 2);
-
-  /* update schema data to the new key ids */
-  for (i = 1; i < (int)target.schemadatalen; i++)
-    target.schemadata[i] = keyused[target.schemadata[i]];
-  /* update keymap to the new key ids */
-  for (i = 0; i < cbdata.nkeymap; i++)
-    cbdata.keymap[i] = keyused[cbdata.keymap[i]];
-  keyused = solv_free(keyused);
-
-  /* increment needid of the used keys, they are already mapped to
-   * the correct string pool  */
-  for (i = 1; i < target.nkeys; i++)
-    {
-      if (target.keys[i].type == type_constantid)
-       needid[target.keys[i].size].need++;
-      needid[target.keys[i].name].need++;
-      needid[target.keys[i].type].need++;
-    }
-
-/********************************************************************/
-
-  if (dirpool && cbdata.dirused && !cbdata.dirused[0])
-    {
-      /* no dirs used at all */
-      cbdata.dirused = solv_free(cbdata.dirused);
-      dirpool = 0;
-    }
-
-  /* increment need id for used dir components */
-  if (dirpool)
-    {
-      /* if we have own dirpool, all entries in it are used.
-        also, all comp ids are already mapped by putinowndirpool(),
-        so we can simply increment needid.
-        (owndirpool != 0, dirused == 0, dirpooldata == 0) */
-      /* else we re-use a dirpool of repodata "dirpooldata".
-        dirused tells us which of the ids are used.
-        we need to map comp ids if we generate a new pool.
-        (owndirpool == 0, dirused != 0, dirpooldata != 0) */
-      for (i = 1; i < dirpool->ndirs; i++)
-       {
-#if 0
-fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
-#endif
-         if (cbdata.dirused && !cbdata.dirused[i])
-           continue;
-         id = dirpool->dirs[i];
-         if (id <= 0)
-           continue;
-         if (dirpooldata && cbdata.ownspool && id > 1)
-           {
-             id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
-             needid = cbdata.needid;
-           }
-         needid[id].need++;
-       }
-    }
-
-
-/********************************************************************/
-
-  /*
-   * create mapping table, new keys are sorted by needid[].need
-   *
-   * needid[key].need : old key -> new key
-   * needid[key].map  : new key -> old key
-   */
-
-  /* zero out id 0 and rel 0 just in case */
-  reloff = needid[0].map;
-  needid[0].need = 0;
-  needid[reloff].need = 0;
-
-  for (i = 1; i < reloff + pool->nrels; i++)
-    needid[i].map = i;
-
-#if 0
-  solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
-#else
-  /* make first entry '' */
-  needid[1].need = 1;
-  solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
-#endif
-  solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
-  /* now needid is in new order, needid[newid].map -> oldid */
-
-  /* calculate string space size, also zero out needid[].need */
-  sizeid = 0;
-  for (i = 1; i < reloff; i++)
-    {
-      if (!needid[i].need)
-        break; /* as we have sorted, every entry after this also has need == 0 */
-      needid[i].need = 0;
-      sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
-    }
-  nstrings = i;        /* our new string id end */
-
-  /* make needid[oldid].need point to newid */
-  for (i = 1; i < nstrings; i++)
-    needid[needid[i].map].need = i;
-
-  /* same as above for relations */
-  for (i = 0; i < pool->nrels; i++)
-    {
-      if (!needid[reloff + i].need)
-        break;
-      needid[reloff + i].need = 0;
-    }
-  nrels = i;   /* our new rel id end */
-
-  for (i = 0; i < nrels; i++)
-    needid[needid[reloff + i].map].need = nstrings + i;
-
-  /* now we have: needid[oldid].need -> newid
-                  needid[newid].map  -> oldid
-     both for strings and relations  */
-
-
-/********************************************************************/
-
-  ndirmap = 0;
-  dirmap = 0;
-  if (dirpool)
-    {
-      /* create our new target directory structure by traversing through all
-       * used dirs. This will concatenate blocks with the same parent
-       * directory into single blocks.
-       * Instead of components, traverse_dirs stores the old dirids,
-       * we will change this in the second step below */
-      /* (dirpooldata and dirused are 0 if we have our own dirpool) */
-      if (cbdata.dirused && !cbdata.dirused[1])
-       cbdata.dirused[1] = 1;  /* always want / entry */
-      dirmap = solv_calloc(dirpool->ndirs, sizeof(Id));
-      dirmap[0] = 0;
-      ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
-
-      /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */
-      /* change dirmap so that it maps from "new dirid" to "new compid" */
-      if (!cbdata.dirused)
-       cbdata.dirused = solv_malloc2(dirpool->ndirs, sizeof(Id));
-      memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
-      for (i = 1; i < ndirmap; i++)
-       {
-         if (dirmap[i] <= 0)
-           continue;
-         cbdata.dirused[dirmap[i]] = i;
-         id = dirpool->dirs[dirmap[i]];
-         if (dirpooldata && cbdata.ownspool && id > 1)
-           id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
-         dirmap[i] = needid[id].need;
-       }
-      /* now the new target directory structure is complete (dirmap), and we have
-       * dirused[olddirid] -> newdirid */
-    }
-
-/********************************************************************/
-
-  /* collect all data
-   * we use extdata[0] for incore data and extdata[keyid] for vertical data
-   */
-
-  cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
-
-  xd = cbdata.extdata;
-  cbdata.current_sub = 0;
-  /* add main schema */
-  cbdata.lastlen = 0;
-  data_addid(xd, mainschema);
-
-#if 1
-  FOR_REPODATAS(repo, j, data)
-    {
-      if (!repodataused[j])
-       continue;
-      repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
-    }
-#endif
-
-  if (xd->len - cbdata.lastlen > cbdata.maxdata)
-    cbdata.maxdata = xd->len - cbdata.lastlen;
-  cbdata.lastlen = xd->len;
-
-  if (anysolvableused)
-    {
-      data_addid(xd, repo->nsolvables);        /* FLEXARRAY nentries */
-      cbdata.doingsolvables = 1;
-
-      /* check if we can do the special filelist memory optimization */
-      if (anyrepodataused)
-       {
-         for (i = 1; i < target.nkeys; i++)
-           if (target.keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
-             cbdata.filelistmode |= cbdata.filelistmode == 0 && target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY ? 1 : 2;
-           else if (target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY)
-             cbdata.filelistmode = 2;
-         if (cbdata.filelistmode != 1)
-           cbdata.filelistmode = 0;
-       }
-
-      for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
-       {
-         if (s->repo != repo)
-           continue;
-         data_addid(xd, cbdata.solvschemata[n]);
-         if (cbdata.keymap[SOLVABLE_NAME])
-           data_addid(xd, needid[s->name].need);
-         if (cbdata.keymap[SOLVABLE_ARCH])
-           data_addid(xd, needid[s->arch].need);
-         if (cbdata.keymap[SOLVABLE_EVR])
-           data_addid(xd, needid[s->evr].need);
-         if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
-           data_addid(xd, needid[s->vendor].need);
-         if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
-         if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
-         if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
-         if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
-         if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
-         if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
-         if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
-         if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
-         if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
-           data_addid(xd, repo->rpmdbid[i - repo->start]);
-         if (anyrepodataused)
-           {
-             cbdata.vstart = -1;
-             FOR_REPODATAS(repo, j, data)
-               {
-                 if (!repodataused[j])
-                   continue;
-                 if (i < data->start || i >= data->end)
-                   continue;
-                 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
-               }
-           }
-         if (xd->len - cbdata.lastlen > cbdata.maxdata)
-           cbdata.maxdata = xd->len - cbdata.lastlen;
-         cbdata.lastlen = xd->len;
-         n++;
-       }
-      cbdata.doingsolvables = 0;
-    }
-
-  assert(cbdata.current_sub == cbdata.nsubschemata);
-  if (cbdata.subschemata)
-    {
-      cbdata.subschemata = solv_free(cbdata.subschemata);
-      cbdata.nsubschemata = 0;
-    }
-
-/********************************************************************/
-
-  target.fp = fp;
-
-  /* write header */
-
-  /* write file header */
-  write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
-  write_u32(&target, SOLV_VERSION_8);
-
-
-  /* write counts */
-  write_u32(&target, nstrings);
-  write_u32(&target, nrels);
-  write_u32(&target, ndirmap);
-  write_u32(&target, anysolvableused ? repo->nsolvables : 0);
-  write_u32(&target, target.nkeys);
-  write_u32(&target, target.nschemata);
-  solv_flags = 0;
-  solv_flags |= SOLV_FLAG_PREFIX_POOL;
-  solv_flags |= SOLV_FLAG_SIZE_BYTES;
-  write_u32(&target, solv_flags);
-
-  if (nstrings)
-    {
-      /*
-       * calculate prefix encoding of the strings
-       */
-      unsigned char *prefixcomp = solv_malloc(nstrings);
-      unsigned int compsum = 0;
-      char *old_str = "";
-
-      prefixcomp[0] = 0;
-      for (i = 1; i < nstrings; i++)
-       {
-         char *str = spool->stringspace + spool->strings[needid[i].map];
-         int same;
-         for (same = 0; same < 255; same++)
-           if (!old_str[same] || old_str[same] != str[same])
-             break;
-         prefixcomp[i] = same;
-         compsum += same;
-         old_str = str;
-       }
-
-      /*
-       * write strings
-       */
-      write_u32(&target, sizeid);
-      /* we save compsum bytes but need 1 extra byte for every string */
-      write_u32(&target, sizeid + nstrings - 1 - compsum);
-      for (i = 1; i < nstrings; i++)
-       {
-         char *str = spool->stringspace + spool->strings[needid[i].map];
-         write_u8(&target, prefixcomp[i]);
-         write_str(&target, str + prefixcomp[i]);
-       }
-      solv_free(prefixcomp);
-    }
-  else
-    {
-      write_u32(&target, 0);
-      write_u32(&target, 0);
-    }
-
-  /*
-   * write RelDeps
-   */
-  for (i = 0; i < nrels; i++)
-    {
-      ran = pool->rels + (needid[reloff + i].map - reloff);
-      write_id(&target, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
-      write_id(&target, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
-      write_u8(&target, ran->flags);
-    }
-
-  /*
-   * write dirs (skip both root and / entry)
-   */
-  for (i = 2; i < ndirmap; i++)
-    {
-      if (dirmap[i] > 0)
-        write_id(&target, dirmap[i]);
-      else
-        write_id(&target, nstrings - dirmap[i]);
-    }
-  solv_free(dirmap);
-
-  /*
-   * write keys
-   */
-  for (i = 1; i < target.nkeys; i++)
-    {
-      write_id(&target, needid[target.keys[i].name].need);
-      write_id(&target, needid[target.keys[i].type].need);
-      if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
-       {
-         if (target.keys[i].type == type_constantid)
-            write_id(&target, needid[target.keys[i].size].need);
-         else
-            write_id(&target, target.keys[i].size);
-       }
-      else
-        write_id(&target, cbdata.extdata[i].len);
-      write_id(&target, target.keys[i].storage);
-    }
-
-  /*
-   * write schemata
-   */
-  write_id(&target, target.schemadatalen);     /* XXX -1? */
-  for (i = 1; i < target.nschemata; i++)
-    write_idarray(&target, pool, 0, repodata_id2schema(&target, i));
-
-/********************************************************************/
-
-  write_id(&target, cbdata.maxdata);
-  write_id(&target, cbdata.extdata[0].len);
-  if (cbdata.extdata[0].len)
-    write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len);
-  solv_free(cbdata.extdata[0].buf);
-
-  /* do we have vertical data? */
-  for (i = 1; i < target.nkeys; i++)
-    if (cbdata.extdata[i].len)
-      break;
-  if (i < target.nkeys)
-    {
-      /* yes, write it in pages */
-      unsigned char vpage[REPOPAGE_BLOBSIZE];
-      int lpage = 0;
-
-      write_u32(&target, REPOPAGE_BLOBSIZE);
-      for (i = 1; i < target.nkeys; i++)
-       if (cbdata.extdata[i].len)
-         {
-           if (cbdata.filelistmode)
-             break;
-           lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage);
-         }
-      if (cbdata.filelistmode && i < target.nkeys)
-       {
-         /* ok, just this single extdata, which is a filelist */
-         xd = cbdata.extdata + i;
-         xd->len = 0;
-         cbdata.filelistmode = -1;
-         for (j = 0; j < cbdata.nkeymap; j++)
-           if (cbdata.keymap[j] != i)
-             cbdata.keymap[j] = 0;
-         for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
-           {
-             if (s->repo != repo)
-               continue;
-             FOR_REPODATAS(repo, j, data)
-               {
-                 if (!repodataused[j])
-                   continue;
-                 if (i < data->start || i >= data->end)
-                   continue;
-                 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
-               }
-             if (xd->len > 1024 * 1024)
-               {
-                 lpage = write_compressed_extdata(&target, xd, vpage, lpage);
-                 xd->len = 0;
-               }
-           }
-         if (xd->len)
-           lpage = write_compressed_extdata(&target, xd, vpage, lpage);
-       }
-      if (lpage)
-       write_compressed_page(&target, vpage, lpage);
-    }
-
-  for (i = 1; i < target.nkeys; i++)
-    solv_free(cbdata.extdata[i].buf);
-  solv_free(cbdata.extdata);
-
-  target.fp = 0;
-  repodata_freedata(&target);
-
-  solv_free(needid);
-  solv_free(cbdata.solvschemata);
-  solv_free(cbdata.schema);
-
-  solv_free(cbdata.keymap);
-  solv_free(cbdata.keymapstart);
-  solv_free(cbdata.dirused);
-  solv_free(repodataused);
-  return target.error;
-}
-
-struct repodata_write_data {
-  int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
-  void *kfdata;
-  int repodataid;
-};
-
-static int
-repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
-{
-  struct repodata_write_data *wd = kfdata;
-
-  /* XXX: special repodata selection hack */
-  if (key->name == 1 && key->size != wd->repodataid)
-    return -1;
-  if (key->storage == KEY_STORAGE_SOLVABLE)
-    return KEY_STORAGE_DROPPED;        /* not part of this repodata */
-  if (wd->keyfilter)
-    return (*wd->keyfilter)(repo, key, wd->kfdata);
-  return key->storage;
-}
-
-int
-repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
-{
-  struct repodata_write_data wd;
-
-  wd.keyfilter = keyfilter;
-  wd.kfdata = kfdata;
-  wd.repodataid = data->repodataid;
-  return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq);
-}
-
-int
-repodata_write(Repodata *data, FILE *fp)
-{
-  return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0);
-}
-
-int
-repo_write(Repo *repo, FILE *fp)
-{
-  return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0);
-}
diff --git a/libsolv-0.6.15/src/repo_write.h b/libsolv-0.6.15/src/repo_write.h
deleted file mode 100644 (file)
index 763147e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repo_write.h
- *
- */
-
-#ifndef REPO_WRITE_H
-#define REPO_WRITE_H
-
-#include <stdio.h>
-
-#include "repo.h"
-#include "queue.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int repo_write(Repo *repo, FILE *fp);
-extern int repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
-
-extern int repodata_write(Repodata *data , FILE *fp);
-extern int repodata_write_filtered(Repodata *data , FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
-
-extern int repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libsolv-0.6.15/src/repodata.c b/libsolv-0.6.15/src/repodata.c
deleted file mode 100644 (file)
index ad3e71a..0000000
+++ /dev/null
@@ -1,3671 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repodata.c
- *
- * Manage data coming from one repository
- *
- * a repository can contain multiple repodata entries, consisting of
- * different sets of keys and different sets of solvables
- */
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <fnmatch.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <regex.h>
-
-#include "repo.h"
-#include "pool.h"
-#include "poolid_private.h"
-#include "util.h"
-#include "hash.h"
-#include "chksum.h"
-
-#include "repopack.h"
-#include "repopage.h"
-
-#define REPODATA_BLOCK 255
-
-static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
-
-void
-repodata_initdata(Repodata *data, Repo *repo, int localpool)
-{
-  memset(data, 0, sizeof (*data));
-  data->repodataid = data - repo->repodata;
-  data->repo = repo;
-  data->localpool = localpool;
-  if (localpool)
-    stringpool_init_empty(&data->spool);
-  /* dirpool_init(&data->dirpool);     just zeros out again */
-  data->keys = solv_calloc(1, sizeof(Repokey));
-  data->nkeys = 1;
-  data->schemata = solv_calloc(1, sizeof(Id));
-  data->schemadata = solv_calloc(1, sizeof(Id));
-  data->nschemata = 1;
-  data->schemadatalen = 1;
-  repopagestore_init(&data->store);
-}
-
-void
-repodata_freedata(Repodata *data)
-{
-  int i;
-
-  solv_free(data->keys);
-
-  solv_free(data->schemata);
-  solv_free(data->schemadata);
-  solv_free(data->schematahash);
-
-  stringpool_free(&data->spool);
-  dirpool_free(&data->dirpool);
-
-  solv_free(data->mainschemaoffsets);
-  solv_free(data->incoredata);
-  solv_free(data->incoreoffset);
-  solv_free(data->verticaloffset);
-
-  repopagestore_free(&data->store);
-
-  solv_free(data->vincore);
-
-  if (data->attrs)
-    for (i = 0; i < data->end - data->start; i++)
-      solv_free(data->attrs[i]);
-  solv_free(data->attrs);
-  if (data->xattrs)
-    for (i = 0; i < data->nxattrs; i++)
-      solv_free(data->xattrs[i]);
-  solv_free(data->xattrs);
-
-  solv_free(data->attrdata);
-  solv_free(data->attriddata);
-  solv_free(data->attrnum64data);
-
-  solv_free(data->dircache);
-}
-
-void
-repodata_free(Repodata *data)
-{
-  Repo *repo = data->repo;
-  int i = data - repo->repodata;
-  if (i == 0)
-    return;
-  repodata_freedata(data);
-  if (i < repo->nrepodata - 1)
-    {
-      /* whoa! this changes the repodataids! */
-      memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
-      for (; i < repo->nrepodata - 1; i++)
-       repo->repodata[i].repodataid = i;
-    }
-  repo->nrepodata--;
-  if (repo->nrepodata == 1)
-    {
-      repo->repodata = solv_free(repo->repodata);
-      repo->nrepodata = 0;
-    }
-}
-
-void
-repodata_empty(Repodata *data, int localpool)
-{
-  void (*loadcallback)(Repodata *) = data->loadcallback;
-  int state = data->state;
-  repodata_freedata(data);
-  repodata_initdata(data, data->repo, localpool);
-  data->state = state;
-  data->loadcallback = loadcallback;
-}
-
-
-/***************************************************************
- * key pool management
- */
-
-/* this is not so time critical that we need a hash, so we do a simple
- * linear search */
-Id
-repodata_key2id(Repodata *data, Repokey *key, int create)
-{
-  Id keyid;
-
-  for (keyid = 1; keyid < data->nkeys; keyid++)
-    if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
-      {
-        if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
-          continue;
-        break;
-      }
-  if (keyid == data->nkeys)
-    {
-      if (!create)
-       return 0;
-      /* allocate new key */
-      data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
-      data->keys[data->nkeys++] = *key;
-      if (data->verticaloffset)
-        {
-          data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
-          data->verticaloffset[data->nkeys - 1] = 0;
-        }
-      data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
-    }
-  return keyid;
-}
-
-
-/***************************************************************
- * schema pool management
- */
-
-#define SCHEMATA_BLOCK 31
-#define SCHEMATADATA_BLOCK 255
-
-Id
-repodata_schema2id(Repodata *data, Id *schema, int create)
-{
-  int h, len, i;
-  Id *sp, cid;
-  Id *schematahash;
-
-  if (!*schema)
-    return 0;  /* XXX: allow empty schema? */
-  if ((schematahash = data->schematahash) == 0)
-    {
-      data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
-      for (i = 1; i < data->nschemata; i++)
-       {
-         for (sp = data->schemadata + data->schemata[i], h = 0; *sp;)
-           h = h * 7 + *sp++;
-         h &= 255;
-         schematahash[h] = i;
-       }
-      data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
-      data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
-    }
-
-  for (sp = schema, len = 0, h = 0; *sp; len++)
-    h = h * 7 + *sp++;
-  h &= 255;
-  len++;
-
-  cid = schematahash[h];
-  if (cid)
-    {
-      if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
-        return cid;
-      /* cache conflict, do a slow search */
-      for (cid = 1; cid < data->nschemata; cid++)
-        if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
-          return cid;
-    }
-  /* a new one */
-  if (!create)
-    return 0;
-  data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
-  data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
-  /* add schema */
-  memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
-  data->schemata[data->nschemata] = data->schemadatalen;
-  data->schemadatalen += len;
-  schematahash[h] = data->nschemata;
-#if 0
-fprintf(stderr, "schema2id: new schema\n");
-#endif
-  return data->nschemata++;
-}
-
-void
-repodata_free_schemahash(Repodata *data)
-{
-  data->schematahash = solv_free(data->schematahash);
-  /* shrink arrays */
-  data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
-  data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
-}
-
-
-/***************************************************************
- * dir pool management
- */
-
-#ifndef HAVE_STRCHRNUL
-static inline const char *strchrnul(const char *str, char x)
-{
-  const char *p = strchr(str, x);
-  return p ? p : str + strlen(str);
-}
-#endif
-
-#define DIRCACHE_SIZE 41       /* < 1k */
-
-#ifdef DIRCACHE_SIZE
-struct dircache {
-  Id ids[DIRCACHE_SIZE];
-  char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
-};
-#endif
-
-Id
-repodata_str2dir(Repodata *data, const char *dir, int create)
-{
-  Id id, parent;
-#ifdef DIRCACHE_SIZE
-  const char *dirs;
-#endif
-  const char *dire;
-
-  parent = 0;
-  if (!*dir)
-    return 0;
-  while (*dir == '/' && dir[1] == '/')
-    dir++;
-  if (*dir == '/' && !dir[1])
-    {
-      if (data->dirpool.ndirs)
-        return 1;
-      return dirpool_add_dir(&data->dirpool, 0, 1, create);
-    }
-#ifdef DIRCACHE_SIZE
-  dirs = dir;
-  if (data->dircache)
-    {
-      int l;
-      struct dircache *dircache = data->dircache;
-      l = strlen(dir);
-      while (l > 0)
-       {
-         if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
-           {
-             parent = dircache->ids[l];
-             dir += l;
-             if (!*dir)
-               return parent;
-             while (*dir == '/')
-               dir++;
-             break;
-           }
-         while (--l)
-           if (dir[l] == '/')
-             break;
-       }
-    }
-#endif
-  while (*dir)
-    {
-      dire = strchrnul(dir, '/');
-      if (data->localpool)
-        id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
-      else
-       id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
-      if (!id)
-       return 0;
-      parent = dirpool_add_dir(&data->dirpool, parent, id, create);
-      if (!parent)
-       return 0;
-#ifdef DIRCACHE_SIZE
-      if (!data->dircache)
-       data->dircache = solv_calloc(1, sizeof(struct dircache));
-      if (data->dircache)
-       {
-         int l = dire - dirs;
-         if (l < DIRCACHE_SIZE)
-           {
-             data->dircache->ids[l] = parent;
-             memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
-           }
-       }
-#endif
-      if (!*dire)
-       break;
-      dir = dire + 1;
-      while (*dir == '/')
-       dir++;
-    }
-  return parent;
-}
-
-void
-repodata_free_dircache(Repodata *data)
-{
-  data->dircache = solv_free(data->dircache);
-}
-
-const char *
-repodata_dir2str(Repodata *data, Id did, const char *suf)
-{
-  Pool *pool = data->repo->pool;
-  int l = 0;
-  Id parent, comp;
-  const char *comps;
-  char *p;
-
-  if (!did)
-    return suf ? suf : "";
-  parent = did;
-  while (parent)
-    {
-      comp = dirpool_compid(&data->dirpool, parent);
-      comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
-      l += strlen(comps);
-      parent = dirpool_parent(&data->dirpool, parent);
-      if (parent)
-       l++;
-    }
-  if (suf)
-    l += strlen(suf) + 1;
-  p = pool_alloctmpspace(pool, l + 1) + l;
-  *p = 0;
-  if (suf)
-    {
-      p -= strlen(suf);
-      strcpy(p, suf);
-      *--p = '/';
-    }
-  parent = did;
-  while (parent)
-    {
-      comp = dirpool_compid(&data->dirpool, parent);
-      comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
-      l = strlen(comps);
-      p -= l;
-      strncpy(p, comps, l);
-      parent = dirpool_parent(&data->dirpool, parent);
-      if (parent)
-        *--p = '/';
-    }
-  return p;
-}
-
-
-/***************************************************************
- * data management
- */
-
-static inline unsigned char *
-data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
-{
-  Id *keyp = data->schemadata + data->schemata[schema];
-  for (; *keyp; keyp++)
-    dp = data_skip_key(data, dp, data->keys + *keyp);
-  return dp;
-}
-
-static unsigned char *
-data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
-{
-  int nentries, schema;
-  switch(key->type)
-    {
-    case REPOKEY_TYPE_FIXARRAY:
-      dp = data_read_id(dp, &nentries);
-      if (!nentries)
-       return dp;
-      dp = data_read_id(dp, &schema);
-      while (nentries--)
-       dp = data_skip_schema(data, dp, schema);
-      return dp;
-    case REPOKEY_TYPE_FLEXARRAY:
-      dp = data_read_id(dp, &nentries);
-      while (nentries--)
-       {
-         dp = data_read_id(dp, &schema);
-         dp = data_skip_schema(data, dp, schema);
-       }
-      return dp;
-    default:
-      if (key->storage == KEY_STORAGE_INCORE)
-        dp = data_skip(dp, key->type);
-      else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-       {
-         dp = data_skip(dp, REPOKEY_TYPE_ID);
-         dp = data_skip(dp, REPOKEY_TYPE_ID);
-       }
-      return dp;
-    }
-}
-
-static unsigned char *
-forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
-{
-  Id k;
-
-  if (!keyid)
-    return 0;
-  if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
-    {
-      int i;
-      for (i = 0; (k = *keyp++) != 0; i++)
-        if (k == keyid)
-         return data->incoredata + data->mainschemaoffsets[i];
-      return 0;
-    }
-  while ((k = *keyp++) != 0)
-    {
-      if (k == keyid)
-       return dp;
-      if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
-       {
-         dp = data_skip(dp, REPOKEY_TYPE_ID);  /* skip offset */
-         dp = data_skip(dp, REPOKEY_TYPE_ID);  /* skip length */
-         continue;
-       }
-      if (data->keys[k].storage != KEY_STORAGE_INCORE)
-       continue;
-      dp = data_skip_key(data, dp, data->keys + k);
-    }
-  return 0;
-}
-
-static unsigned char *
-get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
-{
-  unsigned char *dp;
-  if (len <= 0)
-    return 0;
-  if (off >= data->lastverticaloffset)
-    {
-      off -= data->lastverticaloffset;
-      if ((unsigned int)off + len > data->vincorelen)
-       return 0;
-      return data->vincore + off;
-    }
-  if ((unsigned int)off + len > key->size)
-    return 0;
-  /* we now have the offset, go into vertical */
-  off += data->verticaloffset[key - data->keys];
-  /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
-  dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
-  data->storestate++;
-  if (dp)
-    dp += off % REPOPAGE_BLOBSIZE;
-  return dp;
-}
-
-static inline unsigned char *
-get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
-{
-  unsigned char *dp = *dpp;
-
-  if (!dp)
-    return 0;
-  if (key->storage == KEY_STORAGE_INCORE)
-    {
-      if (advance)
-        *dpp = data_skip_key(data, dp, key);
-      return dp;
-    }
-  else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-    {
-      Id off, len;
-      dp = data_read_id(dp, &off);
-      dp = data_read_id(dp, &len);
-      if (advance)
-        *dpp = dp;
-      return get_vertical_data(data, key, off, len);
-    }
-  return 0;
-}
-
-static int
-load_repodata(Repodata *data)
-{
-  if (data->loadcallback)
-    {
-      data->loadcallback(data);
-      if (data->state == REPODATA_AVAILABLE)
-       return 1;
-    }
-  data->state = REPODATA_ERROR;
-  return 0;
-}
-
-static inline int
-maybe_load_repodata(Repodata *data, Id keyname)
-{
-  if (keyname && !repodata_precheck_keyname(data, keyname))
-    return 0;  /* do not bother... */
-  switch(data->state)
-    {
-    case REPODATA_STUB:
-      if (keyname)
-       {
-         int i;
-         for (i = 1; i < data->nkeys; i++)
-           if (keyname == data->keys[i].name)
-             break;
-         if (i == data->nkeys)
-           return 0;
-       }
-      return load_repodata(data);
-    case REPODATA_ERROR:
-      return 0;
-    case REPODATA_AVAILABLE:
-    case REPODATA_LOADING:
-      return 1;
-    default:
-      data->state = REPODATA_ERROR;
-      return 0;
-    }
-}
-
-static inline unsigned char *
-solvid2data(Repodata *data, Id solvid, Id *schemap)
-{
-  unsigned char *dp = data->incoredata;
-  if (!dp)
-    return 0;
-  if (solvid == SOLVID_META)
-    dp += 1;   /* offset of "meta" solvable */
-  else if (solvid == SOLVID_POS)
-    {
-      Pool *pool = data->repo->pool;
-      if (data->repo != pool->pos.repo)
-       return 0;
-      if (data != data->repo->repodata + pool->pos.repodataid)
-       return 0;
-      dp += pool->pos.dp;
-      if (pool->pos.dp != 1)
-        {
-          *schemap = pool->pos.schema;
-          return dp;
-       }
-    }
-  else
-    {
-      if (solvid < data->start || solvid >= data->end)
-       return 0;
-      dp += data->incoreoffset[solvid - data->start];
-    }
-  return data_read_id(dp, schemap);
-}
-
-/************************************************************************
- * data lookup
- */
-
-static unsigned char *
-find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
-{
-  unsigned char *dp;
-  Id schema, *keyp, *kp;
-  Repokey *key;
-
-  if (!maybe_load_repodata(data, keyname))
-    return 0;
-  dp = solvid2data(data, solvid, &schema);
-  if (!dp)
-    return 0;
-  keyp = data->schemadata + data->schemata[schema];
-  for (kp = keyp; *kp; kp++)
-    if (data->keys[*kp].name == keyname)
-      break;
-  if (!*kp)
-    return 0;
-  *keypp = key = data->keys + *kp;
-  if (key->type == REPOKEY_TYPE_DELETED)
-    return 0;
-  if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
-    return dp; /* no need to forward... */
-  if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
-    return 0;  /* get_data will not work, no need to forward */
-  dp = forward_to_key(data, *kp, keyp, dp);
-  if (!dp)
-    return 0;
-  return get_data(data, key, &dp, 0);
-}
-
-Id
-repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
-{
-  Id schema, *keyp, *kp;
-  if (!maybe_load_repodata(data, keyname))
-    return 0;
-  if (!solvid2data(data, solvid, &schema))
-    return 0;
-  keyp = data->schemadata + data->schemata[schema];
-  for (kp = keyp; *kp; kp++)
-    if (data->keys[*kp].name == keyname)
-      return data->keys[*kp].type;
-  return 0;
-}
-
-Id
-repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
-{
-  unsigned char *dp;
-  Repokey *key;
-  Id id;
-
-  dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  if (key->type == REPOKEY_TYPE_CONSTANTID)
-    return key->size;
-  if (key->type != REPOKEY_TYPE_ID)
-    return 0;
-  dp = data_read_id(dp, &id);
-  return id;
-}
-
-const char *
-repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
-{
-  unsigned char *dp;
-  Repokey *key;
-  Id id;
-
-  dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  if (key->type == REPOKEY_TYPE_STR)
-    return (const char *)dp;
-  if (key->type == REPOKEY_TYPE_CONSTANTID)
-    id = key->size;
-  else if (key->type == REPOKEY_TYPE_ID)
-    dp = data_read_id(dp, &id);
-  else
-    return 0;
-  if (data->localpool)
-    return stringpool_id2str(&data->spool, id);
-  return pool_id2str(data->repo->pool, id);
-}
-
-int
-repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
-{
-  unsigned char *dp;
-  Repokey *key;
-  unsigned int high, low;
-
-  *value = 0;
-  dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  switch (key->type)
-    {
-    case REPOKEY_TYPE_NUM:
-      data_read_num64(dp, &low, &high);
-      *value = (unsigned long long)high << 32 | low;
-      return 1;
-    case REPOKEY_TYPE_U32:
-      data_read_u32(dp, &low);
-      *value = low;
-      return 1;
-    case REPOKEY_TYPE_CONSTANT:
-      *value = key->size;
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-int
-repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
-{
-  Id schema;
-  Id *keyp;
-  unsigned char *dp;
-
-  if (!maybe_load_repodata(data, keyname))
-    return 0;
-  dp = solvid2data(data, solvid, &schema);
-  if (!dp)
-    return 0;
-  /* can't use find_key_data as we need to test the type */
-  for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
-    if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
-      return 1;
-  return 0;
-}
-
-const unsigned char *
-repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
-{
-  unsigned char *dp;
-  Repokey *key;
-
-  dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  switch (key->type)
-    {
-    case_CHKSUM_TYPES:
-      break;
-    default:
-      return 0;
-    }
-  *typep = key->type;
-  return dp;
-}
-
-int
-repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
-{
-  unsigned char *dp;
-  Repokey *key;
-  Id id;
-  int eof = 0;
-
-  queue_empty(q);
-  dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  if (key->type != REPOKEY_TYPE_IDARRAY)
-    return 0;
-  for (;;)
-    {
-      dp = data_read_ideof(dp, &id, &eof);
-      queue_push(q, id);
-      if (eof)
-       break;
-    }
-  return 1;
-}
-
-const void *
-repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
-{
-  unsigned char *dp;
-  Repokey *key;
-  Id len;
-
-  dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp || key->type != REPOKEY_TYPE_BINARY)
-    {
-      *lenp = 0;
-      return 0;
-    }
-  dp = data_read_id(dp, &len);
-  *lenp = len;
-  return dp;
-}
-
-Id
-repodata_globalize_id(Repodata *data, Id id, int create)
-{
-  if (!id || !data || !data->localpool)
-    return id;
-  return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
-}
-
-Id
-repodata_localize_id(Repodata *data, Id id, int create)
-{
-  if (!id || !data || !data->localpool)
-    return id;
-  return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
-}
-
-Id
-repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
-{
-  if (!id || !data || !fromdata)
-    return id;
-  if (!data->localpool || !fromdata->localpool)
-    {
-      if (fromdata->localpool)
-       id = repodata_globalize_id(fromdata, id, create);
-      if (data->localpool)
-       id = repodata_localize_id(data, id, create);
-      return id;
-    }
-  /* localpool is set in both data and fromdata */
-  return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
-}
-
-Id
-repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
-{
-  Id *ap;
-  if (!data->attrs)
-    return 0;
-  ap = data->attrs[solvid - data->start];
-  if (!ap)
-    return 0;
-  for (; *ap; ap += 2)
-    {
-      if (data->keys[*ap].name != keyname)
-       continue;
-      if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
-       return voidid;
-      if (data->keys[*ap].type == REPOKEY_TYPE_ID)
-       return ap[1];
-      return 0;
-    }
-  return 0;
-}
-
-const char *
-repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp)
-{
-  Id *ap, did;
-  Id iter = *iterp;
-  if (iter == 0)       /* find key data */
-    {
-      if (!data->attrs)
-       return 0;
-      ap = data->attrs[solvid - data->start];
-      if (!ap)
-       return 0;
-      for (; *ap; ap += 2)
-       if (data->keys[*ap].name == keyname && data->keys[*ap].type == REPOKEY_TYPE_DIRSTRARRAY)
-         break;
-      if (!*ap)
-       return 0;
-      iter = ap[1];
-    }
-  did = *didp;
-  for (ap = data->attriddata + iter; *ap; ap += 2)
-    {
-      if (did && ap[0] != did)
-       continue;
-      *didp = ap[0];
-      *iterp = ap - data->attriddata + 2;
-      return (const char *)data->attrdata + ap[1];
-    }
-  *iterp = 0;
-  return 0;
-}
-
-/************************************************************************
- * data search
- */
-
-
-const char *
-repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
-{
-  switch (key->type)
-    {
-    case REPOKEY_TYPE_ID:
-    case REPOKEY_TYPE_CONSTANTID:
-    case REPOKEY_TYPE_IDARRAY:
-      if (data && data->localpool)
-       kv->str = stringpool_id2str(&data->spool, kv->id);
-      else
-       kv->str = pool_id2str(pool, kv->id);
-      if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
-       {
-         const char *s;
-         for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
-           ;
-         if (*s == ':' && s > kv->str)
-           kv->str = s + 1;
-       }
-      return kv->str;
-    case REPOKEY_TYPE_STR:
-      return kv->str;
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      if (!(flags & SEARCH_FILES))
-       return kv->str; /* match just the basename */
-      if (kv->num)
-       return kv->str; /* already stringified */
-      /* Put the full filename into kv->str.  */
-      kv->str = repodata_dir2str(data, kv->id, kv->str);
-      kv->num = 1;     /* mark stringification */
-      return kv->str;
-    case_CHKSUM_TYPES:
-      if (!(flags & SEARCH_CHECKSUMS))
-       return 0;       /* skip em */
-      if (kv->num)
-       return kv->str; /* already stringified */
-      kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
-      kv->num = 1;     /* mark stringification */
-      return kv->str;
-    default:
-      return 0;
-    }
-}
-
-
-struct subschema_data {
-  Solvable *s;
-  void *cbdata;
-  KeyValue *parent;
-};
-
-/* search a specific repodata */
-void
-repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
-{
-  Id schema;
-  Repokey *key;
-  Id keyid, *kp, *keyp;
-  unsigned char *dp, *ddp;
-  int onekey = 0;
-  int stop;
-  KeyValue kv;
-  Solvable *s;
-
-  if (!maybe_load_repodata(data, keyname))
-    return;
-  if (solvid == SOLVID_SUBSCHEMA)
-    {
-      struct subschema_data *subd = cbdata;
-      cbdata = subd->cbdata;
-      s = subd->s;
-      schema = subd->parent->id;
-      dp = (unsigned char *)subd->parent->str;
-      kv.parent = subd->parent;
-    }
-  else
-    {
-      schema = 0;
-      dp = solvid2data(data, solvid, &schema);
-      if (!dp)
-       return;
-      s = data->repo->pool->solvables + solvid;
-      kv.parent = 0;
-    }
-  keyp = data->schemadata + data->schemata[schema];
-  if (keyname)
-    {
-      /* search for a specific key */
-      for (kp = keyp; *kp; kp++)
-       if (data->keys[*kp].name == keyname)
-         break;
-      if (!*kp)
-       return;
-      dp = forward_to_key(data, *kp, keyp, dp);
-      if (!dp)
-       return;
-      keyp = kp;
-      onekey = 1;
-    }
-  while ((keyid = *keyp++) != 0)
-    {
-      stop = 0;
-      key = data->keys + keyid;
-      ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
-
-      if (key->type == REPOKEY_TYPE_DELETED)
-       continue;
-      if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
-       {
-         struct subschema_data subd;
-         int nentries;
-         Id schema = 0;
-
-         subd.cbdata = cbdata;
-         subd.s = s;
-         subd.parent = &kv;
-         ddp = data_read_id(ddp, &nentries);
-         kv.num = nentries;
-         kv.entry = 0;
-         kv.eof = 0;
-          while (ddp && nentries > 0)
-           {
-             if (!--nentries)
-               kv.eof = 1;
-             if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
-               ddp = data_read_id(ddp, &schema);
-             kv.id = schema;
-             kv.str = (char *)ddp;
-             stop = callback(cbdata, s, data, key, &kv);
-             if (stop > SEARCH_NEXT_KEY)
-               return;
-             if (stop && stop != SEARCH_ENTERSUB)
-               break;
-             if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
-               repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
-             ddp = data_skip_schema(data, ddp, schema);
-             kv.entry++;
-           }
-         if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
-           {
-             /* sentinel */
-             kv.eof = 2;
-             kv.str = (char *)ddp;
-             stop = callback(cbdata, s, data, key, &kv);
-             if (stop > SEARCH_NEXT_KEY)
-               return;
-           }
-         if (onekey)
-           return;
-         continue;
-       }
-      kv.entry = 0;
-      do
-       {
-         ddp = data_fetch(ddp, &kv, key);
-         if (!ddp)
-           break;
-         stop = callback(cbdata, s, data, key, &kv);
-         kv.entry++;
-       }
-      while (!kv.eof && !stop);
-      if (onekey || stop > SEARCH_NEXT_KEY)
-       return;
-    }
-}
-
-void
-repodata_setpos_kv(Repodata *data, KeyValue *kv)
-{
-  Pool *pool = data->repo->pool;
-  if (!kv)
-    pool_clear_pos(pool);
-  else
-    {
-      pool->pos.repo = data->repo;
-      pool->pos.repodataid = data - data->repo->repodata;
-      pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
-      pool->pos.schema = kv->id;
-    }
-}
-
-/************************************************************************
- * data iterator functions
- */
-
-static inline Id *
-solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
-{
-  kv->id = keyname;
-  switch (keyname)
-    {
-    case SOLVABLE_NAME:
-      kv->eof = 1;
-      return &s->name;
-    case SOLVABLE_ARCH:
-      kv->eof = 1;
-      return &s->arch;
-    case SOLVABLE_EVR:
-      kv->eof = 1;
-      return &s->evr;
-    case SOLVABLE_VENDOR:
-      kv->eof = 1;
-      return &s->vendor;
-    case SOLVABLE_PROVIDES:
-      kv->eof = 0;
-      return s->provides ? s->repo->idarraydata + s->provides : 0;
-    case SOLVABLE_OBSOLETES:
-      kv->eof = 0;
-      return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
-    case SOLVABLE_CONFLICTS:
-      kv->eof = 0;
-      return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
-    case SOLVABLE_REQUIRES:
-      kv->eof = 0;
-      return s->requires ? s->repo->idarraydata + s->requires : 0;
-    case SOLVABLE_RECOMMENDS:
-      kv->eof = 0;
-      return s->recommends ? s->repo->idarraydata + s->recommends : 0;
-    case SOLVABLE_SUPPLEMENTS:
-      kv->eof = 0;
-      return s->supplements ? s->repo->idarraydata + s->supplements : 0;
-    case SOLVABLE_SUGGESTS:
-      kv->eof = 0;
-      return s->suggests ? s->repo->idarraydata + s->suggests : 0;
-    case SOLVABLE_ENHANCES:
-      kv->eof = 0;
-      return s->enhances ? s->repo->idarraydata + s->enhances : 0;
-    case RPM_RPMDBID:
-      kv->eof = 1;
-      return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
-    default:
-      return 0;
-    }
-}
-
-int
-datamatcher_init(Datamatcher *ma, const char *match, int flags)
-{
-  match = match ? solv_strdup(match) : 0;
-  ma->match = match;
-  ma->flags = flags;
-  ma->error = 0;
-  ma->matchdata = 0;
-  if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
-    {
-      ma->matchdata = solv_calloc(1, sizeof(regex_t));
-      ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
-      if (ma->error)
-       {
-         solv_free(ma->matchdata);
-         ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
-       }
-    }
-  if ((flags & SEARCH_FILES) != 0 && match)
-    {
-      /* prepare basename check */
-      if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
-       {
-         const char *p = strrchr(match, '/');
-         ma->matchdata = (void *)(p ? p + 1 : match);
-       }
-      else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
-       {
-         const char *p;
-         for (p = match + strlen(match) - 1; p >= match; p--)
-           if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
-             break;
-         ma->matchdata = (void *)(p + 1);
-       }
-    }
-  return ma->error;
-}
-
-void
-datamatcher_free(Datamatcher *ma)
-{
-  if (ma->match)
-    ma->match = solv_free((char *)ma->match);
-  if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
-    {
-      regfree(ma->matchdata);
-      solv_free(ma->matchdata);
-    }
-  ma->matchdata = 0;
-}
-
-int
-datamatcher_match(Datamatcher *ma, const char *str)
-{
-  int l;
-  switch ((ma->flags & SEARCH_STRINGMASK))
-    {
-    case SEARCH_SUBSTRING:
-      if (ma->flags & SEARCH_NOCASE)
-       return strcasestr(str, ma->match) != 0;
-      else
-       return strstr(str, ma->match) != 0;
-    case SEARCH_STRING:
-      if (ma->flags & SEARCH_NOCASE)
-       return !strcasecmp(ma->match, str);
-      else
-       return !strcmp(ma->match, str);
-    case SEARCH_STRINGSTART:
-      if (ma->flags & SEARCH_NOCASE)
-        return !strncasecmp(ma->match, str, strlen(ma->match));
-      else
-        return !strncmp(ma->match, str, strlen(ma->match));
-    case SEARCH_STRINGEND:
-      l = strlen(str) - strlen(ma->match);
-      if (l < 0)
-       return 0;
-      if (ma->flags & SEARCH_NOCASE)
-       return !strcasecmp(ma->match, str + l);
-      else
-       return !strcmp(ma->match, str + l);
-    case SEARCH_GLOB:
-      return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
-    case SEARCH_REGEX:
-      return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
-    default:
-      return 0;
-    }
-}
-
-/* check if the matcher can match the provides basename */
-
-int
-datamatcher_checkbasename(Datamatcher *ma, const char *basename)
-{
-  int l;
-  const char *match = ma->matchdata;
-  if (!match)
-    return 1;
-  switch (ma->flags & SEARCH_STRINGMASK)
-    {
-    case SEARCH_STRING:
-      break;
-    case SEARCH_STRINGEND:
-      if (match != ma->match)
-       break;          /* had slash, do exact match on basename */
-      /* FALLTHROUGH */
-    case SEARCH_GLOB:
-      /* check if the basename ends with match */
-      l = strlen(basename) - strlen(match);
-      if (l < 0)
-       return 0;
-      basename += l;
-      break;
-    default:
-      return 1;        /* maybe matches */
-    }
-  if ((ma->flags & SEARCH_NOCASE) != 0)
-    return !strcasecmp(match, basename);
-  else
-    return !strcmp(match, basename);
-}
-
-int
-repodata_filelistfilter_matches(Repodata *data, const char *str)
-{
-  /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
-  /* for now hardcoded */
-  if (strstr(str, "bin/"))
-    return 1;
-  if (!strncmp(str, "/etc/", 5))
-    return 1;
-  if (!strcmp(str, "/usr/lib/sendmail"))
-    return 1;
-  return 0;
-}
-
-
-enum {
-  di_bye,
-
-  di_enterrepo,
-  di_entersolvable,
-  di_enterrepodata,
-  di_enterschema,
-  di_enterkey,
-
-  di_nextattr,
-  di_nextkey,
-  di_nextrepodata,
-  di_nextsolvable,
-  di_nextrepo,
-
-  di_enterarray,
-  di_nextarrayelement,
-
-  di_entersub,
-  di_leavesub,
-
-  di_nextsolvablekey,
-  di_entersolvablekey,
-  di_nextsolvableattr
-};
-
-/* see dataiterator.h for documentation */
-int
-dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
-{
-  memset(di, 0, sizeof(*di));
-  di->pool = pool;
-  di->flags = flags & ~SEARCH_THISSOLVID;
-  if (!pool || (repo && repo->pool != pool))
-    {
-      di->state = di_bye;
-      return -1;
-    }
-  if (match)
-    {
-      int error;
-      if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
-       {
-         di->state = di_bye;
-         return error;
-       }
-    }
-  di->keyname = keyname;
-  di->keynames[0] = keyname;
-  dataiterator_set_search(di, repo, p);
-  return 0;
-}
-
-void
-dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
-{
-  *di = *from;
-  if (di->dupstr)
-    {
-      if (di->dupstr == di->kv.str)
-        di->dupstr = solv_memdup(di->dupstr, di->dupstrn);
-      else
-       {
-         di->dupstr = 0;
-         di->dupstrn = 0;
-       }
-    }
-  memset(&di->matcher, 0, sizeof(di->matcher));
-  if (from->matcher.match)
-    datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
-  if (di->nparents)
-    {
-      /* fix pointers */
-      int i;
-      for (i = 1; i < di->nparents; i++)
-       di->parents[i].kv.parent = &di->parents[i - 1].kv;
-      di->kv.parent = &di->parents[di->nparents - 1].kv;
-    }
-}
-
-int
-dataiterator_set_match(Dataiterator *di, const char *match, int flags)
-{
-  di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
-  datamatcher_free(&di->matcher);
-  memset(&di->matcher, 0, sizeof(di->matcher));
-  if (match)
-    {
-      int error;
-      if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
-       {
-         di->state = di_bye;
-         return error;
-       }
-    }
-  return 0;
-}
-
-void
-dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
-{
-  di->repo = repo;
-  di->repoid = 0;
-  di->flags &= ~SEARCH_THISSOLVID;
-  di->nparents = 0;
-  di->rootlevel = 0;
-  di->repodataid = 1;
-  if (!di->pool->urepos)
-    {
-      di->state = di_bye;
-      return;
-    }
-  if (!repo)
-    {
-      di->repoid = 1;
-      di->repo = di->pool->repos[di->repoid];
-    }
-  di->state = di_enterrepo;
-  if (p)
-    dataiterator_jump_to_solvid(di, p);
-}
-
-void
-dataiterator_set_keyname(Dataiterator *di, Id keyname)
-{
-  di->nkeynames = 0;
-  di->keyname = keyname;
-  di->keynames[0] = keyname;
-}
-
-void
-dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
-{
-  int i;
-
-  if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
-    {
-      di->state = di_bye;      /* sorry */
-      return;
-    }
-  for (i = di->nkeynames + 1; i > 0; i--)
-    di->keynames[i] = di->keynames[i - 1];
-  di->keynames[0] = di->keyname = keyname;
-  di->nkeynames++;
-}
-
-void
-dataiterator_free(Dataiterator *di)
-{
-  if (di->matcher.match)
-    datamatcher_free(&di->matcher);
-  if (di->dupstr)
-    solv_free(di->dupstr);
-}
-
-static unsigned char *
-dataiterator_find_keyname(Dataiterator *di, Id keyname)
-{
-  Id *keyp;
-  Repokey *keys = di->data->keys, *key;
-  unsigned char *dp;
-
-  for (keyp = di->keyp; *keyp; keyp++)
-    if (keys[*keyp].name == keyname)
-      break;
-  if (!*keyp)
-    return 0;
-  key = keys + *keyp;
-  if (key->type == REPOKEY_TYPE_DELETED)
-    return 0;
-  if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
-    return 0;          /* get_data will not work, no need to forward */
-  dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
-  if (!dp)
-    return 0;
-  di->keyp = keyp;
-  return dp;
-}
-
-static inline int
-is_filelist_extension(Repodata *data)
-{
-  int j;
-  if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
-    return 0;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name == SOLVABLE_FILELIST)
-      break;
-  if (j == data->nkeys)
-    return 0;
-  if (data->state != REPODATA_AVAILABLE)
-    return 1;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-      return 0;
-  return 1;
-}
-
-static int
-dataiterator_filelistcheck(Dataiterator *di)
-{
-  int j;
-  int needcomplete = 0;
-  Repodata *data = di->data;
-
-  if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
-    if (!di->matcher.match
-       || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
-           && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
-       || !repodata_filelistfilter_matches(data, di->matcher.match))
-      needcomplete = 1;
-  if (data->state != REPODATA_AVAILABLE)
-    return needcomplete ? 1 : 0;
-  if (!needcomplete)
-    {
-      /* we don't need the complete filelist, so ignore all stubs */
-      if (data->repo->nrepodata == 2)
-       return 1;
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-         return 1;
-      return 0;
-    }
-  else
-    {
-      /* we need the complete filelist. check if we habe a filtered filelist and there's
-       * a extension with the complete filelist later on */
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name == SOLVABLE_FILELIST)
-         break;
-      if (j == data->nkeys)
-       return 0;       /* does not have filelist */
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-         break;
-      if (j == data->nkeys)
-       return 1;       /* this is the externsion */
-      while (data - data->repo->repodata + 1 < data->repo->nrepodata)
-       {
-         data++;
-         if (is_filelist_extension(data))
-           return 0;
-       }
-      return 1;
-    }
-}
-
-int
-dataiterator_step(Dataiterator *di)
-{
-  Id schema;
-
-  if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
-    unsigned int ddpoff = di->ddp - di->vert_ddp;
-    di->vert_off += ddpoff;
-    di->vert_len -= ddpoff;
-    di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
-    di->vert_storestate = di->data->storestate;
-    if (!di->ddp)
-      di->state = di_nextkey;
-  }
-  for (;;)
-    {
-      switch (di->state)
-       {
-       case di_enterrepo: di_enterrepo:
-         if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
-           goto di_nextrepo;
-         if (!(di->flags & SEARCH_THISSOLVID))
-           {
-             di->solvid = di->repo->start - 1; /* reset solvid iterator */
-             goto di_nextsolvable;
-           }
-         /* FALLTHROUGH */
-
-       case di_entersolvable: di_entersolvable:
-         if (di->repodataid)
-           {
-             di->repodataid = 1;       /* reset repodata iterator */
-             if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
-               {
-                 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
-
-                 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
-                 di->data = 0;
-                 goto di_entersolvablekey;
-               }
-           }
-         /* FALLTHROUGH */
-
-       case di_enterrepodata: di_enterrepodata:
-         if (di->repodataid)
-           {
-             if (di->repodataid >= di->repo->nrepodata)
-               goto di_nextsolvable;
-             di->data = di->repo->repodata + di->repodataid;
-           }
-         if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
-           goto di_nextrepodata;
-         if (!maybe_load_repodata(di->data, di->keyname))
-           goto di_nextrepodata;
-         di->dp = solvid2data(di->data, di->solvid, &schema);
-         if (!di->dp)
-           goto di_nextrepodata;
-         if (di->solvid == SOLVID_POS)
-           di->solvid = di->pool->pos.solvid;
-         /* reset key iterator */
-         di->keyp = di->data->schemadata + di->data->schemata[schema];
-         /* FALLTHROUGH */
-
-       case di_enterschema: di_enterschema:
-         if (di->keyname)
-           di->dp = dataiterator_find_keyname(di, di->keyname);
-         if (!di->dp || !*di->keyp)
-           {
-             if (di->kv.parent)
-               goto di_leavesub;
-             goto di_nextrepodata;
-           }
-         /* FALLTHROUGH */
-
-       case di_enterkey: di_enterkey:
-         di->kv.entry = -1;
-         di->key = di->data->keys + *di->keyp;
-         if (!di->dp)
-           goto di_nextkey;
-         /* this is get_data() modified to store vert_ data */
-         if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-           {
-             Id off, len;
-             di->dp = data_read_id(di->dp, &off);
-             di->dp = data_read_id(di->dp, &len);
-             di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
-             di->vert_off = off;
-             di->vert_len = len;
-             di->vert_storestate = di->data->storestate;
-           }
-         else if (di->key->storage == KEY_STORAGE_INCORE)
-           {
-             di->ddp = di->dp;
-             if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
-               di->dp = data_skip_key(di->data, di->dp, di->key);
-           }
-         else
-           di->ddp = 0;
-         if (!di->ddp)
-           goto di_nextkey;
-          if (di->key->type == REPOKEY_TYPE_DELETED)
-           goto di_nextkey;
-         if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
-           goto di_enterarray;
-         if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
-           goto di_nextkey;
-         /* FALLTHROUGH */
-
-       case di_nextattr:
-          di->kv.entry++;
-         di->ddp = data_fetch(di->ddp, &di->kv, di->key);
-         if (di->kv.eof)
-           di->state = di_nextkey;
-         else
-           di->state = di_nextattr;
-         break;
-
-       case di_nextkey: di_nextkey:
-         if (!di->keyname && *++di->keyp)
-           goto di_enterkey;
-         if (di->kv.parent)
-           goto di_leavesub;
-         /* FALLTHROUGH */
-
-       case di_nextrepodata: di_nextrepodata:
-         if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
-             goto di_enterrepodata;
-         /* FALLTHROUGH */
-
-       case di_nextsolvable: di_nextsolvable:
-         if (!(di->flags & SEARCH_THISSOLVID))
-           {
-             if (di->solvid < 0)
-               di->solvid = di->repo->start;
-             else
-               di->solvid++;
-             for (; di->solvid < di->repo->end; di->solvid++)
-               {
-                 if (di->pool->solvables[di->solvid].repo == di->repo)
-                   goto di_entersolvable;
-               }
-           }
-         /* FALLTHROUGH */
-
-       case di_nextrepo: di_nextrepo:
-         if (di->repoid > 0)
-           {
-             di->repoid++;
-             di->repodataid = 1;
-             if (di->repoid < di->pool->nrepos)
-               {
-                 di->repo = di->pool->repos[di->repoid];
-                 goto di_enterrepo;
-               }
-           }
-       /* FALLTHROUGH */
-
-       case di_bye: di_bye:
-         di->state = di_bye;
-         return 0;
-
-       case di_enterarray: di_enterarray:
-         if (di->key->name == REPOSITORY_SOLVABLES)
-           goto di_nextkey;
-         di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
-         di->kv.eof = 0;
-         di->kv.entry = -1;
-         /* FALLTHROUGH */
-
-       case di_nextarrayelement: di_nextarrayelement:
-         di->kv.entry++;
-         if (di->kv.entry)
-           di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
-         if (di->kv.entry == di->kv.num)
-           {
-             if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
-               goto di_nextkey;
-             if (!(di->flags & SEARCH_ARRAYSENTINEL))
-               goto di_nextkey;
-             di->kv.str = (char *)di->ddp;
-             di->kv.eof = 2;
-             di->state = di_nextkey;
-             break;
-           }
-         if (di->kv.entry == di->kv.num - 1)
-           di->kv.eof = 1;
-         if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
-           di->ddp = data_read_id(di->ddp, &di->kv.id);
-         di->kv.str = (char *)di->ddp;
-         if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
-           goto di_entersub;
-         if ((di->flags & SEARCH_SUB) != 0)
-           di->state = di_entersub;
-         else
-           di->state = di_nextarrayelement;
-         break;
-
-       case di_entersub: di_entersub:
-         if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
-           goto di_nextarrayelement;   /* sorry, full */
-         di->parents[di->nparents].kv = di->kv;
-         di->parents[di->nparents].dp = di->dp;
-         di->parents[di->nparents].keyp = di->keyp;
-         di->dp = (unsigned char *)di->kv.str;
-         di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
-         memset(&di->kv, 0, sizeof(di->kv));
-         di->kv.parent = &di->parents[di->nparents].kv;
-         di->nparents++;
-         di->keyname = di->keynames[di->nparents - di->rootlevel];
-         goto di_enterschema;
-
-       case di_leavesub: di_leavesub:
-         if (di->nparents - 1 < di->rootlevel)
-           goto di_bye;
-         di->nparents--;
-         di->dp = di->parents[di->nparents].dp;
-         di->kv = di->parents[di->nparents].kv;
-         di->keyp = di->parents[di->nparents].keyp;
-         di->key = di->data->keys + *di->keyp;
-         di->ddp = (unsigned char *)di->kv.str;
-         di->keyname = di->keynames[di->nparents - di->rootlevel];
-         goto di_nextarrayelement;
-
-        /* special solvable attr handling follows */
-
-       case di_nextsolvablekey: di_nextsolvablekey:
-         if (di->keyname || di->key->name == RPM_RPMDBID)
-           goto di_enterrepodata;
-         di->key++;
-         /* FALLTHROUGH */
-
-       case di_entersolvablekey: di_entersolvablekey:
-         di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
-         if (!di->idp || !*di->idp)
-           goto di_nextsolvablekey;
-         if (di->kv.eof)
-           {
-             /* not an array */
-             di->kv.id = *di->idp;
-             di->kv.num = *di->idp;    /* for rpmdbid */
-             di->kv.num2 = 0;          /* for rpmdbid */
-             di->kv.entry = 0;
-             di->state = di_nextsolvablekey;
-             break;
-           }
-         di->kv.entry = -1;
-         /* FALLTHROUGH */
-
-       case di_nextsolvableattr:
-         di->state = di_nextsolvableattr;
-         di->kv.id = *di->idp++;
-         di->kv.entry++;
-         if (!*di->idp)
-           {
-             di->kv.eof = 1;
-             di->state = di_nextsolvablekey;
-           }
-         break;
-
-       }
-
-      if (di->matcher.match)
-       {
-         const char *str;
-         /* simple pre-check so that we don't need to stringify */
-         if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
-           if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
-             continue;
-         if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
-           {
-             if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
-               return 1;
-             continue;
-           }
-         if (!datamatcher_match(&di->matcher, str))
-           continue;
-       }
-      else
-       {
-         if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
-           repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
-       }
-      /* found something! */
-      return 1;
-    }
-}
-
-void
-dataiterator_entersub(Dataiterator *di)
-{
-  if (di->state == di_nextarrayelement)
-    di->state = di_entersub;
-}
-
-void
-dataiterator_setpos(Dataiterator *di)
-{
-  if (di->kv.eof == 2)
-    {
-      pool_clear_pos(di->pool);
-      return;
-    }
-  di->pool->pos.solvid = di->solvid;
-  di->pool->pos.repo = di->repo;
-  di->pool->pos.repodataid = di->data - di->repo->repodata;
-  di->pool->pos.schema = di->kv.id;
-  di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
-}
-
-void
-dataiterator_setpos_parent(Dataiterator *di)
-{
-  if (!di->kv.parent || di->kv.parent->eof == 2)
-    {
-      pool_clear_pos(di->pool);
-      return;
-    }
-  di->pool->pos.solvid = di->solvid;
-  di->pool->pos.repo = di->repo;
-  di->pool->pos.repodataid = di->data - di->repo->repodata;
-  di->pool->pos.schema = di->kv.parent->id;
-  di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
-}
-
-/* clones just the position, not the search keys/matcher */
-void
-dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
-{
-  di->state = from->state;
-  di->flags &= ~SEARCH_THISSOLVID;
-  di->flags |= (from->flags & SEARCH_THISSOLVID);
-  di->repo = from->repo;
-  di->data = from->data;
-  di->dp = from->dp;
-  di->ddp = from->ddp;
-  di->idp = from->idp;
-  di->keyp = from->keyp;
-  di->key = from->key;
-  di->kv = from->kv;
-  di->repodataid = from->repodataid;
-  di->solvid = from->solvid;
-  di->repoid = from->repoid;
-  di->rootlevel = from->rootlevel;
-  memcpy(di->parents, from->parents, sizeof(from->parents));
-  di->nparents = from->nparents;
-  if (di->nparents)
-    {
-      int i;
-      for (i = 1; i < di->nparents; i++)
-       di->parents[i].kv.parent = &di->parents[i - 1].kv;
-      di->kv.parent = &di->parents[di->nparents - 1].kv;
-    }
-  di->dupstr = 0;
-  di->dupstrn = 0;
-  if (from->dupstr && from->dupstr == from->kv.str)
-    {
-      di->dupstrn = from->dupstrn;
-      di->dupstr = solv_memdup(from->dupstr, from->dupstrn);
-    }
-}
-
-void
-dataiterator_seek(Dataiterator *di, int whence)
-{
-  if ((whence & DI_SEEK_STAY) != 0)
-    di->rootlevel = di->nparents;
-  switch (whence & ~DI_SEEK_STAY)
-    {
-    case DI_SEEK_CHILD:
-      if (di->state != di_nextarrayelement)
-       break;
-      if ((whence & DI_SEEK_STAY) != 0)
-       di->rootlevel = di->nparents + 1;       /* XXX: dangerous! */
-      di->state = di_entersub;
-      break;
-    case DI_SEEK_PARENT:
-      if (!di->nparents)
-       {
-         di->state = di_bye;
-         break;
-       }
-      di->nparents--;
-      if (di->rootlevel > di->nparents)
-       di->rootlevel = di->nparents;
-      di->dp = di->parents[di->nparents].dp;
-      di->kv = di->parents[di->nparents].kv;
-      di->keyp = di->parents[di->nparents].keyp;
-      di->key = di->data->keys + *di->keyp;
-      di->ddp = (unsigned char *)di->kv.str;
-      di->keyname = di->keynames[di->nparents - di->rootlevel];
-      di->state = di_nextarrayelement;
-      break;
-    case DI_SEEK_REWIND:
-      if (!di->nparents)
-       {
-         di->state = di_bye;
-         break;
-       }
-      di->dp = (unsigned char *)di->kv.parent->str;
-      di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
-      di->state = di_enterschema;
-      break;
-    default:
-      break;
-    }
-}
-
-void
-dataiterator_skip_attribute(Dataiterator *di)
-{
-  if (di->state == di_nextsolvableattr)
-    di->state = di_nextsolvablekey;
-  else
-    di->state = di_nextkey;
-}
-
-void
-dataiterator_skip_solvable(Dataiterator *di)
-{
-  di->nparents = 0;
-  di->kv.parent = 0;
-  di->rootlevel = 0;
-  di->keyname = di->keynames[0];
-  di->state = di_nextsolvable;
-}
-
-void
-dataiterator_skip_repo(Dataiterator *di)
-{
-  di->nparents = 0;
-  di->kv.parent = 0;
-  di->rootlevel = 0;
-  di->keyname = di->keynames[0];
-  di->state = di_nextrepo;
-}
-
-void
-dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
-{
-  di->nparents = 0;
-  di->kv.parent = 0;
-  di->rootlevel = 0;
-  di->keyname = di->keynames[0];
-  if (solvid == SOLVID_POS)
-    {
-      di->repo = di->pool->pos.repo;
-      if (!di->repo)
-       {
-         di->state = di_bye;
-         return;
-       }
-      di->repoid = 0;
-      if (!di->pool->pos.repodataid && di->pool->pos.solvid == SOLVID_META) {
-       solvid = SOLVID_META;           /* META pos hack */
-      } else {
-        di->data = di->repo->repodata + di->pool->pos.repodataid;
-        di->repodataid = 0;
-      }
-    }
-  else if (solvid > 0)
-    {
-      di->repo = di->pool->solvables[solvid].repo;
-      di->repoid = 0;
-    }
-  if (di->repoid > 0)
-    {
-      if (!di->pool->urepos)
-       {
-         di->state = di_bye;
-         return;
-       }
-      di->repoid = 1;
-      di->repo = di->pool->repos[di->repoid];
-    }
-  if (solvid != SOLVID_POS)
-    di->repodataid = 1;
-  di->solvid = solvid;
-  if (solvid)
-    di->flags |= SEARCH_THISSOLVID;
-  di->state = di_enterrepo;
-}
-
-void
-dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
-{
-  di->nparents = 0;
-  di->kv.parent = 0;
-  di->rootlevel = 0;
-  di->repo = repo;
-  di->repoid = 0;      /* 0 means stay at repo */
-  di->repodataid = 1;
-  di->solvid = 0;
-  di->flags &= ~SEARCH_THISSOLVID;
-  di->state = di_enterrepo;
-}
-
-int
-dataiterator_match(Dataiterator *di, Datamatcher *ma)
-{
-  const char *str;
-  if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
-    return 0;
-  return ma ? datamatcher_match(ma, str) : 1;
-}
-
-void
-dataiterator_strdup(Dataiterator *di)
-{
-  int l = -1;
-
-  if (!di->kv.str || di->kv.str == di->dupstr)
-    return;
-  switch (di->key->type)
-    {
-    case_CHKSUM_TYPES:
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      if (di->kv.num)  /* was it stringified into tmp space? */
-        l = strlen(di->kv.str) + 1;
-      break;
-    default:
-      break;
-    }
-  if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-    {
-      switch (di->key->type)
-       {
-       case REPOKEY_TYPE_STR:
-       case REPOKEY_TYPE_DIRSTRARRAY:
-         l = strlen(di->kv.str) + 1;
-         break;
-       case_CHKSUM_TYPES:
-         l = solv_chksum_len(di->key->type);
-         break;
-       case REPOKEY_TYPE_BINARY:
-         l = di->kv.num;
-         break;
-       }
-    }
-  if (l >= 0)
-    {
-      if (!di->dupstrn || di->dupstrn < l)
-       {
-         di->dupstrn = l + 16;
-         di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
-       }
-      if (l)
-        memcpy(di->dupstr, di->kv.str, l);
-      di->kv.str = di->dupstr;
-    }
-}
-
-/************************************************************************
- * data modify functions
- */
-
-/* extend repodata so that it includes solvables p */
-void
-repodata_extend(Repodata *data, Id p)
-{
-  if (data->start == data->end)
-    data->start = data->end = p;
-  if (p >= data->end)
-    {
-      int old = data->end - data->start;
-      int new = p - data->end + 1;
-      if (data->attrs)
-       {
-         data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
-         memset(data->attrs + old, 0, new * sizeof(Id *));
-       }
-      data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
-      memset(data->incoreoffset + old, 0, new * sizeof(Id));
-      data->end = p + 1;
-    }
-  if (p < data->start)
-    {
-      int old = data->end - data->start;
-      int new = data->start - p;
-      if (data->attrs)
-       {
-         data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
-         memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
-         memset(data->attrs, 0, new * sizeof(Id *));
-       }
-      data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
-      memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
-      memset(data->incoreoffset, 0, new * sizeof(Id));
-      data->start = p;
-    }
-}
-
-/* shrink end of repodata */
-void
-repodata_shrink(Repodata *data, int end)
-{
-  int i;
-
-  if (data->end <= end)
-    return;
-  if (data->start >= end)
-    {
-      if (data->attrs)
-       {
-         for (i = 0; i < data->end - data->start; i++)
-           solv_free(data->attrs[i]);
-          data->attrs = solv_free(data->attrs);
-       }
-      data->incoreoffset = solv_free(data->incoreoffset);
-      data->start = data->end = 0;
-      return;
-    }
-  if (data->attrs)
-    {
-      for (i = end; i < data->end; i++)
-       solv_free(data->attrs[i - data->start]);
-      data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
-    }
-  if (data->incoreoffset)
-    data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
-  data->end = end;
-}
-
-/* extend repodata so that it includes solvables from start to start + num - 1 */
-void
-repodata_extend_block(Repodata *data, Id start, Id num)
-{
-  if (!num)
-    return;
-  if (!data->incoreoffset)
-    {
-      /* this also means that data->attrs is NULL */
-      data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
-      data->start = start;
-      data->end = start + num;
-      return;
-    }
-  repodata_extend(data, start);
-  if (num > 1)
-    repodata_extend(data, start + num - 1);
-}
-
-/**********************************************************************/
-
-
-#define REPODATA_ATTRS_BLOCK 31
-#define REPODATA_ATTRDATA_BLOCK 1023
-#define REPODATA_ATTRIDDATA_BLOCK 63
-#define REPODATA_ATTRNUM64DATA_BLOCK 15
-
-
-Id
-repodata_new_handle(Repodata *data)
-{
-  if (!data->nxattrs)
-    {
-      data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
-      data->nxattrs = 2;       /* -1: SOLVID_META */
-    }
-  data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
-  data->xattrs[data->nxattrs] = 0;
-  return -(data->nxattrs++);
-}
-
-static inline Id **
-repodata_get_attrp(Repodata *data, Id handle)
-{
-  if (handle < 0)
-    {
-      if (handle == SOLVID_META && !data->xattrs)
-       {
-         data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
-          data->nxattrs = 2;
-       }
-      return data->xattrs - handle;
-    }
-  if (handle < data->start || handle >= data->end)
-    repodata_extend(data, handle);
-  if (!data->attrs)
-    data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
-  return data->attrs + (handle - data->start);
-}
-
-static void
-repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
-{
-  Id *pp;
-  Id *ap, **app;
-  int i;
-
-  app = repodata_get_attrp(data, handle);
-  ap = *app;
-  i = 0;
-  if (ap)
-    {
-      /* Determine equality based on the name only, allows us to change
-         type (when overwrite is set), and makes TYPE_CONSTANT work.  */
-      for (pp = ap; *pp; pp += 2)
-        if (data->keys[*pp].name == data->keys[keyid].name)
-          break;
-      if (*pp)
-        {
-         if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
-           {
-             pp[0] = keyid;
-              pp[1] = val;
-           }
-          return;
-        }
-      i = pp - ap;
-    }
-  ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
-  *app = ap;
-  pp = ap + i;
-  *pp++ = keyid;
-  *pp++ = val;
-  *pp = 0;
-}
-
-
-static void
-repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
-{
-  Id keyid;
-
-  keyid = repodata_key2id(data, key, 1);
-  repodata_insert_keyid(data, solvid, keyid, val, 1);
-}
-
-void
-repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
-{
-  Repokey key;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_ID;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, id);
-}
-
-void
-repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
-{
-  Repokey key;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_NUM;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  if (num >= 0x80000000)
-    {
-      data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
-      data->attrnum64data[data->attrnum64datalen] = num;
-      num = 0x80000000 | data->attrnum64datalen++;
-    }
-  repodata_set(data, solvid, &key, (Id)num);
-}
-
-void
-repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
-{
-  Repokey key;
-  Id id;
-  if (data->localpool)
-    id = stringpool_str2id(&data->spool, str, 1);
-  else
-    id = pool_str2id(data->repo->pool, str, 1);
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_ID;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, id);
-}
-
-void
-repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
-{
-  Repokey key;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_CONSTANT;
-  key.size = constant;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, 0);
-}
-
-void
-repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
-{
-  Repokey key;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_CONSTANTID;
-  key.size = id;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, 0);
-}
-
-void
-repodata_set_void(Repodata *data, Id solvid, Id keyname)
-{
-  Repokey key;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_VOID;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, 0);
-}
-
-void
-repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
-{
-  Repokey key;
-  int l;
-
-  l = strlen(str) + 1;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_STR;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
-  memcpy(data->attrdata + data->attrdatalen, str, l);
-  repodata_set(data, solvid, &key, data->attrdatalen);
-  data->attrdatalen += l;
-}
-
-void
-repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
-{
-  Repokey key;
-  unsigned char *dp;
-
-  if (len < 0)
-    return;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_BINARY;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
-  dp = data->attrdata + data->attrdatalen;
-  if (len >= (1 << 14))
-    {
-      if (len >= (1 << 28))
-        *dp++ = (len >> 28) | 128;
-      if (len >= (1 << 21))
-        *dp++ = (len >> 21) | 128;
-      *dp++ = (len >> 14) | 128;
-    }
-  if (len >= (1 << 7))
-    *dp++ = (len >> 7) | 128;
-  *dp++ = len & 127;
-  if (len)
-    memcpy(dp, buf, len);
-  repodata_set(data, solvid, &key, data->attrdatalen);
-  data->attrdatalen = dp + len - data->attrdata;
-}
-
-/* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
- * so that the caller can append entrysize new elements plus the termination zero there */
-static void
-repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
-{
-  int oldsize;
-  Id *ida, *pp, **ppp;
-
-  /* check if it is the same as last time, this speeds things up a lot */
-  if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
-    {
-      /* great! just append the new data */
-      data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-      data->attriddatalen--;   /* overwrite terminating 0  */
-      data->lastdatalen += entrysize;
-      return;
-    }
-
-  ppp = repodata_get_attrp(data, handle);
-  pp = *ppp;
-  if (pp)
-    {
-      for (; *pp; pp += 2)
-        if (data->keys[*pp].name == keyname)
-          break;
-    }
-  if (!pp || !*pp || data->keys[*pp].type != keytype)
-    {
-      /* not found. allocate new key */
-      Repokey key;
-      Id keyid;
-      key.name = keyname;
-      key.type = keytype;
-      key.size = 0;
-      key.storage = KEY_STORAGE_INCORE;
-      data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-      keyid = repodata_key2id(data, &key, 1);
-      repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
-      data->lasthandle = handle;
-      data->lastkey = keyid;
-      data->lastdatalen = data->attriddatalen + entrysize + 1;
-      return;
-    }
-  oldsize = 0;
-  for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
-    oldsize += entrysize;
-  if (ida + 1 == data->attriddata + data->attriddatalen)
-    {
-      /* this was the last entry, just append it */
-      data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-      data->attriddatalen--;   /* overwrite terminating 0  */
-    }
-  else
-    {
-      /* too bad. move to back. */
-      data->attriddata = solv_extend(data->attriddata, data->attriddatalen,  oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-      memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
-      pp[1] = data->attriddatalen;
-      data->attriddatalen += oldsize;
-    }
-  data->lasthandle = handle;
-  data->lastkey = *pp;
-  data->lastdatalen = data->attriddatalen + entrysize + 1;
-}
-
-void
-repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
-                     const unsigned char *str)
-{
-  Repokey key;
-  int l;
-
-  if (!(l = solv_chksum_len(type)))
-    return;
-  key.name = keyname;
-  key.type = type;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
-  memcpy(data->attrdata + data->attrdatalen, str, l);
-  repodata_set(data, solvid, &key, data->attrdatalen);
-  data->attrdatalen += l;
-}
-
-void
-repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
-                     const char *str)
-{
-  unsigned char buf[64];
-  int l;
-
-  if (!(l = solv_chksum_len(type)))
-    return;
-  if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
-    return;
-  repodata_set_bin_checksum(data, solvid, keyname, type, buf);
-}
-
-const char *
-repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
-{
-  int l;
-
-  if (!(l = solv_chksum_len(type)))
-    return "";
-  return pool_bin2hex(data->repo->pool, buf, l);
-}
-
-/* rpm filenames don't contain the epoch, so strip it */
-static inline const char *
-evrid2vrstr(Pool *pool, Id evrid)
-{
-  const char *p, *evr = pool_id2str(pool, evrid);
-  if (!evr)
-    return evr;
-  for (p = evr; *p >= '0' && *p <= '9'; p++)
-    ;
-  return p != evr && *p == ':' && p[1] ? p + 1 : evr;
-}
-
-static inline void
-repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
-{
-  Id id;
-  if (data->localpool)
-    id = stringpool_strn2id(&data->spool, str, l, 1);
-  else
-    id = pool_strn2id(data->repo->pool, str, l, 1);
-  repodata_set_id(data, solvid, keyname, id);
-}
-
-static inline void
-repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
-{
-  if (!str[l])
-    repodata_set_str(data, solvid, keyname, str);
-  else
-    {
-      char *s = solv_strdup(str);
-      s[l] = 0;
-      repodata_set_str(data, solvid, keyname, s);
-      free(s);
-    }
-}
-
-void
-repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
-{
-  Pool *pool = data->repo->pool;
-  Solvable *s;
-  const char *str, *fp;
-  int l = 0;
-
-  if (medianr)
-    repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
-  if (!dir)
-    {
-      if ((dir = strrchr(file, '/')) != 0)
-       {
-          l = dir - file;
-         dir = file;
-         file = dir + l + 1;
-         if (!l)
-           l++;
-       }
-    }
-  else
-    l = strlen(dir);
-  if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
-    {
-      dir += 2;
-      l -= 2;
-    }
-  if (l == 1 && dir[0] == '.')
-    l = 0;
-  s = pool->solvables + solvid;
-  if (dir && l)
-    {
-      str = pool_id2str(pool, s->arch);
-      if (!strncmp(dir, str, l) && !str[l])
-       repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
-      else
-       repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
-    }
-  fp = file;
-  str = pool_id2str(pool, s->name);
-  l = strlen(str);
-  if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
-    {
-      fp += l + 1;
-      str = evrid2vrstr(pool, s->evr);
-      l = strlen(str);
-      if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
-       {
-         fp += l + 1;
-         str = pool_id2str(pool, s->arch);
-         l = strlen(str);
-         if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
-           {
-             repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
-             return;
-           }
-       }
-    }
-  repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
-}
-
-/* XXX: medianr is currently not stored */
-void
-repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
-{
-  int l = 0;
-  const char *evr, *suf, *s;
-
-  if (!dir)
-    {
-      if ((dir = strrchr(file, '/')) != 0)
-       {
-          l = dir - file;
-         dir = file;
-         file = dir + l + 1;
-         if (!l)
-           l++;
-       }
-    }
-  else
-    l = strlen(dir);
-  if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
-    {
-      dir += 2;
-      l -= 2;
-    }
-  if (l == 1 && dir[0] == '.')
-    l = 0;
-  if (dir && l)
-    repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
-  evr = strchr(file, '-');
-  if (evr)
-    {
-      for (s = evr - 1; s > file; s--)
-       if (*s == '-')
-         {
-           evr = s;
-           break;
-         }
-    }
-  suf = strrchr(file, '.');
-  if (suf)
-    {
-      for (s = suf - 1; s > file; s--)
-       if (*s == '.')
-         {
-           suf = s;
-           break;
-         }
-      if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
-       {
-         /* We accept one more item as suffix.  */
-         for (s = suf - 1; s > file; s--)
-           if (*s == '.')
-             {
-               suf = s;
-               break;
-             }
-       }
-    }
-  if (!evr)
-    suf = 0;
-  if (suf && evr && suf < evr)
-    suf = 0;
-  repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
-  if (evr)
-    repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
-  if (suf)
-    repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
-}
-
-void
-repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
-{
-  Pool *pool = data->repo->pool;
-  Solvable *s = pool->solvables + solvid;
-  const char *p, *sevr, *sarch, *name, *evr;
-
-  p = strrchr(sourcepkg, '.');
-  if (!p || strcmp(p, ".rpm") != 0)
-    {
-      if (*sourcepkg)
-        repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
-      return;
-    }
-  p--;
-  while (p > sourcepkg && *p != '.')
-    p--;
-  if (*p != '.' || p == sourcepkg)
-    return;
-  sarch = p-- + 1;
-  while (p > sourcepkg && *p != '-')
-    p--;
-  if (*p != '-' || p == sourcepkg)
-    return;
-  p--;
-  while (p > sourcepkg && *p != '-')
-    p--;
-  if (*p != '-' || p == sourcepkg)
-    return;
-  sevr = p + 1;
-  pool = s->repo->pool;
-
-  name = pool_id2str(pool, s->name);
-  if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
-    repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
-  else
-    repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
-
-  evr = evrid2vrstr(pool, s->evr);
-  if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
-    repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
-  else
-    repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
-
-  if (!strcmp(sarch, "src.rpm"))
-    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
-  else if (!strcmp(sarch, "nosrc.rpm"))
-    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
-  else
-    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
-}
-
-void
-repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
-{
-  Repokey key;
-  int i;
-
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_IDARRAY;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, data->attriddatalen);
-  data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-  for (i = 0; i < q->count; i++)
-    data->attriddata[data->attriddatalen++] = q->elements[i];
-  data->attriddata[data->attriddatalen++] = 0;
-}
-
-void
-repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
-{
-  assert(dir);
-#if 0
-fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
-#endif
-  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
-  data->attriddata[data->attriddatalen++] = dir;
-  data->attriddata[data->attriddatalen++] = num;
-  data->attriddata[data->attriddatalen++] = num2;
-  data->attriddata[data->attriddatalen++] = 0;
-}
-
-void
-repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
-{
-  Id stroff;
-  int l;
-
-  assert(dir);
-  l = strlen(str) + 1;
-  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
-  memcpy(data->attrdata + data->attrdatalen, str, l);
-  stroff = data->attrdatalen;
-  data->attrdatalen += l;
-
-#if 0
-fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str,  data->attriddatalen);
-#endif
-  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
-  data->attriddata[data->attriddatalen++] = dir;
-  data->attriddata[data->attriddatalen++] = stroff;
-  data->attriddata[data->attriddatalen++] = 0;
-}
-
-void
-repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
-{
-#if 0
-fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
-#endif
-  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
-  data->attriddata[data->attriddatalen++] = id;
-  data->attriddata[data->attriddatalen++] = 0;
-}
-
-void
-repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
-                          const char *str)
-{
-  Id id;
-  if (data->localpool)
-    id = stringpool_str2id(&data->spool, str, 1);
-  else
-    id = pool_str2id(data->repo->pool, str, 1);
-  repodata_add_idarray(data, solvid, keyname, id);
-}
-
-void
-repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
-{
-  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
-  data->attriddata[data->attriddatalen++] = ghandle;
-  data->attriddata[data->attriddatalen++] = 0;
-}
-
-void
-repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
-{
-  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
-  data->attriddata[data->attriddatalen++] = ghandle;
-  data->attriddata[data->attriddatalen++] = 0;
-}
-
-void
-repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
-{
-  Id *pp, *ap, **app;
-  app = repodata_get_attrp(data, solvid);
-  ap = *app;
-  if (!ap)
-    return;
-  for (; *ap; ap += 2)
-    if (data->keys[*ap].name == keyname)
-      break;
-  if (!*ap)
-    return;
-  pp = ap;
-  ap += 2;
-  for (; *ap; ap += 2)
-    {
-      if (data->keys[*ap].name == keyname)
-       continue;
-      *pp++ = ap[0];
-      *pp++ = ap[1];
-    }
-  *pp = 0;
-}
-
-/* XXX: does not work correctly, needs fix in iterators! */
-void
-repodata_unset(Repodata *data, Id solvid, Id keyname)
-{
-  Repokey key;
-  key.name = keyname;
-  key.type = REPOKEY_TYPE_DELETED;
-  key.size = 0;
-  key.storage = KEY_STORAGE_INCORE;
-  repodata_set(data, solvid, &key, 0);
-}
-
-/* add all (uninternalized) attrs from src to dest */
-void
-repodata_merge_attrs(Repodata *data, Id dest, Id src)
-{
-  Id *keyp;
-  if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
-    return;
-  for (; *keyp; keyp += 2)
-    repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
-}
-
-/* add some (uninternalized) attrs from src to dest */
-void
-repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
-{
-  Id *keyp;
-  if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
-    return;
-  for (; *keyp; keyp += 2)
-    if (!keyidmap || MAPTST(keyidmap, keyp[0]))
-      repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
-}
-
-/* swap (uninternalized) attrs from src and dest */
-void
-repodata_swap_attrs(Repodata *data, Id dest, Id src)
-{
-  Id *tmpattrs;
-  if (!data->attrs || dest == src)
-    return;
-  if (dest < data->start || dest >= data->end)
-    repodata_extend(data, dest);
-  if (src < data->start || src >= data->end)
-    repodata_extend(data, src);
-  tmpattrs = data->attrs[dest - data->start];
-  data->attrs[dest - data->start] = data->attrs[src - data->start];
-  data->attrs[src - data->start] = tmpattrs;
-}
-
-
-/**********************************************************************/
-
-/* TODO: unify with repo_write and repo_solv! */
-
-#define EXTDATA_BLOCK 1023
-
-struct extdata {
-  unsigned char *buf;
-  int len;
-};
-
-static void
-data_addid(struct extdata *xd, Id sx)
-{
-  unsigned int x = (unsigned int)sx;
-  unsigned char *dp;
-
-  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
-  dp = xd->buf + xd->len;
-
-  if (x >= (1 << 14))
-    {
-      if (x >= (1 << 28))
-        *dp++ = (x >> 28) | 128;
-      if (x >= (1 << 21))
-        *dp++ = (x >> 21) | 128;
-      *dp++ = (x >> 14) | 128;
-    }
-  if (x >= (1 << 7))
-    *dp++ = (x >> 7) | 128;
-  *dp++ = x & 127;
-  xd->len = dp - xd->buf;
-}
-
-static void
-data_addid64(struct extdata *xd, unsigned long long x)
-{
-  if (x >= 0x100000000)
-    {
-      if ((x >> 35) != 0)
-       {
-         data_addid(xd, (Id)(x >> 35));
-         xd->buf[xd->len - 1] |= 128;
-       }
-      data_addid(xd, (Id)((unsigned int)x | 0x80000000));
-      xd->buf[xd->len - 5] = (x >> 28) | 128;
-    }
-  else
-    data_addid(xd, (Id)x);
-}
-
-static void
-data_addideof(struct extdata *xd, Id sx, int eof)
-{
-  unsigned int x = (unsigned int)sx;
-  unsigned char *dp;
-
-  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
-  dp = xd->buf + xd->len;
-
-  if (x >= (1 << 13))
-    {
-      if (x >= (1 << 27))
-        *dp++ = (x >> 27) | 128;
-      if (x >= (1 << 20))
-        *dp++ = (x >> 20) | 128;
-      *dp++ = (x >> 13) | 128;
-    }
-  if (x >= (1 << 6))
-    *dp++ = (x >> 6) | 128;
-  *dp++ = eof ? (x & 63) : (x & 63) | 64;
-  xd->len = dp - xd->buf;
-}
-
-static void
-data_addblob(struct extdata *xd, unsigned char *blob, int len)
-{
-  xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
-  memcpy(xd->buf + xd->len, blob, len);
-  xd->len += len;
-}
-
-/*********************************/
-
-/* this is to reduct memory usage when internalizing oversized repos */
-static void
-compact_attrdata(Repodata *data, int entry, int nentry)
-{
-  int i;
-  unsigned int attrdatastart = data->attrdatalen;
-  unsigned int attriddatastart = data->attriddatalen;
-  if (attrdatastart < 1024 * 1024 * 4 && attriddatastart < 1024 * 1024)
-    return;
-  for (i = entry; i < nentry; i++)
-    {
-      Id v, *attrs = data->attrs[i];
-      if (!attrs)
-       continue;
-      for (; *attrs; attrs += 2)
-       {
-         switch (data->keys[*attrs].type)
-           {
-           case REPOKEY_TYPE_STR:
-           case REPOKEY_TYPE_BINARY:
-           case_CHKSUM_TYPES:
-             if ((unsigned int)attrs[1] < attrdatastart)
-                attrdatastart = attrs[1];
-             break;
-           case REPOKEY_TYPE_DIRSTRARRAY:
-             for (v = attrs[1]; data->attriddata[v] ; v += 2)
-               if (data->attriddata[v + 1] < attrdatastart)
-                 attrdatastart = data->attriddata[v + 1];
-             /* FALLTHROUGH */
-           case REPOKEY_TYPE_IDARRAY:
-           case REPOKEY_TYPE_DIRNUMNUMARRAY:
-             if ((unsigned int)attrs[1] < attriddatastart)
-               attriddatastart = attrs[1];
-             break;
-           case REPOKEY_TYPE_FIXARRAY:
-           case REPOKEY_TYPE_FLEXARRAY:
-             return;
-           default:
-             break;
-           }
-       }
-    }
-#if 0
-  printf("compact_attrdata %d %d\n", entry, nentry);
-  printf("attrdatastart: %d\n", attrdatastart);
-  printf("attriddatastart: %d\n", attriddatastart);
-#endif
-  if (attrdatastart < 1024 * 1024 * 4 && attriddatastart < 1024 * 1024)
-    return;
-  for (i = entry; i < nentry; i++)
-    {
-      Id v, *attrs = data->attrs[i];
-      if (!attrs)
-       continue;
-      for (; *attrs; attrs += 2)
-       {
-         switch (data->keys[*attrs].type)
-           {
-           case REPOKEY_TYPE_STR:
-           case REPOKEY_TYPE_BINARY:
-           case_CHKSUM_TYPES:
-             attrs[1] -= attrdatastart;
-             break;
-           case REPOKEY_TYPE_DIRSTRARRAY:
-             for (v = attrs[1]; data->attriddata[v] ; v += 2)
-               data->attriddata[v + 1] -= attrdatastart;
-             /* FALLTHROUGH */
-           case REPOKEY_TYPE_IDARRAY:
-           case REPOKEY_TYPE_DIRNUMNUMARRAY:
-             attrs[1] -= attriddatastart;
-             break;
-           default:
-             break;
-           }
-       }
-    }
-  if (attrdatastart)
-    {
-      data->attrdatalen -= attrdatastart;
-      memmove(data->attrdata, data->attrdata + attrdatastart, data->attrdatalen);
-      data->attrdata = solv_extend_resize(data->attrdata, data->attrdatalen, 1, REPODATA_ATTRDATA_BLOCK);
-    }
-  if (attriddatastart)
-    {
-      data->attriddatalen -= attriddatastart;
-      memmove(data->attriddata, data->attriddata + attriddatastart, data->attriddatalen * sizeof(Id));
-      data->attriddata = solv_extend_resize(data->attriddata, data->attriddatalen, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
-    }
-}
-
-/* internalalize some key into incore/vincore data */
-
-static void
-repodata_serialize_key(Repodata *data, struct extdata *newincore,
-                      struct extdata *newvincore,
-                      Id *schema,
-                      Repokey *key, Id val)
-{
-  Id *ida;
-  struct extdata *xd;
-  unsigned int oldvincorelen = 0;
-  Id schemaid, *sp;
-
-  xd = newincore;
-  if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-    {
-      xd = newvincore;
-      oldvincorelen = xd->len;
-    }
-  switch (key->type)
-    {
-    case REPOKEY_TYPE_VOID:
-    case REPOKEY_TYPE_CONSTANT:
-    case REPOKEY_TYPE_CONSTANTID:
-    case REPOKEY_TYPE_DELETED:
-      break;
-    case REPOKEY_TYPE_STR:
-      data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
-      break;
-    case REPOKEY_TYPE_MD5:
-      data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
-      break;
-    case REPOKEY_TYPE_SHA1:
-      data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
-      break;
-    case REPOKEY_TYPE_SHA224:
-      data_addblob(xd, data->attrdata + val, SIZEOF_SHA224);
-      break;
-    case REPOKEY_TYPE_SHA256:
-      data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
-      break;
-    case REPOKEY_TYPE_SHA384:
-      data_addblob(xd, data->attrdata + val, SIZEOF_SHA384);
-      break;
-    case REPOKEY_TYPE_SHA512:
-      data_addblob(xd, data->attrdata + val, SIZEOF_SHA512);
-      break;
-    case REPOKEY_TYPE_NUM:
-      if (val & 0x80000000)
-       {
-         data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
-         break;
-       }
-      /* FALLTHROUGH */
-    case REPOKEY_TYPE_ID:
-    case REPOKEY_TYPE_DIR:
-      data_addid(xd, val);
-      break;
-    case REPOKEY_TYPE_BINARY:
-      {
-       Id len;
-       unsigned char *dp = data_read_id(data->attrdata + val, &len);
-       dp += (unsigned int)len;
-       data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
-      }
-      break;
-    case REPOKEY_TYPE_IDARRAY:
-      for (ida = data->attriddata + val; *ida; ida++)
-       data_addideof(xd, ida[0], ida[1] ? 0 : 1);
-      break;
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      for (ida = data->attriddata + val; *ida; ida += 3)
-       {
-         data_addid(xd, ida[0]);
-         data_addid(xd, ida[1]);
-         data_addideof(xd, ida[2], ida[3] ? 0 : 1);
-       }
-      break;
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      for (ida = data->attriddata + val; *ida; ida += 2)
-       {
-         data_addideof(xd, ida[0], ida[2] ? 0 : 1);
-         data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
-       }
-      break;
-    case REPOKEY_TYPE_FIXARRAY:
-      {
-       int num = 0;
-       schemaid = 0;
-       for (ida = data->attriddata + val; *ida; ida++)
-         {
-           Id *kp;
-           sp = schema;
-           kp = data->xattrs[-*ida];
-           if (!kp)
-             continue;         /* ignore empty elements */
-           num++;
-           for (; *kp; kp += 2)
-             *sp++ = *kp;
-           *sp = 0;
-           if (!schemaid)
-             schemaid = repodata_schema2id(data, schema, 1);
-           else if (schemaid != repodata_schema2id(data, schema, 0))
-             {
-               pool_debug(data->repo->pool, SOLV_ERROR, "repodata_serialize_key: fixarray substructs with different schemas\n");
-               num = 0;
-               break;
-             }
-         }
-       data_addid(xd, num);
-       if (!num)
-         break;
-       data_addid(xd, schemaid);
-       for (ida = data->attriddata + val; *ida; ida++)
-         {
-           Id *kp = data->xattrs[-*ida];
-           if (!kp)
-             continue;
-           for (; *kp; kp += 2)
-             repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
-         }
-       break;
-      }
-    case REPOKEY_TYPE_FLEXARRAY:
-      {
-       int num = 0;
-       for (ida = data->attriddata + val; *ida; ida++)
-         num++;
-       data_addid(xd, num);
-       for (ida = data->attriddata + val; *ida; ida++)
-         {
-           Id *kp = data->xattrs[-*ida];
-           if (!kp)
-             {
-               data_addid(xd, 0);      /* XXX */
-               continue;
-             }
-           sp = schema;
-           for (;*kp; kp += 2)
-             *sp++ = *kp;
-           *sp = 0;
-           schemaid = repodata_schema2id(data, schema, 1);
-           data_addid(xd, schemaid);
-           kp = data->xattrs[-*ida];
-           for (;*kp; kp += 2)
-             repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
-         }
-       break;
-      }
-    default:
-      pool_debug(data->repo->pool, SOLV_FATAL, "repodata_serialize_key: don't know how to handle type %d\n", key->type);
-      exit(1);
-    }
-  if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-    {
-      /* put offset/len in incore */
-      data_addid(newincore, data->lastverticaloffset + oldvincorelen);
-      oldvincorelen = xd->len - oldvincorelen;
-      data_addid(newincore, oldvincorelen);
-    }
-}
-
-/* create a circular linked list of all keys that share
- * the same keyname */
-static Id *
-calculate_keylink(Repodata *data)
-{
-  int i, j;
-  Id *link;
-  Id maxkeyname = 0, *keytable = 0;
-  link = solv_calloc(data->nkeys, sizeof(Id));
-  if (data->nkeys <= 2)
-    return link;
-  for (i = 1; i < data->nkeys; i++)
-    {
-      Id n = data->keys[i].name;
-      if (n >= maxkeyname)
-       {
-         keytable = solv_realloc2(keytable, n + 128, sizeof(Id));
-         memset(keytable + maxkeyname, 0, (n + 128 - maxkeyname) * sizeof(Id));
-         maxkeyname = n + 128;
-       }
-      j = keytable[n];
-      if (j)
-       link[i] = link[j];
-      else
-       j = i;
-      link[j] = i;
-      keytable[n] = i;
-    }
-  /* remove links that just point to themselfs */
-  for (i = 1; i < data->nkeys; i++)
-    if (link[i] == i)
-      link[i] = 0;
-  solv_free(keytable);
-  return link;
-}
-
-void
-repodata_internalize(Repodata *data)
-{
-  Repokey *key, solvkey;
-  Id entry, nentry;
-  Id schemaid, keyid, *schema, *sp, oldschemaid, *keyp, *seen;
-  Offset *oldincoreoffs = 0;
-  int schemaidx;
-  unsigned char *dp, *ndp;
-  int neednewschema;
-  struct extdata newincore;
-  struct extdata newvincore;
-  Id solvkeyid;
-  Id *keylink;
-  int haveoldkl;
-
-  if (!data->attrs && !data->xattrs)
-    return;
-
-#if 0
-  printf("repodata_internalize %d\n", data->repodataid);
-  printf("  attr data: %d K\n", data->attrdatalen / 1024);
-  printf("  attrid data: %d K\n", data->attriddatalen / (1024 / 4));
-#endif
-  newvincore.buf = data->vincore;
-  newvincore.len = data->vincorelen;
-
-  /* find the solvables key, create if needed */
-  memset(&solvkey, 0, sizeof(solvkey));
-  solvkey.name = REPOSITORY_SOLVABLES;
-  solvkey.type = REPOKEY_TYPE_FLEXARRAY;
-  solvkey.size = 0;
-  solvkey.storage = KEY_STORAGE_INCORE;
-  solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
-
-  schema = solv_malloc2(data->nkeys, sizeof(Id));
-  seen = solv_malloc2(data->nkeys, sizeof(Id));
-
-  /* Merge the data already existing (in data->schemata, ->incoredata and
-     friends) with the new attributes in data->attrs[].  */
-  nentry = data->end - data->start;
-  memset(&newincore, 0, sizeof(newincore));
-  data_addid(&newincore, 0);   /* start data at offset 1 */
-
-  data->mainschema = 0;
-  data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
-
-  keylink = calculate_keylink(data);
-  /* join entry data */
-  /* we start with the meta data, entry -1 */
-  for (entry = -1; entry < nentry; entry++)
-    {
-      oldschemaid = 0;
-      dp = data->incoredata;
-      if (dp)
-       {
-         dp += entry >= 0 ? data->incoreoffset[entry] : 1;
-          dp = data_read_id(dp, &oldschemaid);
-       }
-      memset(seen, 0, data->nkeys * sizeof(Id));
-#if 0
-fprintf(stderr, "oldschemaid %d\n", oldschemaid);
-fprintf(stderr, "schemata %d\n", data->schemata[oldschemaid]);
-fprintf(stderr, "schemadata %p\n", data->schemadata);
-#endif
-
-      /* seen: -1: old data,  0: skipped,  >0: id + 1 */
-      neednewschema = 0;
-      sp = schema;
-      haveoldkl = 0;
-      for (keyp = data->schemadata + data->schemata[oldschemaid]; *keyp; keyp++)
-       {
-         if (seen[*keyp])
-           {
-             /* oops, should not happen */
-             neednewschema = 1;
-             continue;
-           }
-         seen[*keyp] = -1;     /* use old marker */
-         *sp++ = *keyp;
-         if (keylink[*keyp])
-           haveoldkl = 1;      /* potential keylink conflict */
-       }
-
-      /* strip solvables key */
-      if (entry < 0 && solvkeyid && seen[solvkeyid])
-       {
-         *sp = 0;
-         for (sp = keyp = schema; *sp; sp++)
-           if (*sp != solvkeyid)
-             *keyp++ = *sp;
-         sp = keyp;
-         seen[solvkeyid] = 0;
-         neednewschema = 1;
-       }
-
-      /* add new entries */
-      if (entry >= 0)
-       keyp = data->attrs ? data->attrs[entry] : 0;
-      else
-        keyp = data->xattrs ? data->xattrs[1] : 0;
-      if (keyp)
-        for (; *keyp; keyp += 2)
-         {
-           if (!seen[*keyp])
-             {
-               neednewschema = 1;
-               *sp++ = *keyp;
-               if (haveoldkl && keylink[*keyp])                /* this should be pretty rare */
-                 {
-                   Id kl;
-                   for (kl = keylink[*keyp]; kl != *keyp; kl = keylink[kl])
-                     if (seen[kl] == -1)
-                       {
-                         /* replacing old key kl, remove from schema and seen */
-                         Id *osp;
-                         for (osp = schema; osp < sp; osp++)
-                           if (*osp == kl)
-                             {
-                               memmove(osp, osp + 1, (sp - osp) * sizeof(Id));
-                               sp--;
-                               seen[kl] = 0;
-                               break;
-                             }
-                       }
-                 }
-             }
-           seen[*keyp] = keyp[1] + 1;
-         }
-
-      /* add solvables key if needed */
-      if (entry < 0 && data->end != data->start)
-       {
-         *sp++ = solvkeyid;    /* always last in schema */
-         neednewschema = 1;
-       }
-
-      /* commit schema */
-      *sp = 0;
-      if (neednewschema)
-        /* Ideally we'd like to sort the new schema here, to ensure
-          schema equality independend of the ordering. */
-       schemaid = repodata_schema2id(data, schema, 1);
-      else
-       schemaid = oldschemaid;
-
-      if (entry < 0)
-       {
-         data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
-         data->mainschema = schemaid;
-       }
-
-      /* find offsets in old incore data */
-      if (oldschemaid)
-       {
-         Id *lastneeded = 0;
-         for (sp = data->schemadata + data->schemata[oldschemaid]; *sp; sp++)
-           if (seen[*sp] == -1)
-             lastneeded = sp + 1;
-         if (lastneeded)
-           {
-             if (!oldincoreoffs)
-               oldincoreoffs = solv_malloc2(data->nkeys, 2 * sizeof(Offset));
-             for (sp = data->schemadata + data->schemata[oldschemaid]; sp != lastneeded; sp++)
-               {
-                 /* Skip the data associated with this old key.  */
-                 key = data->keys + *sp;
-                 ndp = dp;
-                 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
-                   {
-                     ndp = data_skip(ndp, REPOKEY_TYPE_ID);
-                     ndp = data_skip(ndp, REPOKEY_TYPE_ID);
-                   }
-                 else if (key->storage == KEY_STORAGE_INCORE)
-                   ndp = data_skip_key(data, ndp, key);
-                 oldincoreoffs[*sp * 2] = dp - data->incoredata;
-                 oldincoreoffs[*sp * 2 + 1] = ndp - dp;
-                 dp = ndp;
-               }
-           }
-       }
-
-      /* just copy over the complete old entry (including the schemaid) if there was no new data */
-      if (entry >= 0 && !neednewschema && oldschemaid && (!data->attrs || !data->attrs[entry]) && dp)
-       {
-         ndp = data->incoredata + data->incoreoffset[entry];
-         data->incoreoffset[entry] = newincore.len;
-         data_addblob(&newincore, ndp, dp - ndp);
-         goto entrydone;
-       }
-
-      /* Now create data blob.  We walk through the (possibly new) schema
-        and either copy over old data, or insert the new.  */
-      if (entry >= 0)
-        data->incoreoffset[entry] = newincore.len;
-      data_addid(&newincore, schemaid);
-
-      /* we don't use a pointer to the schemadata here as repodata_serialize_key
-       * may call repodata_schema2id() which might realloc our schemadata */
-      for (schemaidx = data->schemata[schemaid]; (keyid = data->schemadata[schemaidx]) != 0; schemaidx++)
-       {
-         if (entry < 0)
-           {
-             data->mainschemaoffsets[schemaidx - data->schemata[schemaid]] = newincore.len;
-             if (keyid == solvkeyid)
-               {
-                 /* add flexarray entry count */
-                 data_addid(&newincore, data->end - data->start);
-                 break;        /* always the last entry */
-               }
-           }
-         if (seen[keyid] == -1)
-           {
-             if (oldincoreoffs[keyid * 2 + 1])
-               data_addblob(&newincore, data->incoredata + oldincoreoffs[keyid * 2], oldincoreoffs[keyid * 2 + 1]);
-           }
-         else if (seen[keyid])
-           repodata_serialize_key(data, &newincore, &newvincore, schema, data->keys + keyid, seen[keyid] - 1);
-       }
-
-entrydone:
-      /* free memory */
-      if (entry >= 0 && data->attrs)
-       {
-         if (data->attrs[entry])
-           data->attrs[entry] = solv_free(data->attrs[entry]);
-         if (entry && entry % 4096 == 0 && data->nxattrs <= 2 && entry + 64 < nentry)
-           {
-             compact_attrdata(data, entry + 1, nentry);        /* try to free some memory */
-#if 0
-             printf("  attr data: %d K\n", data->attrdatalen / 1024);
-             printf("  attrid data: %d K\n", data->attriddatalen / (1024 / 4));
-             printf("  incore data: %d K\n", newincore.len / 1024);
-             printf("  sum: %d K\n", (newincore.len + data->attrdatalen + data->attriddatalen * 4) / 1024);
-             /* malloc_stats(); */
-#endif
-           }
-       }
-    }
-  /* free all xattrs */
-  for (entry = 0; entry < data->nxattrs; entry++)
-    if (data->xattrs[entry])
-      solv_free(data->xattrs[entry]);
-  data->xattrs = solv_free(data->xattrs);
-  data->nxattrs = 0;
-
-  data->lasthandle = 0;
-  data->lastkey = 0;
-  data->lastdatalen = 0;
-  solv_free(schema);
-  solv_free(seen);
-  solv_free(keylink);
-  solv_free(oldincoreoffs);
-  repodata_free_schemahash(data);
-
-  solv_free(data->incoredata);
-  data->incoredata = newincore.buf;
-  data->incoredatalen = newincore.len;
-  data->incoredatafree = 0;
-
-  solv_free(data->vincore);
-  data->vincore = newvincore.buf;
-  data->vincorelen = newvincore.len;
-
-  data->attrs = solv_free(data->attrs);
-  data->attrdata = solv_free(data->attrdata);
-  data->attriddata = solv_free(data->attriddata);
-  data->attrnum64data = solv_free(data->attrnum64data);
-  data->attrdatalen = 0;
-  data->attriddatalen = 0;
-  data->attrnum64datalen = 0;
-#if 0
-  printf("repodata_internalize %d done\n", data->repodataid);
-  printf("  incore data: %d K\n", data->incoredatalen / 1024);
-#endif
-}
-
-void
-repodata_disable_paging(Repodata *data)
-{
-  if (maybe_load_repodata(data, 0))
-    {
-      repopagestore_disable_paging(&data->store);
-      data->storestate++;
-    }
-}
-
-static void
-repodata_load_stub(Repodata *data)
-{
-  Repo *repo = data->repo;
-  Pool *pool = repo->pool;
-  int r, i;
-  struct _Pool_tmpspace oldtmpspace;
-  Datapos oldpos;
-
-  if (!pool->loadcallback)
-    {
-      data->state = REPODATA_ERROR;
-      return;
-    }
-  data->state = REPODATA_LOADING;
-
-  /* save tmp space and pos */
-  oldtmpspace = pool->tmpspace;
-  memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
-  oldpos = pool->pos;
-
-  r = pool->loadcallback(pool, data, pool->loadcallbackdata);
-
-  /* restore tmp space and pos */
-  for (i = 0; i < POOL_TMPSPACEBUF; i++)
-    solv_free(pool->tmpspace.buf[i]);
-  pool->tmpspace = oldtmpspace;
-  if (r && oldpos.repo == repo && oldpos.repodataid == data->repodataid)
-    memset(&oldpos, 0, sizeof(oldpos));
-  pool->pos = oldpos;
-
-  data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
-}
-
-static inline void
-repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
-{
-  Repokey xkey;
-
-  xkey.name = keyname;
-  xkey.type = keytype;
-  xkey.storage = KEY_STORAGE_INCORE;
-  xkey.size = 0;
-  repodata_key2id(data, &xkey, 1);
-}
-
-static Repodata *
-repodata_add_stub(Repodata **datap)
-{
-  Repodata *data = *datap;
-  Repo *repo = data->repo;
-  Id repodataid = data - repo->repodata;
-  Repodata *sdata = repo_add_repodata(repo, 0);
-  data = repo->repodata + repodataid;
-  if (data->end > data->start)
-    repodata_extend_block(sdata, data->start, data->end - data->start);
-  sdata->state = REPODATA_STUB;
-  sdata->loadcallback = repodata_load_stub;
-  *datap = data;
-  return sdata;
-}
-
-Repodata *
-repodata_create_stubs(Repodata *data)
-{
-  Repo *repo = data->repo;
-  Pool *pool = repo->pool;
-  Repodata *sdata;
-  int *stubdataids;
-  Dataiterator di;
-  Id xkeyname = 0;
-  int i, cnt = 0;
-
-  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
-  while (dataiterator_step(&di))
-    if (di.data == data)
-      cnt++;
-  dataiterator_free(&di);
-  if (!cnt)
-    return data;
-  stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
-  for (i = 0; i < cnt; i++)
-    {
-      sdata = repodata_add_stub(&data);
-      stubdataids[i] = sdata - repo->repodata;
-    }
-  i = 0;
-  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
-  sdata = 0;
-  while (dataiterator_step(&di))
-    {
-      if (di.data != data)
-       continue;
-      if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
-       {
-         dataiterator_entersub(&di);
-         sdata = repo->repodata + stubdataids[i++];
-         xkeyname = 0;
-         continue;
-       }
-      switch (di.key->type)
-       {
-        case REPOKEY_TYPE_ID:
-         repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
-         break;
-       case REPOKEY_TYPE_CONSTANTID:
-         repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
-         break;
-       case REPOKEY_TYPE_STR:
-         repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
-         break;
-       case REPOKEY_TYPE_VOID:
-         repodata_set_void(sdata, SOLVID_META, di.key->name);
-         break;
-       case REPOKEY_TYPE_NUM:
-         repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
-         break;
-       case_CHKSUM_TYPES:
-         repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
-         break;
-       case REPOKEY_TYPE_IDARRAY:
-         repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
-         if (di.key->name == REPOSITORY_KEYS)
-           {
-             if (!xkeyname)
-               {
-                 if (!di.kv.eof)
-                   xkeyname = di.kv.id;
-               }
-             else
-               {
-                 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
-                 xkeyname = 0;
-               }
-           }
-         break;
-       default:
-         break;
-       }
-    }
-  dataiterator_free(&di);
-  for (i = 0; i < cnt; i++)
-    repodata_internalize(repo->repodata + stubdataids[i]);
-  solv_free(stubdataids);
-  return data;
-}
-
-unsigned int
-repodata_memused(Repodata *data)
-{
-  return data->incoredatalen + data->vincorelen;
-}
-
diff --git a/libsolv-0.6.15/src/repodata.h b/libsolv-0.6.15/src/repodata.h
deleted file mode 100644 (file)
index c18c688..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repodata.h
- *
- */
-
-#ifndef LIBSOLV_REPODATA_H
-#define LIBSOLV_REPODATA_H
-
-#include <stdio.h>
-
-#include "pooltypes.h"
-#include "pool.h"
-#include "dirpool.h"
-
-#ifdef LIBSOLV_INTERNAL
-#include "repopage.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SIZEOF_MD5     16
-#define SIZEOF_SHA1    20
-#define SIZEOF_SHA224  28
-#define SIZEOF_SHA256  32
-#define SIZEOF_SHA384  48
-#define SIZEOF_SHA512  64
-
-struct _Repo;
-struct _KeyValue;
-
-typedef struct _Repokey {
-  Id name;
-  Id type;                     /* REPOKEY_TYPE_xxx */
-  unsigned int size;
-  unsigned int storage;                /* KEY_STORAGE_xxx */
-} Repokey;
-
-#define KEY_STORAGE_DROPPED             0
-#define KEY_STORAGE_SOLVABLE            1
-#define KEY_STORAGE_INCORE              2
-#define KEY_STORAGE_VERTICAL_OFFSET     3
-
-#ifdef LIBSOLV_INTERNAL
-struct dircache;
-#endif
-
-typedef struct _Repodata {
-  Id repodataid;               /* our id */
-  struct _Repo *repo;          /* back pointer to repo */
-
-#define REPODATA_AVAILABLE     0
-#define REPODATA_STUB          1
-#define REPODATA_ERROR         2
-#define REPODATA_STORE         3
-#define REPODATA_LOADING       4
-
-  int state;                   /* available, stub or error */
-
-  void (*loadcallback)(struct _Repodata *);
-
-  int start;                   /* start of solvables this repodata is valid for */
-  int end;                     /* last solvable + 1 of this repodata */
-
-  Repokey *keys;               /* keys, first entry is always zero */
-  int nkeys;                   /* length of keys array */
-  unsigned char keybits[32];   /* keyname hash */
-
-  Id *schemata;                        /* schema -> offset into schemadata */
-  int nschemata;               /* number of schemata */
-  Id *schemadata;              /* schema storage */
-
-  Stringpool spool;            /* local string pool */
-  int localpool;               /* is local string pool used */
-
-  Dirpool dirpool;             /* local dir pool */
-
-#ifdef LIBSOLV_INTERNAL
-  FILE *fp;                    /* file pointer of solv file */
-  int error;                   /* corrupt solv file */
-
-  unsigned int schemadatalen;   /* schema storage size */
-  Id *schematahash;            /* unification helper */
-
-  unsigned char *incoredata;   /* in-core data */
-  unsigned int incoredatalen;  /* in-core data used */
-  unsigned int incoredatafree; /* free data len */
-
-  Id mainschema;               /* SOLVID_META schema */
-  Id *mainschemaoffsets;       /* SOLVID_META offsets into incoredata */
-
-  Id *incoreoffset;            /* offset for all entries */
-
-  Id *verticaloffset;          /* offset for all verticals, nkeys elements */
-  Id lastverticaloffset;       /* end of verticals */
-
-  Repopagestore store;         /* our page store */
-  Id storestate;               /* incremented every time the store might change */
-
-  unsigned char *vincore;      /* internal vertical data */
-  unsigned int vincorelen;     /* data size */
-
-  Id **attrs;                  /* un-internalized attributes */
-  Id **xattrs;                 /* anonymous handles */
-  int nxattrs;                 /* number of handles */
-
-  unsigned char *attrdata;     /* their string data space */
-  unsigned int attrdatalen;    /* its len */
-  Id *attriddata;              /* their id space */
-  unsigned int attriddatalen;  /* its len */
-  unsigned long long *attrnum64data;   /* their 64bit num data space */
-  unsigned int attrnum64datalen;       /* its len */
-
-  /* array cache to speed up repodata_add functions*/
-  Id lasthandle;
-  Id lastkey;
-  Id lastdatalen;
-
-  /* directory cache to speed up repodata_str2dir */
-  struct dircache *dircache;
-#endif
-
-} Repodata;
-
-#define SOLVID_META            -1
-#define SOLVID_POS             -2
-#define SOLVID_SUBSCHEMA       -3              /* internal! */
-
-
-/*-----
- * management functions
- */
-void repodata_initdata(Repodata *data, struct _Repo *repo, int localpool);
-void repodata_freedata(Repodata *data);
-
-void repodata_free(Repodata *data);
-void repodata_empty(Repodata *data, int localpool);
-
-
-/*
- * key management functions
- */
-Id repodata_key2id(Repodata *data, Repokey *key, int create);
-
-static inline Repokey *
-repodata_id2key(Repodata *data, Id keyid)
-{
-  return data->keys + keyid;
-}
-
-/*
- * schema management functions
- */
-Id repodata_schema2id(Repodata *data, Id *schema, int create);
-void repodata_free_schemahash(Repodata *data);
-
-static inline Id *
-repodata_id2schema(Repodata *data, Id schemaid)
-{
-  return data->schemadata + data->schemata[schemaid];
-}
-
-/*
- * data search and access
- */
-
-/* check if there is a chance that the repodata contains data for
- * the specified keyname */
-static inline int
-repodata_precheck_keyname(Repodata *data, Id keyname)
-{
-  unsigned char x = data->keybits[(keyname >> 3) & (sizeof(data->keybits) - 1)];
-  return x && (x & (1 << (keyname & 7))) ? 1 : 0;
-}
-
-/* check if the repodata contains data for the specified keyname */
-static inline int
-repodata_has_keyname(Repodata *data, Id keyname)
-{
-  int i;
-  if (!repodata_precheck_keyname(data, keyname))
-    return 0;
-  for (i = 1; i < data->nkeys; i++)
-    if (data->keys[i].name == keyname)
-      return 1;
-  return 0;
-}
-
-/* search key <keyname> (all keys, if keyname == 0) for Id <solvid>
- * Call <callback> for each match */
-void repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct _KeyValue *kv), void *cbdata);
-
-/* Make sure the found KeyValue has the "str" field set. Return "str"
- * if valid, NULL if not possible */
-const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct _KeyValue *kv, int flags);
-
-int repodata_filelistfilter_matches(Repodata *data, const char *str);
-
-
-/* lookup functions */
-Id repodata_lookup_type(Repodata *data, Id solvid, Id keyname);
-Id repodata_lookup_id(Repodata *data, Id solvid, Id keyname);
-const char *repodata_lookup_str(Repodata *data, Id solvid, Id keyname);
-int repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value);
-int repodata_lookup_void(Repodata *data, Id solvid, Id keyname);
-const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep);
-int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
-const void *repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp);
-
-
-/*-----
- * data assignment functions
- */
-
-/*
- * extend the data so that it contains the specified solvables
- * (no longer needed, as the repodata_set functions autoextend)
- */
-void repodata_extend(Repodata *data, Id p);
-void repodata_extend_block(Repodata *data, Id p, int num);
-void repodata_shrink(Repodata *data, int end);
-
-/* internalize freshly set data, so that it is found by the search
- * functions and written out */
-void repodata_internalize(Repodata *data);
-
-/* create an anonymous handle. useful for substructures like
- * fixarray/flexarray  */
-Id repodata_new_handle(Repodata *data);
-
-/* basic types: void, num, string, Id */
-void repodata_set_void(Repodata *data, Id solvid, Id keyname);
-void repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num);
-void repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id);
-void repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str);
-void repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len);
-/* create id from string, then set_id */
-void repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str);
-
-/* set numeric constant */
-void repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant);
-
-/* set Id constant */
-void repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id);
-
-/* checksum */
-void repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
-                              const unsigned char *buf);
-void repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
-                          const char *str);
-void repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
-
-
-/* directory (for package file list) */
-void repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2);
-void repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str);
-void repodata_free_dircache(Repodata *data);
-
-
-/* Arrays */
-void repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id);
-void repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname, const char *str);
-void repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle);
-void repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle);
-
-void repodata_unset(Repodata *data, Id solvid, Id keyname);
-void repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname);
-
-/*
- merge/swap attributes from one solvable to another
- works only if the data is not yet internalized
-*/
-void repodata_merge_attrs(Repodata *data, Id dest, Id src);
-void repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite);
-void repodata_swap_attrs(Repodata *data, Id dest, Id src);
-
-Repodata *repodata_create_stubs(Repodata *data);
-
-/*
- * load all paged data, used to speed up copying in repo_rpmdb
- */
-void repodata_disable_paging(Repodata *data);
-
-/* helper functions */
-Id repodata_globalize_id(Repodata *data, Id id, int create);
-Id repodata_localize_id(Repodata *data, Id id, int create);
-Id repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create);
-
-Id repodata_str2dir(Repodata *data, const char *dir, int create);
-const char *repodata_dir2str(Repodata *data, Id did, const char *suf);
-const char *repodata_chk2str(Repodata *data, Id type, const unsigned char *buf);
-void repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file);
-void repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file);
-void repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg);
-Id repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid);
-const char *repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp);
-
-/* stats */
-unsigned int repodata_memused(Repodata *data);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_REPODATA_H */
diff --git a/libsolv-0.6.15/src/repopack.h b/libsolv-0.6.15/src/repopack.h
deleted file mode 100644 (file)
index 3079239..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/* pack/unpack functions for key data */
-
-#ifndef LIBSOLV_REPOPACK_H
-#define LIBSOLV_REPOPACK_H
-
-static inline unsigned char *
-data_read_id(unsigned char *dp, Id *idp)
-{
-  Id x;
-  unsigned char c;
-  if (!(dp[0] & 0x80))
-    {
-      *idp = dp[0];
-      return dp + 1;
-    }
-  if (!(dp[1] & 0x80))
-    {
-      *idp = dp[0] << 7 ^ dp[1] ^ 0x4000;
-      return dp + 2;
-    }
-  if (!(dp[2] & 0x80))
-    {
-      *idp = dp[0] << 14 ^ dp[1] << 7 ^ dp[2] ^ 0x204000;
-      return dp + 3;
-    }
-  if (!(dp[3] & 0x80))
-    {
-      *idp = dp[0] << 21 ^ dp[1] << 14 ^ dp[2] << 7 ^ dp[3] ^ 0x10204000;
-      return dp + 4;
-    }
-  x = dp[0] << 28 ^ dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204000;
-  if (!(dp[4] & 0x80))
-    {
-      *idp = x;
-      return dp + 5;
-    }
-  x ^= 80;
-  dp += 5;
-  for (;;)
-    {
-      c = *dp++;
-      if (!(c & 0x80))
-        {
-          *idp = (x << 7) ^ c;
-          return dp;
-        }
-      x = (x << 7) ^ (c ^ 128);
-    }
-}
-
-static inline unsigned char *
-data_read_num64(unsigned char *dp, unsigned int *low, unsigned int *high)
-{
-  unsigned long long int x;
-  unsigned char c;
-
-  *high = 0;
-  if (!(dp[0] & 0x80))
-    {
-      *low = dp[0];
-      return dp + 1;
-    }
-  if (!(dp[1] & 0x80))
-    {
-      *low = dp[0] << 7 ^ dp[1] ^ 0x4000;
-      return dp + 2;
-    }
-  if (!(dp[2] & 0x80))
-    {
-      *low = dp[0] << 14 ^ dp[1] << 7 ^ dp[2] ^ 0x204000;
-      return dp + 3;
-    }
-  if (!(dp[3] & 0x80))
-    {
-      *low = dp[0] << 21 ^ dp[1] << 14 ^ dp[2] << 7 ^ dp[3] ^ 0x10204000;
-      return dp + 4;
-    }
-  if (!(dp[4] & 0x80))
-    {
-      *low = dp[0] << 28 ^ dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204000;
-      *high = (dp[0] ^ 0x80) >> 4;
-      return dp + 5;
-    }
-  x = (unsigned long long)(dp[0] ^ 0x80) << 28 ^ (unsigned int)(dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204080);
-  dp += 5;
-  for (;;)
-    {
-      c = *dp++;
-      if (!(c & 0x80))
-       {
-         x = (x << 7) ^ c;
-         *low = x;
-         *high = x >> 32;
-         return dp;
-       }
-      x = (x << 7) ^ (c ^ 128);
-    }
-}
-
-static inline unsigned char *
-data_read_ideof(unsigned char *dp, Id *idp, int *eof)
-{
-  Id x = 0;
-  unsigned char c;
-  for (;;)
-    {
-      c = *dp++;
-      if (!(c & 0x80))
-        {
-          if (c & 0x40)
-            {
-              c ^= 0x40;
-              *eof = 0;
-            }
-          else
-            *eof = 1;
-          *idp = (x << 6) ^ c;
-          return dp;
-        }
-      x = (x << 7) ^ c ^ 128;
-    }
-}
-
-static inline unsigned char *
-data_read_u32(unsigned char *dp, unsigned int *nump)
-{
-  *nump = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3];
-  return dp + 4;
-}
-
-static inline unsigned char *
-data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
-{
-  kv->eof = 1;
-  if (!dp)
-    return 0;
-  switch (key->type)
-    {
-    case REPOKEY_TYPE_VOID:
-      return dp;
-    case REPOKEY_TYPE_CONSTANT:
-      kv->num2 = 0;
-      kv->num = key->size;
-      return dp;
-    case REPOKEY_TYPE_CONSTANTID:
-      kv->id = key->size;
-      return dp;
-    case REPOKEY_TYPE_STR:
-      kv->str = (const char *)dp;
-      return dp + strlen(kv->str) + 1;
-    case REPOKEY_TYPE_ID:
-    case REPOKEY_TYPE_DIR:
-      return data_read_id(dp, &kv->id);
-    case REPOKEY_TYPE_NUM:
-      return data_read_num64(dp, &kv->num, &kv->num2);
-    case REPOKEY_TYPE_U32:
-      kv->num2 = 0;
-      return data_read_u32(dp, &kv->num);
-    case REPOKEY_TYPE_MD5:
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + SIZEOF_MD5;
-    case REPOKEY_TYPE_SHA1:
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + SIZEOF_SHA1;
-    case REPOKEY_TYPE_SHA224:
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + SIZEOF_SHA224;
-    case REPOKEY_TYPE_SHA256:
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + SIZEOF_SHA256;
-    case REPOKEY_TYPE_SHA384:
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + SIZEOF_SHA384;
-    case REPOKEY_TYPE_SHA512:
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + SIZEOF_SHA512;
-    case REPOKEY_TYPE_BINARY:
-      dp = data_read_id(dp, (Id *)&kv->num);
-      kv->str = (const char *)dp;
-      return dp + kv->num;
-    case REPOKEY_TYPE_IDARRAY:
-      return data_read_ideof(dp, &kv->id, &kv->eof);
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      dp = data_read_ideof(dp, &kv->id, &kv->eof);
-      kv->num = 0;     /* not stringified yet */
-      kv->str = (const char *)dp;
-      return dp + strlen(kv->str) + 1;
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      dp = data_read_id(dp, &kv->id);
-      dp = data_read_id(dp, (Id *)&kv->num);
-      return data_read_ideof(dp, (Id *)&kv->num2, &kv->eof);
-    case REPOKEY_TYPE_FIXARRAY:
-      dp = data_read_id(dp, (Id *)&kv->num);
-      return data_read_id(dp, &kv->id);
-    case REPOKEY_TYPE_FLEXARRAY:
-      return data_read_id(dp, (Id *)&kv->num);
-    default:
-      return 0;
-    }
-}
-
-static inline unsigned char *
-data_skip(unsigned char *dp, int type)
-{
-  unsigned char x;
-  switch (type)
-    {
-    case REPOKEY_TYPE_VOID:
-    case REPOKEY_TYPE_CONSTANT:
-    case REPOKEY_TYPE_CONSTANTID:
-    case REPOKEY_TYPE_DELETED:
-      return dp;
-    case REPOKEY_TYPE_ID:
-    case REPOKEY_TYPE_NUM:
-    case REPOKEY_TYPE_DIR:
-      while ((*dp & 0x80) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_U32:
-      return dp + 4;
-    case REPOKEY_TYPE_MD5:
-      return dp + SIZEOF_MD5;
-    case REPOKEY_TYPE_SHA1:
-      return dp + SIZEOF_SHA1;
-    case REPOKEY_TYPE_SHA224:
-      return dp + SIZEOF_SHA224;
-    case REPOKEY_TYPE_SHA256:
-      return dp + SIZEOF_SHA256;
-    case REPOKEY_TYPE_SHA384:
-      return dp + SIZEOF_SHA384;
-    case REPOKEY_TYPE_SHA512:
-      return dp + SIZEOF_SHA512;
-    case REPOKEY_TYPE_IDARRAY:
-    case REPOKEY_TYPE_REL_IDARRAY:
-      while ((*dp & 0xc0) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_STR:
-      while ((*dp) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_BINARY:
-      {
-       unsigned int len;
-       dp = data_read_id(dp, (Id *)&len);
-       return dp + len;
-      }
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      for (;;)
-        {
-          while ((*dp & 0x80) != 0)
-            dp++;
-          x = *dp++;
-          while ((*dp) != 0)
-            dp++;
-          dp++;
-          if (!(x & 0x40))
-            return dp;
-        }
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      for (;;)
-        {
-          while ((*dp & 0x80) != 0)
-            dp++;
-          dp++;
-          while ((*dp & 0x80) != 0)
-            dp++;
-          dp++;
-          while ((*dp & 0x80) != 0)
-            dp++;
-          if (!(*dp & 0x40))
-            return dp + 1;
-          dp++;
-        }
-    default:
-      return 0;
-    }
-}
-
-static inline unsigned char *
-data_skip_verify(unsigned char *dp, int type, int maxid, int maxdir)
-{
-  Id id;
-  int eof;
-
-  switch (type)
-    {
-    case REPOKEY_TYPE_VOID:
-    case REPOKEY_TYPE_CONSTANT:
-    case REPOKEY_TYPE_CONSTANTID:
-    case REPOKEY_TYPE_DELETED:
-      return dp;
-    case REPOKEY_TYPE_NUM:
-      while ((*dp & 0x80) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_U32:
-      return dp + 4;
-    case REPOKEY_TYPE_MD5:
-      return dp + SIZEOF_MD5;
-    case REPOKEY_TYPE_SHA1:
-      return dp + SIZEOF_SHA1;
-    case REPOKEY_TYPE_SHA224:
-      return dp + SIZEOF_SHA224;
-    case REPOKEY_TYPE_SHA256:
-      return dp + SIZEOF_SHA256;
-    case REPOKEY_TYPE_SHA384:
-      return dp + SIZEOF_SHA384;
-    case REPOKEY_TYPE_SHA512:
-      return dp + SIZEOF_SHA512;
-    case REPOKEY_TYPE_ID:
-      dp = data_read_id(dp, &id);
-      if (id >= maxid)
-       return 0;
-      return dp;
-    case REPOKEY_TYPE_DIR:
-      dp = data_read_id(dp, &id);
-      if (id >= maxdir)
-       return 0;
-      return dp;
-    case REPOKEY_TYPE_IDARRAY:
-      for (;;)
-       {
-         dp = data_read_ideof(dp, &id, &eof);
-         if (id >= maxid)
-           return 0;
-         if (eof)
-           return dp;
-       }
-    case REPOKEY_TYPE_STR:
-      while ((*dp) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_BINARY:
-      {
-       unsigned int len;
-       dp = data_read_id(dp, (Id *)&len);
-       return dp + len;
-      }
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      for (;;)
-        {
-         dp = data_read_ideof(dp, &id, &eof);
-         if (id >= maxdir)
-           return 0;
-          while ((*dp) != 0)
-            dp++;
-          dp++;
-          if (eof)
-            return dp;
-        }
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      for (;;)
-        {
-         dp = data_read_id(dp, &id);
-         if (id >= maxdir)
-           return 0;
-          while ((*dp & 0x80) != 0)
-            dp++;
-          dp++;
-          while ((*dp & 0x80) != 0)
-            dp++;
-          if (!(*dp & 0x40))
-            return dp + 1;
-          dp++;
-        }
-    default:
-      return 0;
-    }
-}
-
-#endif /* LIBSOLV_REPOPACK */
diff --git a/libsolv-0.6.15/src/repopage.c b/libsolv-0.6.15/src/repopage.c
deleted file mode 100644 (file)
index 2b7a863..0000000
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
- * Copyright (c) 2007-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * repopage.c
- *
- * Paging and compression functions for the vertical repository data.
- * Vertical data is grouped by key, normal data is grouped by solvable.
- * This makes searching for a string in vertical data fast as there's
- * no need to skip over data if keys we're not interested in.
- *
- * The vertical data is split into pages, each page is compressed with a fast
- * compression algorithm. These pages are read in on demand, not recently used
- * pages automatically get dropped.
- */
-
-#define _XOPEN_SOURCE 500
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <time.h>
-
-#include "repo.h"
-#include "repopage.h"
-
-
-
-#define BLOCK_SIZE (65536*1)
-#if BLOCK_SIZE <= 65536
-typedef uint16_t Ref;
-#else
-typedef uint32_t Ref;
-#endif
-
-/*
-   The format is tailored for fast decompression (i.e. only byte based),
-   and skewed to ASCII content (highest bit often not set):
-
-   a 0LLLLLLL
-        - self-describing ASCII character hex L
-   b 100lllll <l+1 bytes>
-        - literal run of length l+1
-   c 101oolll <8o>
-        - back ref of length l+2, at offset -(o+1) (o < 1 << 10)
-   d 110lllll <8o>
-        - back ref of length l+2+8, at offset -(o+1) (o < 1 << 8)
-   e 1110llll <8o> <8o>
-        - back ref of length l+3, at offset -(o+1) (o < 1 << 16)
-  f1 1111llll <8l> <8o> <8o>
-        - back ref, length l+19 (l < 1<<12), offset -(o+1) (o < 1<<16)
-  f2 11110lll <8l> <8o> <8o>
-        - back ref, length l+19 (l < 1<<11), offset -(o+1) (o < 1<<16)
-   g 11111lll <8l> <8o> <8o> <8o>
-        - back ref, length l+5 (l < 1<<11), offset -(o+1) (o < 1<<24)
-
-   Generally for a literal of length L we need L+1 bytes, hence it is
-   better to encode also very short backrefs (2 chars) as backrefs if
-   their offset is small, as that only needs two bytes.  Except if we
-   already have a literal run, in that case it's better to append there,
-   instead of breaking it for a backref.  So given a potential backref
-   at offset O, length L the strategy is as follows:
-
-   L < 2 : encode as 1-literal
-   L == 2, O > 1024 : encode as 1-literal
-   L == 2, have already literals: encode as 1-literal
-   O = O - 1
-   L >= 2, L <= 9, O < 1024                            : encode as c
-   L >= 10, L <= 41, O < 256                           : encode as d
-   else we have either O >= 1024, or L >= 42:
-   L < 3 : encode as 1-literal
-   L >= 3, L <= 18, O < 65536                          : encode as e
-   L >= 19, L <= 4095+18, O < 65536                    : encode as f
-   else we have either L >= 4096+18 or O >= 65536.
-   O >= 65536: encode as 1-literal, too bad
-     (with the current block size this can't happen)
-   L >= 4096+18, so reduce to 4095+18                  : encode as f
-*/
-
-
-static unsigned int
-compress_buf(const unsigned char *in, unsigned int in_len,
-             unsigned char *out, unsigned int out_len)
-{
-  unsigned int oo = 0;         /* out-offset */
-  unsigned int io = 0;         /* in-offset */
-#define HS (65536)
-  Ref htab[HS];
-  Ref hnext[BLOCK_SIZE];
-  unsigned int litofs = 0;
-  memset(htab, -1, sizeof (htab));
-  memset(hnext, -1, sizeof (hnext));
-  while (io + 2 < in_len)
-    {
-      /* Search for a match of the string starting at IN, we have at
-         least three characters.  */
-      unsigned int hval = in[io] | in[io + 1] << 8 | in[io + 2] << 16;
-      unsigned int try, mlen, mofs, tries;
-      hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
-      hval = hval & (HS - 1);
-      try = htab[hval];
-      hnext[io] = htab[hval];
-      htab[hval] = io;
-      mlen = 0;
-      mofs = 0;
-
-      for (tries = 0; try != -1 && tries < 12; tries++)
-        {
-         if (try < io
-             && in[try] == in[io] && in[try + 1] == in[io + 1])
-           {
-             mlen = 2;
-             mofs = (io - try) - 1;
-             break;
-           }
-         try = hnext[try];
-       }
-      for (; try != -1 && tries < 12; tries++)
-       {
-         /* assert(mlen >= 2); */
-         /* assert(io + mlen < in_len); */
-         /* Try a match starting from [io] with the strings at [try].
-            That's only sensible if TRY actually is before IO (can happen
-            with uninit hash table).  If we have a previous match already
-            we're only going to take the new one if it's longer, hence
-            check the potentially last character.  */
-         if (try < io && in[try + mlen] == in[io + mlen])
-           {
-             unsigned int this_len, this_ofs;
-             if (memcmp(in + try, in + io, mlen))
-               goto no_match;
-             this_len = mlen + 1;
-             /* Now try extending the match by more characters.  */
-             for (;
-                  io + this_len < in_len
-                  && in[try + this_len] == in[io + this_len]; this_len++)
-               ;
-#if 0
-             unsigned int testi;
-             for (testi = 0; testi < this_len; testi++)
-               assert(in[try + testi] == in[io + testi]);
-#endif
-             this_ofs = (io - try) - 1;
-             /*if (this_ofs > 65535)
-                goto no_match; */
-#if 0
-             assert(this_len >= 2);
-             assert(this_len >= mlen);
-             assert(this_len > mlen || (this_len == mlen && this_ofs > mofs));
-#endif
-             mlen = this_len, mofs = this_ofs;
-             /* If our match extends up to the end of input, no next
-                match can become better.  This is not just an
-                optimization, it establishes a loop invariant
-                (io + mlen < in_len).  */
-             if (io + mlen >= in_len)
-               goto match_done;
-           }
-       no_match:
-         try = hnext[try];
-         /*if (io - try - 1 >= 65536)
-           break;*/
-       }
-
-match_done:
-      if (mlen)
-       {
-         /*fprintf(stderr, "%d %d\n", mlen, mofs);*/
-         if (mlen == 2 && (litofs || mofs >= 1024))
-           mlen = 0;
-         /*else if (mofs >= 65536)
-           mlen = 0;*/
-         else if (mofs >= 65536)
-           {
-             if (mlen >= 2048 + 5)
-               mlen = 2047 + 5;
-             else if (mlen < 5)
-               mlen = 0;
-           }
-         else if (mlen < 3)
-           mlen = 0;
-         /*else if (mlen >= 4096 + 19)
-           mlen = 4095 + 19;*/
-         else if (mlen >= 2048 + 19)
-           mlen = 2047 + 19;
-         /* Skip this match if the next character would deliver a better one,
-            but only do this if we have the chance to really extend the
-            length (i.e. our current length isn't yet the (conservative)
-            maximum).  */
-         if (mlen && mlen < (2048 + 5) && io + 3 < in_len)
-           {
-             unsigned int hval =
-               in[io + 1] | in[io + 2] << 8 | in[io + 3] << 16;
-             unsigned int try;
-             hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
-             hval = hval & (HS - 1);
-             try = htab[hval];
-             if (try < io + 1
-                 && in[try] == in[io + 1] && in[try + 1] == in[io + 2])
-               {
-                 unsigned int this_len;
-                 this_len = 2;
-                 for (;
-                      io + 1 + this_len < in_len
-                      && in[try + this_len] == in[io + 1 + this_len];
-                      this_len++)
-                   ;
-                 if (this_len >= mlen)
-                   mlen = 0;
-               }
-           }
-       }
-      if (!mlen)
-       {
-         if (!litofs)
-           litofs = io + 1;
-         io++;
-       }
-      else
-       {
-         if (litofs)
-           {
-             unsigned litlen;
-             litofs--;
-             litlen = io - litofs;
-             /* fprintf(stderr, "lit: %d\n", litlen); */
-             while (litlen)
-               {
-                 unsigned int easy_sz;
-                 /* Emit everything we can as self-describers.  As soon as
-                    we hit a byte we can't emit as such we're going to emit
-                    a length descriptor anyway, so we can as well include
-                    bytes < 0x80 which might follow afterwards in that run.  */
-                 for (easy_sz = 0;
-                      easy_sz < litlen && in[litofs + easy_sz] < 0x80;
-                      easy_sz++)
-                   ;
-                 if (easy_sz)
-                   {
-                     if (oo + easy_sz >= out_len)
-                       return 0;
-                     memcpy(out + oo, in + litofs, easy_sz);
-                     litofs += easy_sz;
-                     oo += easy_sz;
-                     litlen -= easy_sz;
-                     if (!litlen)
-                       break;
-                   }
-                 if (litlen <= 32)
-                   {
-                     if (oo + 1 + litlen >= out_len)
-                       return 0;
-                     out[oo++] = 0x80 | (litlen - 1);
-                     while (litlen--)
-                       out[oo++] = in[litofs++];
-                     break;
-                   }
-                 else
-                   {
-                     /* Literal length > 32, so chunk it.  */
-                     if (oo + 1 + 32 >= out_len)
-                       return 0;
-                     out[oo++] = 0x80 | 31;
-                     memcpy(out + oo, in + litofs, 32);
-                     oo += 32;
-                     litofs += 32;
-                     litlen -= 32;
-                   }
-               }
-             litofs = 0;
-           }
-
-         /* fprintf(stderr, "ref: %d @ %d\n", mlen, mofs); */
-
-         if (mlen >= 2 && mlen <= 9 && mofs < 1024)
-           {
-             if (oo + 2 >= out_len)
-               return 0;
-             out[oo++] = 0xa0 | ((mofs & 0x300) >> 5) | (mlen - 2);
-             out[oo++] = mofs & 0xff;
-           }
-         else if (mlen >= 10 && mlen <= 41 && mofs < 256)
-           {
-             if (oo + 2 >= out_len)
-               return 0;
-             out[oo++] = 0xc0 | (mlen - 10);
-             out[oo++] = mofs;
-           }
-         else if (mofs >= 65536)
-           {
-             assert(mlen >= 5 && mlen < 2048 + 5);
-             if (oo + 5 >= out_len)
-               return 0;
-             out[oo++] = 0xf8 | ((mlen - 5) >> 8);
-             out[oo++] = (mlen - 5) & 0xff;
-             out[oo++] = mofs & 0xff;
-             out[oo++] = (mofs >> 8) & 0xff;
-             out[oo++] = mofs >> 16;
-           }
-         else if (mlen >= 3 && mlen <= 18)
-           {
-             assert(mofs < 65536);
-             if (oo + 3 >= out_len)
-               return 0;
-             out[oo++] = 0xe0 | (mlen - 3);
-             out[oo++] = mofs & 0xff;
-             out[oo++] = mofs >> 8;
-           }
-         else
-           {
-             assert(mlen >= 19 && mlen <= 4095 + 19 && mofs < 65536);
-             if (oo + 4 >= out_len)
-               return 0;
-             out[oo++] = 0xf0 | ((mlen - 19) >> 8);
-             out[oo++] = (mlen - 19) & 0xff;
-             out[oo++] = mofs & 0xff;
-             out[oo++] = mofs >> 8;
-           }
-         /* Insert the hashes for the compressed run [io..io+mlen-1].
-            For [io] we have it already done at the start of the loop.
-            So it's from [io+1..io+mlen-1], and we need three chars per
-            hash, so the accessed characters will be [io+1..io+mlen-1+2],
-            ergo io+mlen+1 < in_len.  */
-         mlen--;
-         io++;
-         while (mlen--)
-           {
-             if (io + 2 < in_len)
-               {
-                 unsigned int hval =
-                   in[io] | in[io + 1] << 8 | in[io + 2] << 16;
-                 hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
-                 hval = hval & (HS - 1);
-                 hnext[io] = htab[hval];
-                 htab[hval] = io;
-               }
-             io++;
-           };
-       }
-    }
-  /* We might have some characters left.  */
-  if (io < in_len && !litofs)
-    litofs = io + 1;
-  io = in_len;
-  if (litofs)
-    {
-      unsigned litlen;
-      litofs--;
-      litlen = io - litofs;
-      /* fprintf(stderr, "lit: %d\n", litlen); */
-      while (litlen)
-       {
-         unsigned int easy_sz;
-         /* Emit everything we can as self-describers.  As soon as we hit a
-            byte we can't emit as such we're going to emit a length
-            descriptor anyway, so we can as well include bytes < 0x80 which
-            might follow afterwards in that run.  */
-         for (easy_sz = 0; easy_sz < litlen && in[litofs + easy_sz] < 0x80;
-              easy_sz++)
-           ;
-         if (easy_sz)
-           {
-             if (oo + easy_sz >= out_len)
-               return 0;
-             memcpy(out + oo, in + litofs, easy_sz);
-             litofs += easy_sz;
-             oo += easy_sz;
-             litlen -= easy_sz;
-             if (!litlen)
-               break;
-           }
-         if (litlen <= 32)
-           {
-             if (oo + 1 + litlen >= out_len)
-               return 0;
-             out[oo++] = 0x80 | (litlen - 1);
-             while (litlen--)
-               out[oo++] = in[litofs++];
-             break;
-           }
-         else
-           {
-             /* Literal length > 32, so chunk it.  */
-             if (oo + 1 + 32 >= out_len)
-               return 0;
-             out[oo++] = 0x80 | 31;
-             memcpy(out + oo, in + litofs, 32);
-             oo += 32;
-             litofs += 32;
-             litlen -= 32;
-           }
-       }
-      litofs = 0;
-    }
-  return oo;
-}
-
-static unsigned int
-unchecked_decompress_buf(const unsigned char *in, unsigned int in_len,
-                         unsigned char *out,
-                         unsigned int out_len __attribute__((unused)))
-{
-  unsigned char *orig_out = out;
-  const unsigned char *in_end = in + in_len;
-  while (in < in_end)
-    {
-      unsigned int first = *in++;
-      int o;
-      switch (first >> 4)
-       {
-       default:
-         /* This default case can't happen, but GCCs VRP is not strong
-            enough to see this, so make this explicitely not fall to
-            the end of the switch, so that we don't have to initialize
-            o above.  */
-         continue;
-       case 0: case 1:
-       case 2: case 3:
-       case 4: case 5:
-       case 6: case 7:
-         /* a 0LLLLLLL */
-         /* fprintf (stderr, "lit: 1\n"); */
-         *out++ = first;
-         continue;
-       case 8: case 9:
-         /* b 100lllll <l+1 bytes> */
-         {
-           unsigned int l = first & 31;
-           /* fprintf (stderr, "lit: %d\n", l); */
-           do
-             *out++ = *in++;
-           while (l--);
-           continue;
-         }
-       case 10: case 11:
-         /* c 101oolll <8o> */
-         {
-           o = first & (3 << 3);
-           o = (o << 5) | *in++;
-           first = (first & 7) + 2;
-           break;
-         }
-       case 12: case 13:
-         /* d 110lllll <8o> */
-         {
-           o = *in++;
-           first = (first & 31) + 10;
-           break;
-         }
-       case 14:
-         /* e 1110llll <8o> <8o> */
-         {
-           o = in[0] | (in[1] << 8);
-           in += 2;
-           first = first & 31;
-           first += 3;
-           break;
-         }
-       case 15:
-         /* f1 1111llll <8o> <8o> <8l> */
-         /* f2 11110lll <8o> <8o> <8l> */
-         /* g 11111lll <8o> <8o> <8o> <8l> */
-         {
-           first = first & 15;
-           if (first >= 8)
-             {
-               first = (((first - 8) << 8) | in[0]) + 5;
-               o = in[1] | (in[2] << 8) | (in[3] << 16);
-               in += 4;
-             }
-           else
-             {
-               first = ((first << 8) | in[0]) + 19;
-               o = in[1] | (in[2] << 8);
-               in += 3;
-             }
-           break;
-         }
-       }
-      /* fprintf(stderr, "ref: %d @ %d\n", first, o); */
-      o++;
-      o = -o;
-#if 0
-      /* We know that first will not be zero, and this loop structure is
-         better optimizable.  */
-      do
-       {
-         *out = *(out - o);
-         out++;
-       }
-      while (--first);
-#else
-      switch (first)
-        {
-         case 18: *out = *(out + o); out++;
-         case 17: *out = *(out + o); out++;
-         case 16: *out = *(out + o); out++;
-         case 15: *out = *(out + o); out++;
-         case 14: *out = *(out + o); out++;
-         case 13: *out = *(out + o); out++;
-         case 12: *out = *(out + o); out++;
-         case 11: *out = *(out + o); out++;
-         case 10: *out = *(out + o); out++;
-         case  9: *out = *(out + o); out++;
-         case  8: *out = *(out + o); out++;
-         case  7: *out = *(out + o); out++;
-         case  6: *out = *(out + o); out++;
-         case  5: *out = *(out + o); out++;
-         case  4: *out = *(out + o); out++;
-         case  3: *out = *(out + o); out++;
-         case  2: *out = *(out + o); out++;
-         case  1: *out = *(out + o); out++;
-         case  0: break;
-         default:
-           /* Duff duff :-) */
-           switch (first & 15)
-             {
-               do
-                 {
-                   case  0: *out = *(out + o); out++;
-                   case 15: *out = *(out + o); out++;
-                   case 14: *out = *(out + o); out++;
-                   case 13: *out = *(out + o); out++;
-                   case 12: *out = *(out + o); out++;
-                   case 11: *out = *(out + o); out++;
-                   case 10: *out = *(out + o); out++;
-                   case  9: *out = *(out + o); out++;
-                   case  8: *out = *(out + o); out++;
-                   case  7: *out = *(out + o); out++;
-                   case  6: *out = *(out + o); out++;
-                   case  5: *out = *(out + o); out++;
-                   case  4: *out = *(out + o); out++;
-                   case  3: *out = *(out + o); out++;
-                   case  2: *out = *(out + o); out++;
-                   case  1: *out = *(out + o); out++;
-                 }
-               while ((int)(first -= 16) > 0);
-             }
-           break;
-       }
-#endif
-    }
-  return out - orig_out;
-}
-
-/**********************************************************************/
-
-void repopagestore_init(Repopagestore *store)
-{
-  memset(store, 0, sizeof(*store));
-  store->pagefd = -1;
-}
-
-void repopagestore_free(Repopagestore *store)
-{
-  store->blob_store = solv_free(store->blob_store);
-  store->file_pages = solv_free(store->file_pages);
-  store->mapped_at = solv_free(store->mapped_at);
-  store->mapped = solv_free(store->mapped);
-  if (store->pagefd != -1)
-    close(store->pagefd);
-  store->pagefd = -1;
-}
-
-
-/**********************************************************************/
-
-unsigned char *
-repopagestore_load_page_range(Repopagestore *store, unsigned int pstart, unsigned int pend)
-{
-/* Make sure all pages from PSTART to PEND (inclusive) are loaded,
-   and are consecutive.  Return a pointer to the mapping of PSTART.  */
-  unsigned char buf[REPOPAGE_BLOBSIZE];
-  unsigned int i, best, pnum;
-
-  if (pstart == pend)
-    {
-      /* Quick check in case the requested page is already mapped */
-      if (store->mapped_at[pstart] != -1)
-       return store->blob_store + store->mapped_at[pstart];
-    }
-  else
-    {
-      /* Quick check in case all pages are already mapped and consecutive.  */
-      for (pnum = pstart; pnum <= pend; pnum++)
-       if (store->mapped_at[pnum] == -1
-           || (pnum > pstart
-               && store->mapped_at[pnum]
-                  != store->mapped_at[pnum-1] + REPOPAGE_BLOBSIZE))
-         break;
-      if (pnum > pend)
-       return store->blob_store + store->mapped_at[pstart];
-    }
-
-  if (store->pagefd == -1 || !store->file_pages)
-    return 0;  /* no backing file */
-
-#ifdef DEBUG_PAGING
-  fprintf(stderr, "PAGE: want %d pages starting at %d\n", pend - pstart + 1, pstart);
-#endif
-
-  /* Ensure that we can map the numbers of pages we need at all.  */
-  if (pend - pstart + 1 > store->nmapped)
-    {
-      unsigned int oldcan = store->nmapped;
-      store->nmapped = pend - pstart + 1;
-      if (store->nmapped < 4)
-        store->nmapped = 4;
-      store->mapped = solv_realloc2(store->mapped, store->nmapped, sizeof(store->mapped[0]));
-      for (i = oldcan; i < store->nmapped; i++)
-       store->mapped[i] = -1;
-      store->blob_store = solv_realloc2(store->blob_store, store->nmapped, REPOPAGE_BLOBSIZE);
-#ifdef DEBUG_PAGING
-      fprintf(stderr, "PAGE: can map %d pages\n", store->nmapped);
-#endif
-    }
-
-  if (store->mapped_at[pstart] != -1)
-    {
-      /* assume forward search */
-      best = store->mapped_at[pstart] / REPOPAGE_BLOBSIZE;
-      if (best + (pend - pstart) >= store->nmapped)
-       best = 0;
-    }
-  else if (store->mapped_at[pend] != -1)
-    {
-      /* assume backward search */
-      best = store->mapped_at[pend] / REPOPAGE_BLOBSIZE;
-      if (best < pend - pstart)
-       best = store->nmapped - 1;
-      best -= pend - pstart;
-    }
-  else
-    {
-      /* choose some "random" location to avoid thrashing */
-      best = (pstart + store->rr_counter++) % (store->nmapped - pend + pstart);
-    }
-
-  /* So we want to map our pages from [best] to [best+pend-pstart].
-     Use a very simple strategy, which doesn't make the best use of
-     our resources, but works.  Throw away all pages in that range
-     (even ours) then copy around ours or read them in.  */
-  for (i = best, pnum = pstart; pnum <= pend; i++, pnum++)
-    {
-      unsigned int pnum_mapped_at;
-      unsigned int oldpnum = store->mapped[i];
-      if (oldpnum != -1)
-       {
-         if (oldpnum == pnum)
-           continue;   /* already have the correct page */
-         /* Evict this page.  */
-#ifdef DEBUG_PAGING
-         fprintf(stderr, "PAGE: evict page %d from %d\n", oldpnum, i);
-#endif
-         store->mapped[i] = -1;
-         store->mapped_at[oldpnum] = -1;
-       }
-      /* check if we can copy the correct content (before it gets evicted) */
-      pnum_mapped_at = store->mapped_at[pnum];
-      if (pnum_mapped_at != -1 && pnum_mapped_at != i * REPOPAGE_BLOBSIZE)
-       {
-         void *dest = store->blob_store + i * REPOPAGE_BLOBSIZE;
-#ifdef DEBUG_PAGING
-         fprintf(stderr, "PAGECOPY: %d from %d to %d\n", pnum, pnum_mapped_at / REPOPAGE_BLOBSIZE, i);
-#endif
-         memcpy(dest, store->blob_store + pnum_mapped_at, REPOPAGE_BLOBSIZE);
-         store->mapped[pnum_mapped_at / REPOPAGE_BLOBSIZE] = -1;
-         store->mapped[i] = pnum;
-         store->mapped_at[pnum] = i * REPOPAGE_BLOBSIZE;
-       }
-    }
-
-  /* Everything is free now.  Read in or copy the pages we want.  */
-  for (i = best, pnum = pstart; pnum <= pend; i++, pnum++)
-    {
-      void *dest = store->blob_store + i * REPOPAGE_BLOBSIZE;
-      if (store->mapped_at[pnum] != -1)
-        {
-          unsigned int pnum_mapped_at = store->mapped_at[pnum];
-         if (pnum_mapped_at != i * REPOPAGE_BLOBSIZE)
-           {
-#ifdef DEBUG_PAGING
-             fprintf(stderr, "PAGECOPY: %d from %d to %d\n", pnum, pnum_mapped_at / REPOPAGE_BLOBSIZE, i);
-#endif
-             /* Still mapped somewhere else, so just copy it from there.  */
-             memcpy(dest, store->blob_store + pnum_mapped_at, REPOPAGE_BLOBSIZE);
-             store->mapped[pnum_mapped_at / REPOPAGE_BLOBSIZE] = -1;
-           }
-       }
-      else
-        {
-         Attrblobpage *p = store->file_pages + pnum;
-         unsigned int in_len = p->page_size;
-         unsigned int compressed = in_len & 1;
-         in_len >>= 1;
-#ifdef DEBUG_PAGING
-         fprintf(stderr, "PAGEIN: %d to %d", pnum, i);
-#endif
-          if (pread(store->pagefd, compressed ? buf : dest, in_len, store->file_offset + p->page_offset) != in_len)
-           {
-             perror("mapping pread");
-             return 0;
-           }
-         if (compressed)
-           {
-             unsigned int out_len;
-             out_len = unchecked_decompress_buf(buf, in_len, dest, REPOPAGE_BLOBSIZE);
-             if (out_len != REPOPAGE_BLOBSIZE && pnum < store->num_pages - 1)
-               {
-#ifdef DEBUG_PAGING
-                 fprintf(stderr, "can't decompress\n");
-#endif
-                 return 0;
-               }
-#ifdef DEBUG_PAGING
-             fprintf(stderr, " (expand %d to %d)", in_len, out_len);
-#endif
-           }
-#ifdef DEBUG_PAGING
-         fprintf(stderr, "\n");
-#endif
-       }
-      store->mapped_at[pnum] = i * REPOPAGE_BLOBSIZE;
-      store->mapped[i] = pnum;
-    }
-  return store->blob_store + best * REPOPAGE_BLOBSIZE;
-}
-
-unsigned int
-repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
-{
-  return compress_buf(page, len, cpage, max);
-}
-
-#define SOLV_ERROR_EOF         3
-#define SOLV_ERROR_CORRUPT     6
-
-static inline unsigned int
-read_u32(FILE *fp)
-{
-  int c, i;
-  unsigned int x = 0;
-
-  for (i = 0; i < 4; i++)
-    {
-      c = getc(fp);
-      if (c == EOF)
-        return 0;
-      x = (x << 8) | c;
-    }
-  return x;
-}
-
-/* Try to either setup on-demand paging (using FP as backing
-   file), or in case that doesn't work (FP not seekable) slurps in
-   all pages and deactivates paging.  */
-int
-repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int pagesz, unsigned int blobsz)
-{
-  unsigned int npages;
-  unsigned int i;
-  unsigned int can_seek;
-  unsigned int cur_page_ofs;
-  unsigned char buf[REPOPAGE_BLOBSIZE];
-
-  if (pagesz != REPOPAGE_BLOBSIZE)
-    {
-      /* We could handle this by slurping in everything.  */
-      return SOLV_ERROR_CORRUPT;
-    }
-  can_seek = 1;
-  if ((store->file_offset = ftell(fp)) < 0)
-    can_seek = 0;
-  clearerr(fp);
-  if (can_seek)
-    store->pagefd = dup(fileno(fp));
-  if (store->pagefd == -1)
-    can_seek = 0;
-  else
-    fcntl(store->pagefd, F_SETFD, FD_CLOEXEC);
-
-#ifdef DEBUG_PAGING
-  fprintf(stderr, "can %sseek\n", can_seek ? "" : "NOT ");
-#endif
-  npages = (blobsz + REPOPAGE_BLOBSIZE - 1) / REPOPAGE_BLOBSIZE;
-
-  store->num_pages = npages;
-  store->mapped_at = solv_malloc2(npages, sizeof(*store->mapped_at));
-
-  /* If we can't seek on our input we have to slurp in everything.
-   * Otherwise set up file_pages containing offest/length of the
-   * pages */
-  if (can_seek)
-    store->file_pages = solv_malloc2(npages, sizeof(*store->file_pages));
-  else
-    store->blob_store = solv_malloc2(npages, REPOPAGE_BLOBSIZE);
-  cur_page_ofs = 0;
-  for (i = 0; i < npages; i++)
-    {
-      unsigned int in_len = read_u32(fp);
-      unsigned int compressed = in_len & 1;
-      in_len >>= 1;
-#ifdef DEBUG_PAGING
-      fprintf(stderr, "page %d: len %d (%scompressed)\n",
-              i, in_len, compressed ? "" : "not ");
-#endif
-      if (can_seek)
-        {
-         Attrblobpage *p = store->file_pages + i;
-          cur_page_ofs += 4;
-          store->mapped_at[i] = -1;    /* not mapped yet */
-         p->page_offset = cur_page_ofs;
-         p->page_size = in_len * 2 + compressed;
-         if (fseek(fp, in_len, SEEK_CUR) < 0)
-           {
-             /* We can't fall back to non-seeking behaviour as we already
-                read over some data pages without storing them away.  */
-             close(store->pagefd);
-             store->pagefd = -1;
-             return SOLV_ERROR_EOF;
-           }
-         cur_page_ofs += in_len;
-       }
-      else
-        {
-         unsigned int out_len;
-         void *dest = store->blob_store + i * REPOPAGE_BLOBSIZE;
-          store->mapped_at[i] = i * REPOPAGE_BLOBSIZE;
-         /* We can't seek, so suck everything in.  */
-         if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
-           {
-             perror("fread");
-             return SOLV_ERROR_EOF;
-           }
-         if (compressed)
-           {
-             out_len = unchecked_decompress_buf(buf, in_len, dest, REPOPAGE_BLOBSIZE);
-             if (out_len != REPOPAGE_BLOBSIZE && i < npages - 1)
-               {
-                 return SOLV_ERROR_CORRUPT;
-               }
-           }
-       }
-    }
-  return 0;
-}
-
-void
-repopagestore_disable_paging(Repopagestore *store)
-{
-  if (store->num_pages)
-    repopagestore_load_page_range(store, 0, store->num_pages - 1);
-}
-
-#ifdef STANDALONE
-
-static void
-transfer_file(FILE * from, FILE * to, int compress)
-{
-  unsigned char inb[BLOCK_SIZE];
-  unsigned char outb[BLOCK_SIZE];
-  while (!feof (from) && !ferror (from))
-    {
-      unsigned int in_len, out_len;
-      if (compress)
-       {
-         in_len = fread(inb, 1, BLOCK_SIZE, from);
-         if (in_len)
-           {
-             unsigned char *b = outb;
-             out_len = compress_buf(inb, in_len, outb, sizeof (outb));
-             if (!out_len)
-               b = inb, out_len = in_len;
-             if (fwrite(&out_len, sizeof (out_len), 1, to) != 1)
-               {
-                 perror("write size");
-                 exit (1);
-               }
-             if (fwrite(b, out_len, 1, to) != 1)
-               {
-                 perror("write data");
-                 exit (1);
-               }
-           }
-       }
-      else
-       {
-         if (fread(&in_len, sizeof(in_len), 1, from) != 1)
-           {
-             if (feof(from))
-               return;
-             perror("can't read size");
-             exit(1);
-           }
-         if (fread(inb, in_len, 1, from) != 1)
-           {
-             perror("can't read data");
-             exit(1);
-           }
-         out_len =
-           unchecked_decompress_buf(inb, in_len, outb, sizeof(outb));
-         if (fwrite(outb, out_len, 1, to) != 1)
-           {
-             perror("can't write output");
-             exit(1);
-           }
-       }
-    }
-}
-
-/* Just for benchmarking purposes.  */
-static void
-dumb_memcpy(void *dest, const void *src, unsigned int len)
-{
-  char *d = dest;
-  const char *s = src;
-  while (len--)
-    *d++ = *s++;
-}
-
-static void
-benchmark(FILE * from)
-{
-  unsigned char inb[BLOCK_SIZE];
-  unsigned char outb[BLOCK_SIZE];
-  unsigned int in_len = fread(inb, 1, BLOCK_SIZE, from);
-  unsigned int out_len;
-  if (!in_len)
-    {
-      perror("can't read from input");
-      exit(1);
-    }
-
-  unsigned int calib_loop;
-  unsigned int per_loop;
-  unsigned int i, j;
-  clock_t start, end;
-  float seconds;
-
-#if 0
-  calib_loop = 1;
-  per_loop = 0;
-  start = clock();
-  while ((clock() - start) < CLOCKS_PER_SEC / 4)
-    {
-      calib_loop *= 2;
-      for (i = 0; i < calib_loop; i++)
-       dumb_memcpy(outb, inb, in_len);
-      per_loop += calib_loop;
-    }
-
-  fprintf(stderr, "memcpy:\nCalibrated to %d iterations per loop\n",
-          per_loop);
-
-  start = clock();
-  for (i = 0; i < 10; i++)
-    for (j = 0; j < per_loop; j++)
-      dumb_memcpy(outb, inb, in_len);
-  end = clock();
-  seconds = (end - start) / (float) CLOCKS_PER_SEC;
-  fprintf(stderr, "%.2f seconds == %.2f MB/s\n", seconds,
-          ((long long) in_len * per_loop * 10) / (1024 * 1024 * seconds));
-#endif
-
-  calib_loop = 1;
-  per_loop = 0;
-  start = clock();
-  while ((clock() - start) < CLOCKS_PER_SEC / 4)
-    {
-      calib_loop *= 2;
-      for (i = 0; i < calib_loop; i++)
-       compress_buf(inb, in_len, outb, sizeof(outb));
-      per_loop += calib_loop;
-    }
-
-  fprintf(stderr, "compression:\nCalibrated to %d iterations per loop\n",
-          per_loop);
-
-  start = clock();
-  for (i = 0; i < 10; i++)
-    for (j = 0; j < per_loop; j++)
-      compress_buf(inb, in_len, outb, sizeof(outb));
-  end = clock();
-  seconds = (end - start) / (float) CLOCKS_PER_SEC;
-  fprintf(stderr, "%.2f seconds == %.2f MB/s\n", seconds,
-          ((long long) in_len * per_loop * 10) / (1024 * 1024 * seconds));
-
-  out_len = compress_buf(inb, in_len, outb, sizeof(outb));
-
-  calib_loop = 1;
-  per_loop = 0;
-  start = clock();
-  while ((clock() - start) < CLOCKS_PER_SEC / 4)
-    {
-      calib_loop *= 2;
-      for (i = 0; i < calib_loop; i++)
-       unchecked_decompress_buf(outb, out_len, inb, sizeof(inb));
-      per_loop += calib_loop;
-    }
-
-  fprintf(stderr, "decompression:\nCalibrated to %d iterations per loop\n",
-          per_loop);
-
-  start = clock();
-  for (i = 0; i < 10; i++)
-    for (j = 0; j < per_loop; j++)
-      unchecked_decompress_buf(outb, out_len, inb, sizeof(inb));
-  end = clock();
-  seconds = (end - start) / (float) CLOCKS_PER_SEC;
-  fprintf(stderr, "%.2f seconds == %.2f MB/s\n", seconds,
-          ((long long) in_len * per_loop * 10) / (1024 * 1024 * seconds));
-}
-
-int
-main(int argc, char *argv[])
-{
-  int compress = 1;
-  if (argc > 1 && !strcmp(argv[1], "-d"))
-    compress = 0;
-  if (argc > 1 && !strcmp(argv[1], "-b"))
-    benchmark(stdin);
-  else
-    transfer_file(stdin, stdout, compress);
-  return 0;
-}
-
-#endif
-
diff --git a/libsolv-0.6.15/src/repopage.h b/libsolv-0.6.15/src/repopage.h
deleted file mode 100644 (file)
index 739345e..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2007-2011, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef LIBSOLV_REPOPAGE_H
-#define LIBSOLV_REPOPAGE_H
-
-#define REPOPAGE_BLOBBITS 15
-#define REPOPAGE_BLOBSIZE (1 << REPOPAGE_BLOBBITS)
-
-typedef struct _Attrblobpage
-{
-  /* page_size == 0 means the page is not backed by some file storage.
-     Otherwise it is L*2+(compressed ? 1 : 0), with L being the data
-     length.  */
-  unsigned int page_offset;
-  unsigned int page_size;
-} Attrblobpage;
-
-typedef struct _Repopagestore {
-  int pagefd;          /* file descriptor we're paging from */
-  long file_offset;    /* pages in file start here */
-
-  unsigned char *blob_store;
-  unsigned int num_pages;
-
-  /* mapped_at[page] == -1  --> not loaded, otherwise offset into
-     store->blob_store.  The size of the mapping is REPOPAGE_BLOBSIZE
-     except for the last page.  */
-  unsigned int *mapped_at;
-
-  Attrblobpage *file_pages;
-
-  /* mapped[i] is -1 if nothing is mapped at logical page I,
-   otherwise it contains the page number (of the mapped page).  */
-  unsigned int *mapped;
-  unsigned int nmapped;
-  unsigned int rr_counter;
-} Repopagestore;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void repopagestore_init(Repopagestore *store);
-void repopagestore_free(Repopagestore *store);
-
-/* load pages pstart..pend into consecutive memory, return address */
-unsigned char *repopagestore_load_page_range(Repopagestore *store, unsigned int pstart, unsigned int pend);
-
-/* compress a page, return compressed len */
-unsigned int repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max);
-
-/* setup page data for repodata_load_page_range */
-int repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int pagesz, unsigned int blobsz);
-
-void repopagestore_disable_paging(Repopagestore *store);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_REPOPAGE_H */
diff --git a/libsolv-0.6.15/src/rules.c b/libsolv-0.6.15/src/rules.c
deleted file mode 100644 (file)
index 248b1cd..0000000
+++ /dev/null
@@ -1,4740 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * rules.c
- *
- * SAT based dependency solver
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "solver.h"
-#include "solver_private.h"
-#include "bitmap.h"
-#include "pool.h"
-#include "poolarch.h"
-#include "util.h"
-#include "evr.h"
-#include "policy.h"
-#include "solverdebug.h"
-#include "linkedpkg.h"
-#include "cplxdeps.h"
-
-#define RULES_BLOCK 63
-
-static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep);
-static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded);
-
-/*-------------------------------------------------------------------
- * Check if dependency is possible
- *
- * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap.
- * used in solver_addpkgrulesforweak and solver_createcleandepsmap.
- */
-
-static inline int
-dep_possible(Solver *solv, Id dep, Map *m)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags >= 8)
-        {
-         if (rd->flags == REL_COND)
-           return 1;
-         if (rd->flags == REL_AND)
-           {
-             if (!dep_possible(solv, rd->name, m))
-               return 0;
-             return dep_possible(solv, rd->evr, m);
-           }
-         if (rd->flags == REL_OR)
-           {
-             if (dep_possible(solv, rd->name, m))
-               return 1;
-             return dep_possible(solv, rd->evr, m);
-           }
-         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-           return solver_splitprovides(solv, rd->evr, m);
-       }
-    }
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (MAPTST(m, p))
-       return 1;
-    }
-  return 0;
-}
-
-static inline int
-is_otherproviders_dep(Pool *pool, Id dep)
-{
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
-       return 1;
-    }
-  return 0;
-}
-
-/********************************************************************
- *
- * Rule handling
- *
- * - unify rules, remove duplicates
- */
-
-/*-------------------------------------------------------------------
- *
- * compare rules for unification sort
- *
- */
-
-static int
-unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  Rule *a = (Rule *)ap;
-  Rule *b = (Rule *)bp;
-  Id *ad, *bd;
-  int x;
-
-  x = a->p - b->p;
-  if (x)
-    return x;                         /* p differs */
-
-  /* identical p */
-  if (a->d == 0 && b->d == 0)
-    return a->w2 - b->w2;             /* assertion: return w2 diff */
-
-  if (a->d == 0)                      /* a is assertion, b not */
-    {
-      x = a->w2 - pool->whatprovidesdata[b->d];
-      return x ? x : -1;
-    }
-
-  if (b->d == 0)                      /* b is assertion, a not */
-    {
-      x = pool->whatprovidesdata[a->d] - b->w2;
-      return x ? x : 1;
-    }
-
-  /* compare whatprovidesdata */
-  ad = pool->whatprovidesdata + a->d;
-  bd = pool->whatprovidesdata + b->d;
-  while (*bd)
-    if ((x = *ad++ - *bd++) != 0)
-      return x;
-  return *ad;
-}
-
-int
-solver_rulecmp(Solver *solv, Rule *r1, Rule *r2)
-{
-  return unifyrules_sortcmp(r1, r2, solv->pool);
-}
-
-
-/*-------------------------------------------------------------------
- *
- * unify rules
- * go over all rules and remove duplicates
- */
-
-void
-solver_unifyrules(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  int i, j;
-  Rule *ir, *jr;
-
-  if (solv->nrules <= 2)              /* nothing to unify */
-    return;
-
-  /* sort rules first */
-  solv_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
-
-  /* prune rules
-   * i = unpruned
-   * j = pruned
-   */
-  jr = 0;
-  for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
-    {
-      if (jr && !unifyrules_sortcmp(ir, jr, pool))
-       continue;                      /* prune! */
-      jr = solv->rules + j++;         /* keep! */
-      if (ir != jr)
-        *jr = *ir;
-    }
-
-  /* reduced count from nrules to j rules */
-  POOL_DEBUG(SOLV_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
-
-  /* adapt rule buffer */
-  solv->nrules = j;
-  solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
-
-  /*
-   * debug: log rule statistics
-   */
-  IF_POOLDEBUG (SOLV_DEBUG_STATS)
-    {
-      int binr = 0;
-      int lits = 0;
-      Id *dp;
-      Rule *r;
-
-      for (i = 1; i < solv->nrules; i++)
-       {
-         r = solv->rules + i;
-         if (r->d == 0)
-           binr++;
-         else
-           {
-             dp = solv->pool->whatprovidesdata + r->d;
-             while (*dp++)
-               lits++;
-           }
-       }
-      POOL_DEBUG(SOLV_DEBUG_STATS, "  binary: %d\n", binr);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
-    }
-}
-
-#if 0
-
-/*
- * hash rule
- */
-
-static Hashval
-hashrule(Solver *solv, Id p, Id d, int n)
-{
-  unsigned int x = (unsigned int)p;
-  int *dp;
-
-  if (n <= 1)
-    return (x * 37) ^ (unsigned int)d;
-  dp = solv->pool->whatprovidesdata + d;
-  while (*dp)
-    x = (x * 37) ^ (unsigned int)*dp++;
-  return x;
-}
-#endif
-
-
-/*-------------------------------------------------------------------
- *
- */
-
-/*
- * add rule
- *
- * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
- *
- * p < 0  : pkg id of A
- * d > 0  : Offset in whatprovidesdata (list of providers of b)
- *
- * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
- * p < 0  : pkg id of A
- * p2 < 0 : Id of solvable (e.g. B1)
- *
- * d == 0, p2 == 0: unary rule, assertion => (A) or (-A)
- *
- *   Install:    p > 0, d = 0   (A)             user requested install
- *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
- *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
- *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
- *   Conflicts:  p < 0, p2 < 0  (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
- *                                              also used for obsoletes
- *   No-op ?:    p = 0, d = 0   (null)          (used as placeholder in update/feature rules)
- *
- *   resulting watches:
- *   ------------------
- *   Direct assertion (no watch needed) --> d = 0, w1 = p, w2 = 0
- *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
- *   every other : w1 = p, w2 = whatprovidesdata[d];
- *
- *   always returns a rule for non-pkg rules
- */
-
-Rule *
-solver_addrule(Solver *solv, Id p, Id p2, Id d)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-
-  if (d)
-    {
-      assert(!p2 && d > 0);
-      if (!pool->whatprovidesdata[d])
-       d = 0;
-      else if (!pool->whatprovidesdata[d + 1])
-       {
-         p2 = pool->whatprovidesdata[d];
-         d = 0;
-       }
-    }
-
-  /* now we have two cases:
-   * 1 or 2 literals:    d = 0, p, p2 contain the literals
-   * 3 or more literals: d > 0, p2 == 0, d is offset into whatprovidesdata
-   */
-
-  /* it often happenes that requires lead to adding the same pkg rule
-   * multiple times, so we prune those duplicates right away to make
-   * the work for unifyrules a bit easier */
-  if (!solv->pkgrules_end)             /* we add pkg rules */
-    {
-      r = solv->rules + solv->nrules - 1;
-      if (d)
-       {
-         Id *dp;
-         /* check if rule is identical */
-         if (r->p == p)
-           {
-             Id *dp2;
-             if (r->d == d)
-               return r;
-             dp2 = pool->whatprovidesdata + r->d;
-             for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
-               if (*dp != *dp2)
-                 break;
-             if (*dp == *dp2)
-               return r;
-           }
-         /* check if rule is self-fulfilling */
-         for (dp = pool->whatprovidesdata + d; *dp; dp++)
-           if (*dp == -p)
-             return 0;                 /* rule is self-fulfilling */
-       }
-      else
-       {
-         if (p2 && p > p2)
-           {
-             Id o = p;                 /* switch p1 and p2 */
-             p = p2;
-             p2 = o;
-           }
-         if (r->p == p && !r->d && r->w2 == p2)
-           return r;
-         if (p == -p2)
-           return 0;                   /* rule is self-fulfilling */
-       }
-    }
-
-  solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
-  r = solv->rules + solv->nrules++;    /* point to rule space */
-  r->p = p;
-  r->d = d;
-  r->w1 = p;
-  r->w2 = d ? pool->whatprovidesdata[d] : p2;
-  r->n1 = 0;
-  r->n2 = 0;
-  IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
-    {
-      POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "  Add rule: ");
-      solver_printrule(solv, SOLV_DEBUG_RULE_CREATION, r);
-    }
-  return r;
-}
-
-
-void
-solver_shrinkrules(Solver *solv, int nrules)
-{
-  solv->nrules = nrules;
-  solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
-}
-
-/******************************************************************************
- ***
- *** pkg rule part: create rules representing the package dependencies
- ***
- ***/
-
-/*
- *  special multiversion patch conflict handling:
- *  a patch conflict is also satisfied if some other
- *  version with the same name/arch that doesn't conflict
- *  gets installed. The generated rule is thus:
- *  -patch|-cpack|opack1|opack2|...
- */
-static Id
-makemultiversionconflict(Solver *solv, Id n, Id con)
-{
-  Pool *pool = solv->pool;
-  Solvable *s, *sn;
-  Queue q;
-  Id p, pp, qbuf[64];
-
-  sn = pool->solvables + n;
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  queue_push(&q, -n);
-  FOR_PROVIDES(p, pp, sn->name)
-    {
-      s = pool->solvables + p;
-      if (s->name != sn->name || s->arch != sn->arch)
-       continue;
-      if (!MAPTST(&solv->multiversion, p))
-       continue;
-      if (pool_match_nevr(pool, pool->solvables + p, con))
-       continue;
-      /* here we have a multiversion solvable that doesn't conflict */
-      /* thus we're not in conflict if it is installed */
-      queue_push(&q, p);
-    }
-  if (q.count == 1)
-    n = 0;     /* no other package found, normal conflict handling */
-  else
-    n = pool_queuetowhatprovides(pool, &q);
-  queue_free(&q);
-  return n;
-}
-
-static inline void
-addpkgrule(Solver *solv, Id p, Id p2, Id d, int type, Id dep)
-{
-  if (!solv->ruleinfoq)
-    solver_addrule(solv, p, p2, d);
-  else
-    addpkgruleinfo(solv, p, p2, d, type, dep);
-}
-
-#ifdef ENABLE_LINKED_PKGS
-
-static void
-addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m, Queue *workq)
-{
-  Pool *pool = solv->pool;
-  int i;
-  if (!qr->count)
-    return;
-#if 0
-  printf("ADDLINKS %s\n -> %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
-  for (i = 0; i < qr->count; i++)
-    printf("    - %s\n", pool_solvid2str(pool, qr->elements[i]));
-  printf(" <- %s\n", pool_dep2str(pool, prv));
-  for (i = 0; i < qp->count; i++)
-    printf("    - %s\n", pool_solvid2str(pool, qp->elements[i]));
-#endif
-
-  if (qr->count == 1)
-    addpkgrule(solv, -(s - pool->solvables), qr->elements[0], 0, SOLVER_RULE_PKG_REQUIRES, req);
-  else
-    addpkgrule(solv, -(s - pool->solvables), 0, pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req);
-  if (qp->count > 1)
-    {
-      Id d = pool_queuetowhatprovides(pool, qp);
-      for (i = 0; i < qr->count; i++)
-       addpkgrule(solv, -qr->elements[i], 0, d, SOLVER_RULE_PKG_REQUIRES, prv);
-    }
-  else if (qp->count)
-    {
-      for (i = 0; i < qr->count; i++)
-       addpkgrule(solv, -qr->elements[i], qp->elements[0], 0, SOLVER_RULE_PKG_REQUIRES, prv);
-    }
-  if (!m)
-    return;    /* nothing more to do if called from getpkgruleinfos() */
-  for (i = 0; i < qr->count; i++)
-    if (!MAPTST(m, qr->elements[i]))
-      queue_push(workq, qr->elements[i]);
-  for (i = 0; i < qp->count; i++)
-    if (!MAPTST(m, qp->elements[i]))
-      queue_push(workq, qp->elements[i]);
-  if (solv->installed && s->repo == solv->installed)
-    {
-      Repo *installed = solv->installed;
-      /* record installed buddies */
-      if (!solv->instbuddy)
-        solv->instbuddy = solv_calloc(installed->end - installed->start, sizeof(Id));
-      if (qr->count == 1)
-        solv->instbuddy[s - pool->solvables - installed->start] = qr->elements[0];
-      for (i = 0; i < qr->count; i++)
-       {
-         Id p = qr->elements[i];
-         if (pool->solvables[p].repo != installed)
-           continue;   /* huh? */
-         if (qp->count > 1 || (solv->instbuddy[p - installed->start] != 0 && solv->instbuddy[p - installed->start] != s - pool->solvables))
-           solv->instbuddy[p - installed->start] = 1;  /* 1: ambiguous buddy */
-         else
-           solv->instbuddy[p - installed->start] = s - pool->solvables;
-       }
-    }
-}
-
-static void
-add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq)
-{
-  Queue qr, qp;
-  Id req = 0, prv = 0;
-  queue_init(&qr);
-  queue_init(&qp);
-  find_package_link(solv->pool, s, &req, &qr, &prv, &qp);
-  if (qr.count)
-    addlinks(solv, s, req, &qr, prv, &qp, m, workq);
-  queue_free(&qr);
-  queue_free(&qp);
-}
-
-#endif
-
-#ifdef ENABLE_COMPLEX_DEPS
-
-static void
-add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  int i, j, flags;
-  Queue bq;
-
-  queue_init(&bq);
-  flags = dontfix ? CPLXDEPS_DONTFIX : 0;
-  /* CNF expansion for requires, DNF + INVERT expansion for conflicts */
-  if (type == SOLVER_RULE_PKG_CONFLICTS)
-    flags |= CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT;
-
-  i = pool_normalize_complex_dep(pool, dep, &bq, flags);
-  /* handle special cases */
-  if (i == 0)
-    {
-      if (dontfix)
-       {
-         POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken dependency %s of installed package %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, p));
-       }
-      else
-       {
-         POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep));
-         addpkgrule(solv, -p, 0, 0, type == SOLVER_RULE_PKG_REQUIRES ? SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP : type, dep);
-       }
-      queue_free(&bq);
-      return;
-    }
-  if (i == 1)
-    {
-      queue_free(&bq);
-      return;
-    }
-
-  /* go through all blocks and add a rule for each block */
-  for (i = 0; i < bq.count; i++)
-    {
-      if (!bq.elements[i])
-       continue;       /* huh? */
-      if (bq.elements[i] == pool->nsolvables)
-       {
-         /* conventional requires (cannot be a conflicts as they have been expanded) */
-         Id *dp = pool->whatprovidesdata + bq.elements[i + 1];
-         i += 2;
-         if (dontfix)
-           {
-             for (j = 0; dp[j] != 0; j++)
-               if (pool->solvables[dp[j]].repo == installed)
-                 break;                /* provider was installed */
-             if (!dp[j])
-               continue;
-           }
-         /* check if the rule contains both p and -p */
-         for (j = 0; dp[j] != 0; j++)
-           if (dp[j] == p)
-             break;
-         if (dp[j])
-           continue;
-         addpkgrule(solv, -p, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, dep);
-         /* push all non-visited providers on the work queue */
-         if (m)
-           for (; *dp; dp++)
-             if (!MAPTST(m, *dp))
-               queue_push(workq, *dp);
-         continue;
-       }
-      if (!bq.elements[i + 1])
-       {
-         Id p2 = bq.elements[i++];
-         /* simple rule with just two literals, we'll add a (-p, p2) rule */
-         if (dontfix)
-           {
-             if (p2 < 0 && pool->solvables[-p2].repo == installed)
-               continue;
-             if (p2 > 0 && pool->solvables[p2].repo != installed)
-               continue;
-           }
-         if (-p == p2)
-           {
-             if (type == SOLVER_RULE_PKG_CONFLICTS)
-               {
-                 if (pool->forbidselfconflicts && !is_otherproviders_dep(pool, dep))
-                   addpkgrule(solv, -p, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, dep);
-                 continue;
-               }
-             addpkgrule(solv, -p, 0, 0, type, dep);
-             continue;
-           }
-         /* check if the rule contains both p and -p */
-         if (p == p2)
-           continue;
-         addpkgrule(solv, -p, p2, 0, type, dep);
-         if (m && p2 > 0 && !MAPTST(m, p2))
-           queue_push(workq, p2);
-       }
-      else
-       {
-         Id *qele;
-         int qcnt;
-
-         qele = bq.elements + i;
-         qcnt = i;
-         while (bq.elements[i])
-            i++;
-         qcnt = i - qcnt;
-         if (dontfix)
-           {
-             for (j = 0; j < qcnt; j++)
-               {
-                 if (qele[j] > 0 && pool->solvables[qele[j]].repo == installed)
-                   break;
-                 if (qele[j] < 0 && pool->solvables[-qele[j]].repo != installed)
-                   break;
-               }
-             if (j == qcnt)
-               continue;
-           }
-         /* add -p to (ordered) rule (overwriting the trailing zero) */
-         for (j = 0; ; j++)
-           {
-             if (j == qcnt || qele[j] > -p)
-               {
-                 if (j < qcnt)
-                   memmove(qele + j + 1, qele + j, (qcnt - j) * sizeof(Id));
-                 qele[j] = -p;
-                 qcnt++;
-                 break;
-               }
-             if (qele[j] == -p)
-               break;
-           }
-         /* check if the rule contains both p and -p */
-         for (j = 0; j < qcnt; j++)
-           if (qele[j] == p)
-             break;
-         if (j < qcnt)
-           continue;
-         addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep);
-         if (m)
-           for (j = 0; j < qcnt; j++)
-             if (qele[j] > 0 && !MAPTST(m, qele[j]))
-               queue_push(workq, qele[j]);
-       }
-    }
-  queue_free(&bq);
-}
-
-#endif
-
-/*-------------------------------------------------------------------
- *
- * add (install) rules for solvable
- *
- * s: Solvable for which to add rules
- * m: m[s] = 1 for solvables which have rules, prevent rule duplication
- *
- * Algorithm: 'visit all nodes of a graph'. The graph nodes are
- *  solvables, the edges their dependencies.
- *  Starting from an installed solvable, this will create all rules
- *  representing the graph created by the solvables dependencies.
- *
- * for unfulfilled requirements, conflicts, obsoletes,....
- * add a negative assertion for solvables that are not installable
- *
- * It will also create rules for all solvables referenced by 's'
- *  i.e. descend to all providers of requirements of 's'
- *
- */
-
-void
-solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-
-  Queue workq; /* list of solvables we still have to work on */
-  Id workqbuf[64];
-
-  int i;
-  int dontfix;         /* ignore dependency errors for installed solvables */
-  Id req, *reqp;
-  Id con, *conp;
-  Id obs, *obsp;
-  Id rec, *recp;
-  Id sug, *sugp;
-  Id p, pp;            /* whatprovides loops */
-  Id *dp;              /* ptr to 'whatprovides' */
-  Id n;                        /* Id for current solvable 's' */
-
-  queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
-  queue_push(&workq, s - pool->solvables);     /* push solvable Id to work queue */
-
-  /* loop until there's no more work left */
-  while (workq.count)
-    {
-      /*
-       * n: Id of solvable
-       * s: Pointer to solvable
-       */
-
-      n = queue_shift(&workq);         /* 'pop' next solvable to work on from queue */
-      if (m)
-       {
-         if (MAPTST(m, n))             /* continue if already visited */
-           continue;
-         MAPSET(m, n);                 /* mark as visited */
-       }
-
-      s = pool->solvables + n;
-
-      dontfix = 0;
-      if (installed                    /* Installed system available */
-         && s->repo == installed       /* solvable is installed */
-         && !solv->fixmap_all          /* NOT repair errors in dependency graph */
-         && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
-        {
-         dontfix = 1;                  /* dont care about broken deps */
-        }
-
-      if (!dontfix)
-       {
-         if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC
-               ? pool_disabled_solvable(pool, s)
-               : !pool_installable(pool, s))
-           {
-             POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", pool_solvid2str(pool, n), n);
-             addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0);
-           }
-       }
-
-#ifdef ENABLE_LINKED_PKGS
-      /* add pseudo-package <-> real-package links */
-      if (has_package_link(pool, s))
-        add_package_link(solv, s, m, &workq);
-#endif
-
-      /*-----------------------------------------
-       * check requires of s
-       */
-
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)            /* go through all requires */
-           {
-             if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
-               continue;
-
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, req))
-               {
-                 /* we have AND/COND deps, normalize */
-                 add_complex_deprules(solv, n, req, SOLVER_RULE_PKG_REQUIRES, dontfix, &workq, m);
-                 continue;
-               }
-#endif
-
-             /* find list of solvables providing 'req' */
-             dp = pool_whatprovides_ptr(pool, req);
-
-             if (*dp == SYSTEMSOLVABLE)          /* always installed */
-               continue;
-
-             if (dontfix)
-               {
-                 /* the strategy here is to not insist on dependencies
-                   * that are already broken. so if we find one provider
-                   * that was already installed, we know that the
-                   * dependency was not broken before so we enforce it */
-                 for (i = 0; (p = dp[i]) != 0; i++)
-                   if (pool->solvables[p].repo == installed)
-                     break;            /* found installed provider */
-                 if (!p)
-                   {
-                     /* didn't find an installed provider: previously broken dependency */
-                     POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s));
-                     continue;
-                   }
-               }
-
-             if (!*dp)
-               {
-                 POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, n), n, pool_dep2str(pool, req));
-                 addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req);
-                 continue;
-               }
-
-             for (i = 0; dp[i] != 0; i++)
-               if (n == dp[i])
-                 break;
-             if (dp[i])
-               continue;               /* provided by itself, no need to add rule */
-
-             IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
-               {
-                 POOL_DEBUG(SOLV_DEBUG_RULE_CREATION,"  %s requires %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
-                 for (i = 0; dp[i]; i++)
-                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "   provided by %s\n", pool_solvid2str(pool, dp[i]));
-               }
-
-             /* add 'requires' dependency */
-              /* rule: (-requestor|provider1|provider2|...|providerN) */
-             addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req);
-
-             /* push all non-visited providers on the work queue */
-             if (m)
-               for (; *dp; dp++)
-                 if (!MAPTST(m, *dp))
-                   queue_push(&workq, *dp);
-           }
-       }
-
-      /* that's all we check for src packages */
-      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-       continue;
-
-      /*-----------------------------------------
-       * check conflicts of s
-       */
-
-      if (s->conflicts)
-       {
-         int ispatch = 0;
-
-         /* we treat conflicts in patches a bit differen:
-          * - nevr matching
-          * - multiversion handling
-          * XXX: we should really handle this different, looking
-          * at the name is a bad hack
-          */
-         if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
-           ispatch = 1;
-         conp = s->repo->idarraydata + s->conflicts;
-         /* foreach conflicts of 's' */
-         while ((con = *conp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (!ispatch && pool_is_complex_dep(pool, con))
-               {
-                 /* we have AND/COND deps, normalize */
-                 add_complex_deprules(solv, n, con, SOLVER_RULE_PKG_CONFLICTS, dontfix, &workq, m);
-                 continue;
-               }
-#endif
-             /* foreach providers of a conflict of 's' */
-             FOR_PROVIDES(p, pp, con)
-               {
-                 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
-                   continue;
-                 /* dontfix: dont care about conflicts with already installed packs */
-                 if (dontfix && pool->solvables[p].repo == installed)
-                   continue;
-                 if (p == n)           /* p == n: self conflict */
-                   {
-                     if (!pool->forbidselfconflicts || is_otherproviders_dep(pool, con))
-                       continue;
-                     addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con);
-                     continue;
-                   }
-                 if (ispatch && solv->multiversion.size && MAPTST(&solv->multiversion, p) && ISRELDEP(con))
-                   {
-                     /* our patch conflicts with a multiversion package */
-                     Id d = makemultiversionconflict(solv, p, con);
-                     if (d)
-                       {
-                         addpkgrule(solv, -n, 0, d, SOLVER_RULE_PKG_CONFLICTS, con);
-                         continue;
-                       }
-                   }
-                 if (p == SYSTEMSOLVABLE)
-                   p = 0;
-                  /* rule: -n|-p: either solvable _or_ provider of conflict */
-                 addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONFLICTS, con);
-               }
-           }
-       }
-
-      /*-----------------------------------------
-       * check obsoletes and implicit obsoletes of a package
-       * if ignoreinstalledsobsoletes is not set, we're also checking
-       * obsoletes of installed packages (like newer rpm versions)
-       */
-      if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
-       {
-         int multi = solv->multiversion.size && MAPTST(&solv->multiversion, n);
-         int isinstalled = (installed && s->repo == installed);
-         if (s->obsoletes && (!multi || solv->keepexplicitobsoletes))
-           {
-             obsp = s->repo->idarraydata + s->obsoletes;
-             /* foreach obsoletes */
-             while ((obs = *obsp++) != 0)
-               {
-                 /* foreach provider of an obsoletes of 's' */
-                 FOR_PROVIDES(p, pp, obs)
-                   {
-                     Solvable *ps = pool->solvables + p;
-                     if (p == n)
-                       continue;
-                     if (isinstalled && dontfix && ps->repo == installed)
-                       continue;       /* don't repair installed/installed problems */
-                     if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
-                         && !pool_match_nevr(pool, ps, obs))
-                       continue;
-                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-                       continue;
-                     if (p == SYSTEMSOLVABLE)
-                       p = 0;
-                     if (!isinstalled)
-                       addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_OBSOLETES, obs);
-                     else
-                       addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs);
-                   }
-               }
-           }
-         /* check implicit obsoletes
-           * for installed packages we only need to check installed/installed problems (and
-           * only when dontfix is not set), as the others are picked up when looking at the
-           * uninstalled package.
-           */
-         if (!isinstalled || !dontfix)
-           {
-             FOR_PROVIDES(p, pp, s->name)
-               {
-                 Solvable *ps = pool->solvables + p;
-                 if (p == n)
-                   continue;
-                 if (isinstalled && ps->repo != installed)
-                   continue;
-                 /* we still obsolete packages with same nevra, like rpm does */
-                 /* (actually, rpm mixes those packages. yuck...) */
-                 if (multi && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
-                   {
-                     if (isinstalled || ps->repo != installed)
-                       continue;
-                     /* also check the installed package for multi-ness */
-                     if (MAPTST(&solv->multiversion, p))
-                       continue;
-                   }
-                 if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
-                   continue;
-                 if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
-                   continue;
-                 if (p == SYSTEMSOLVABLE)
-                   p = 0;
-                 if (s->name == ps->name)
-                   {
-                     /* optimization: do not add the same-name conflict rule if it was
-                      * already added when we looked at the other package.
-                      * (this assumes pool_colormatch is symmetric) */
-                     if (p && m && ps->repo != installed && MAPTST(m, p) &&
-                         (ps->arch != ARCH_SRC && ps->arch != ARCH_NOSRC) &&
-                         !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
-                       continue;
-                     addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_SAME_NAME, 0);
-                   }
-                 else
-                   addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name);
-               }
-           }
-       }
-
-      if (m && pool->implicitobsoleteusescolors && (s->arch > pool->lastarch || pool->id2arch[s->arch] != 1))
-       {
-         int a = pool->id2arch[s->arch];
-         /* check lock-step candidates */
-         FOR_PROVIDES(p, pp, s->name)
-           {
-             Solvable *ps = pool->solvables + p;
-             if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p))
-               continue;
-             if (ps->arch > pool->lastarch || pool->id2arch[ps->arch] == 1 || pool->id2arch[ps->arch] >= a)
-               continue;
-             queue_push(&workq, p);
-           }
-       }
-
-      /*-----------------------------------------
-       * add recommends/suggests to the work queue
-       */
-      if (s->recommends && m)
-       {
-         recp = s->repo->idarraydata + s->recommends;
-         while ((rec = *recp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, rec))
-               {
-                 pool_add_pos_literals_complex_dep(pool, rec, &workq, m, 0);
-                   continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, rec)
-               if (!MAPTST(m, p))
-                 queue_push(&workq, p);
-           }
-       }
-      if (s->suggests && m)
-       {
-         sugp = s->repo->idarraydata + s->suggests;
-         while ((sug = *sugp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, sug))
-               {
-                 pool_add_pos_literals_complex_dep(pool, sug, &workq, m, 0);
-                   continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, sug)
-               if (!MAPTST(m, p))
-                 queue_push(&workq, p);
-           }
-       }
-    }
-  queue_free(&workq);
-}
-
-#ifdef ENABLE_LINKED_PKGS
-void
-solver_addpkgrulesforlinked(Solver *solv, Map *m)
-{
-  Pool *pool = solv->pool;
-  Solvable *s;
-  int i, j;
-  Queue qr;
-
-  queue_init(&qr);
-  for (i = 1; i < pool->nsolvables; i++)
-    {
-      if (MAPTST(m, i))
-       continue;
-      s = pool->solvables + i;
-      if (!s->repo || s->repo == solv->installed)
-       continue;
-      if (!strchr(pool_id2str(pool, s->name), ':'))
-       continue;
-      if (!pool_installable(pool, s))
-       continue;
-      find_package_link(pool, s, 0, &qr, 0, 0);
-      if (qr.count)
-       {
-         for (j = 0; j < qr.count; j++)
-           if (MAPTST(m, qr.elements[j]))
-             {
-               solver_addpkgrulesforsolvable(solv, s, m);
-               break;
-             }
-         queue_empty(&qr);
-       }
-    }
-  queue_free(&qr);
-}
-#endif
-
-/*-------------------------------------------------------------------
- *
- * Add rules for packages possibly selected in by weak dependencies
- *
- * m: already added solvables
- */
-
-void
-solver_addpkgrulesforweak(Solver *solv, Map *m)
-{
-  Pool *pool = solv->pool;
-  Solvable *s;
-  Id sup, *supp;
-  int i, n;
-
-  /* foreach solvable in pool */
-  for (i = n = 1; n < pool->nsolvables; i++, n++)
-    {
-      if (i == pool->nsolvables)               /* wrap i */
-       i = 1;
-      if (MAPTST(m, i))                                /* already added that one */
-       continue;
-
-      s = pool->solvables + i;
-      if (!s->repo)
-       continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       continue;       /* only look at installable ones */
-
-      sup = 0;
-      if (s->supplements)
-       {
-         /* find possible supplements */
-         supp = s->repo->idarraydata + s->supplements;
-         while ((sup = *supp++) != 0)
-           if (dep_possible(solv, sup, m))
-             break;
-       }
-
-      /* if nothing found, check for enhances */
-      if (!sup && s->enhances)
-       {
-         supp = s->repo->idarraydata + s->enhances;
-         while ((sup = *supp++) != 0)
-           if (dep_possible(solv, sup, m))
-             break;
-       }
-      /* if nothing found, goto next solvables */
-      if (!sup)
-       continue;
-      solver_addpkgrulesforsolvable(solv, s, m);
-      n = 0;                   /* check all solvables again because we added solvables to m */
-    }
-}
-
-
-/*-------------------------------------------------------------------
- *
- * add package rules for possible updates
- *
- * s: solvable
- * m: map of already visited solvables
- * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
- */
-
-void
-solver_addpkgrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
-{
-  Pool *pool = solv->pool;
-  int i;
-    /* queue and buffer for it */
-  Queue qs;
-  Id qsbuf[64];
-
-  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
-    /* find update candidates for 's' */
-  policy_findupdatepackages(solv, s, &qs, allow_all);
-    /* add rule for 's' if not already done */
-  if (!MAPTST(m, s - pool->solvables))
-    solver_addpkgrulesforsolvable(solv, s, m);
-    /* foreach update candidate, add rule if not already done */
-  for (i = 0; i < qs.count; i++)
-    if (!MAPTST(m, qs.elements[i]))
-      solver_addpkgrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
-  queue_free(&qs);
-}
-
-
-/***********************************************************************
- ***
- ***  Update/Feature rule part
- ***
- ***  Those rules make sure an installed package isn't silently deleted
- ***
- ***/
-
-static Id
-finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
-{
-  Pool *pool = solv->pool;
-  int i;
-
-  policy_findupdatepackages(solv, s, qs, allow_all ? allow_all : 2);
-  if (!qs->count)
-    {
-      if (allow_all)
-        return 0;              /* orphaned, don't create feature rule */
-      /* check if this is an orphaned package */
-      policy_findupdatepackages(solv, s, qs, 1);
-      if (!qs->count)
-       return 0;               /* orphaned, don't create update rule */
-      qs->count = 0;
-      return -SYSTEMSOLVABLE;  /* supported but not installable */
-    }
-  if (allow_all)
-    return s - pool->solvables;
-  /* check if it is ok to keep the installed package */
-  if (solv->dupmap.size && MAPTST(&solv->dupmap,  s - pool->solvables))
-    return s - pool->solvables;
-  for (i = 0; i < qs->count; i++)
-    {
-      Solvable *ns = pool->solvables + qs->elements[i];
-      if (s->evr == ns->evr && solvable_identical(s, ns))
-        return s - pool->solvables;
-    }
-  /* nope, it must be some other package */
-  return -SYSTEMSOLVABLE;
-}
-
-#if 0
-/* add packages from the dup repositories to the update candidates
- * this isn't needed for the global dup mode as all packages are
- * from dup repos in that case */
-static void
-addduppackages(Solver *solv, Solvable *s, Queue *qs)
-{
-  Queue dupqs;
-  Id p, dupqsbuf[64];
-  int i;
-  int oldnoupdateprovide = solv->noupdateprovide;
-
-  queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf));
-  solv->noupdateprovide = 1;
-  policy_findupdatepackages(solv, s, &dupqs, 2);
-  solv->noupdateprovide = oldnoupdateprovide;
-  for (i = 0; i < dupqs.count; i++)
-    {
-      p = dupqs.elements[i];
-      if (MAPTST(&solv->dupmap, p))
-        queue_pushunique(qs, p);
-    }
-  queue_free(&dupqs);
-}
-#endif
-
-/*-------------------------------------------------------------------
- *
- * add rule for update
- *   (A|A1|A2|A3...)  An = update candidates for A
- *
- * s = (installed) solvable
- */
-
-void
-solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
-{
-  /* installed packages get a special upgrade allowed rule */
-  Pool *pool = solv->pool;
-  Id p, d;
-  Queue qs;
-  Id qsbuf[64];
-  int isorphaned = 0;
-
-  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
-  p = s - pool->solvables;
-  /* find update candidates for 's' */
-  if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
-    p = finddistupgradepackages(solv, s, &qs, allow_all);
-  else
-    policy_findupdatepackages(solv, s, &qs, allow_all);
-
-#ifdef ENABLE_LINKED_PKGS
-  if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start])
-    {
-      const char *name = pool_id2str(pool, s->name);
-      if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
-       {
-         /* a linked pseudo package. As it is linked, we do not need an update/feature rule */
-         /* nevertheless we set specialupdaters so we can update */
-         solver_addrule(solv, 0, 0, 0);
-         if (!allow_all && qs.count)
-           {
-             if (p != -SYSTEMSOLVABLE)
-               queue_unshift(&qs, p);
-             if (!solv->specialupdaters)
-               solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
-             solv->specialupdaters[s - pool->solvables - solv->installed->start] = pool_queuetowhatprovides(pool, &qs);
-           }
-         queue_free(&qs);
-         return;
-       }
-    }
-#endif
-
-  if (!allow_all && !p)                /* !p implies qs.count == 0 */
-    {
-      queue_push(&solv->orphaned, s - pool->solvables);                /* an orphaned package */
-      if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
-       p = s - pool->solvables;        /* keep this orphaned package installed */
-      queue_free(&qs);
-      solver_addrule(solv, p, 0, 0);
-      return;
-    }
-
-  if (!allow_all && qs.count && solv->multiversion.size)
-    {
-      int i, j;
-
-      for (i = 0; i < qs.count; i++)
-       if (MAPTST(&solv->multiversion, qs.elements[i]))
-         break;
-      if (i < qs.count)
-       {
-         /* filter out all multiversion packages as they don't update */
-         d = pool_queuetowhatprovides(pool, &qs);      /* save qs away */
-         for (j = i; i < qs.count; i++)
-            {
-             if (MAPTST(&solv->multiversion, qs.elements[i]))
-               {
-                 Solvable *ps = pool->solvables + qs.elements[i];
-                 /* if keepexplicitobsoletes is set and the name is different,
-                  * we assume that there is an obsoletes. XXX: not 100% correct */
-                 if (solv->keepexplicitobsoletes && ps->name != s->name)
-                   {
-                     qs.elements[j++] = qs.elements[i];
-                     continue;
-                   }
-                 /* it's ok if they have same nevra */
-                 if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
-                   continue;
-               }
-             qs.elements[j++] = qs.elements[i];
-           }
-         if (j < qs.count)             /* filtered at least one package? */
-           {
-             if (j == 0 && p == -SYSTEMSOLVABLE)
-               {
-                 /* this is a multiversion orphan */
-                 queue_push(&solv->orphaned, s - pool->solvables);
-                 if (!solv->specialupdaters)
-                   solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
-                 solv->specialupdaters[s - pool->solvables - solv->installed->start] = d;
-                 if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
-                   {
-                     /* we need to keep the orphan */
-                     queue_free(&qs);
-                     solver_addrule(solv, s - pool->solvables, 0, 0);
-                     return;
-                   }
-                 /* we can drop it as long as we update */
-                 isorphaned = 1;
-                 j = qs.count;         /* force the update */
-               }
-             qs.count = j;
-           }
-         else if (p != -SYSTEMSOLVABLE)
-           {
-             /* could fallthrough, but then we would do pool_queuetowhatprovides twice */
-             queue_free(&qs);
-             solver_addrule(solv, s - pool->solvables, 0, d);  /* allow update of s */
-             return;
-           }
-       }
-    }
-  if (!isorphaned && p == -SYSTEMSOLVABLE && solv->dupmap.size)
-    p = s - pool->solvables;           /* let the dup rules sort it out */
-  if (qs.count && p == -SYSTEMSOLVABLE)
-    p = queue_shift(&qs);
-  if (qs.count > 1)
-    {
-      d = pool_queuetowhatprovides(pool, &qs);
-      queue_free(&qs);
-      solver_addrule(solv, p, 0, d);   /* allow update of s */
-    }
-  else
-    {
-      d = qs.count ? qs.elements[0] : 0;
-      queue_free(&qs);
-      solver_addrule(solv, p, d, 0);   /* allow update of s */
-    }
-}
-
-static inline void
-disableupdaterule(Solver *solv, Id p)
-{
-  Rule *r;
-
-  MAPSET(&solv->noupdate, p - solv->installed->start);
-  r = solv->rules + solv->updaterules + (p - solv->installed->start);
-  if (r->p && r->d >= 0)
-    solver_disablerule(solv, r);
-  r = solv->rules + solv->featurerules + (p - solv->installed->start);
-  if (r->p && r->d >= 0)
-    solver_disablerule(solv, r);
-  if (solv->bestrules_pkg)
-    {
-      int i, ni;
-      ni = solv->bestrules_end - solv->bestrules;
-      for (i = 0; i < ni; i++)
-       if (solv->bestrules_pkg[i] == p)
-         solver_disablerule(solv, solv->rules + solv->bestrules + i);
-    }
-}
-
-static inline void
-reenableupdaterule(Solver *solv, Id p)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-
-  MAPCLR(&solv->noupdate, p - solv->installed->start);
-  r = solv->rules + solv->updaterules + (p - solv->installed->start);
-  if (r->p)
-    {
-      if (r->d < 0)
-       {
-         solver_enablerule(solv, r);
-         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
-           }
-       }
-    }
-  else
-    {
-      r = solv->rules + solv->featurerules + (p - solv->installed->start);
-      if (r->p && r->d < 0)
-       {
-         solver_enablerule(solv, r);
-         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
-           }
-       }
-    }
-  if (solv->bestrules_pkg)
-    {
-      int i, ni;
-      ni = solv->bestrules_end - solv->bestrules;
-      for (i = 0; i < ni; i++)
-       if (solv->bestrules_pkg[i] == p)
-         solver_enablerule(solv, solv->rules + solv->bestrules + i);
-    }
-}
-
-
-/***********************************************************************
- ***
- ***  Infarch rule part
- ***
- ***  Infarch rules make sure the solver uses the best architecture of
- ***  a package if multiple archetectures are available
- ***
- ***/
-
-void
-solver_addinfarchrules(Solver *solv, Map *addedmap)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = pool->installed;
-  int first, i, j;
-  Id p, pp, a, aa, bestarch;
-  Solvable *s, *ps, *bests;
-  Queue badq, allowedarchs;
-  Queue lsq;
-
-  queue_init(&badq);
-  queue_init(&allowedarchs);
-  queue_init(&lsq);
-  solv->infarchrules = solv->nrules;
-  for (i = 1; i < pool->nsolvables; i++)
-    {
-      if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
-       continue;
-      s = pool->solvables + i;
-      first = i;
-      bestarch = 0;
-      bests = 0;
-      queue_empty(&allowedarchs);
-      FOR_PROVIDES(p, pp, s->name)
-       {
-         ps = pool->solvables + p;
-         if (ps->name != s->name || !MAPTST(addedmap, p))
-           continue;
-         if (p == i)
-           first = 0;
-         if (first)
-           break;
-         a = ps->arch;
-         a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-         if (a != 1 && installed && ps->repo == installed)
-           {
-             if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
-               queue_pushunique(&allowedarchs, ps->arch);      /* also ok to keep this architecture */
-             continue;         /* ignore installed solvables when calculating the best arch */
-           }
-         if (a && a != 1 && (!bestarch || a < bestarch))
-           {
-             bestarch = a;
-             bests = ps;
-           }
-       }
-      if (first)
-       continue;
-
-      /* speed up common case where installed package already has best arch */
-      if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
-       allowedarchs.count--;   /* installed arch is best */
-
-      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestarch)
-       {
-         /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
-          * if the corresponding installed package is not lock-stepped */
-         queue_empty(&allowedarchs);
-         FOR_PROVIDES(p, pp, s->name)
-           {
-             Id p2, pp2;
-             ps = pool->solvables + p;
-             if (ps->name != s->name || ps->repo != installed || !MAPTST(addedmap, p))
-               continue;
-             if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
-               continue;
-             a = ps->arch;
-             a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-             if (!a)
-               {
-                 queue_pushunique(&allowedarchs, ps->arch);    /* strange arch, allow */
-                 continue;
-               }
-             if (a == 1 || ((a ^ bestarch) & 0xffff0000) == 0)
-               continue;
-             /* have installed package with inferior arch, check if lock-stepped */
-             FOR_PROVIDES(p2, pp2, s->name)
-               {
-                 Solvable *s2 = pool->solvables + p2;
-                 Id a2;
-                 if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
-                   continue;
-                 a2 = s2->arch;
-                 a2 = (a2 <= pool->lastarch) ? pool->id2arch[a2] : 0;
-                 if (a2 && (a2 == 1 || ((a2 ^ bestarch) & 0xffff0000) == 0))
-                   break;
-               }
-             if (!p2)
-               queue_pushunique(&allowedarchs, ps->arch);
-           }
-       }
-
-      /* find all bad packages */
-      queue_empty(&badq);
-      FOR_PROVIDES(p, pp, s->name)
-       {
-         ps = pool->solvables + p;
-         if (ps->name != s->name || !MAPTST(addedmap, p))
-           continue;
-         a = ps->arch;
-         a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-         if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
-           {
-             if (installed && ps->repo == installed)
-               {
-                 if (pool->implicitobsoleteusescolors)
-                   queue_push(&badq, p);               /* special lock-step handling, see below */
-                 continue;     /* always ok to keep an installed package */
-               }
-             for (j = 0; j < allowedarchs.count; j++)
-               {
-                 aa = allowedarchs.elements[j];
-                 if (ps->arch == aa)
-                   break;
-                 aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
-                 if (aa && ((a ^ aa) & 0xffff0000) == 0)
-                   break;      /* compatible */
-               }
-             if (j == allowedarchs.count)
-               queue_push(&badq, p);
-           }
-       }
-
-      /* block all solvables in the badq! */
-      for (j = 0; j < badq.count; j++)
-       {
-         p = badq.elements[j];
-         /* lock-step */
-         if (pool->implicitobsoleteusescolors)
-           {
-             Id p2;
-             int haveinstalled = 0;
-             queue_empty(&lsq);
-             FOR_PROVIDES(p2, pp, s->name)
-               {
-                 Solvable *s2 = pool->solvables + p2;
-                 if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
-                   continue;
-                 a = s2->arch;
-                 a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-                 if (a && (a == 1 || ((a ^ bestarch) & 0xffff000) == 0))
-                   {
-                     queue_push(&lsq, p2);
-                     if (installed && s2->repo == installed)
-                       haveinstalled = 1;
-                   }
-               }
-             if (installed && pool->solvables[p].repo == installed && !haveinstalled)
-               continue;       /* installed package not in lock-step */
-           }
-         if (lsq.count < 2)
-           solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0);
-         else
-           solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq));
-       }
-    }
-  queue_free(&lsq);
-  queue_free(&badq);
-  queue_free(&allowedarchs);
-  solv->infarchrules_end = solv->nrules;
-}
-
-static inline void
-disableinfarchrule(Solver *solv, Id name)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  int i;
-  for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
-    {
-      if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
-        solver_disablerule(solv, r);
-    }
-}
-
-static inline void
-reenableinfarchrule(Solver *solv, Id name)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  int i;
-  for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
-    {
-      if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
-        {
-          solver_enablerule(solv, r);
-          IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-            {
-              POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-              solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
-            }
-        }
-    }
-}
-
-
-/***********************************************************************
- ***
- ***  Dup rule part
- ***
- ***  Dup rules make sure a package is selected from the specified dup
- ***  repositories if an update candidate is included in one of them.
- ***
- ***/
-
-static inline void
-add_cleandeps_package(Solver *solv, Id p)
-{
-  if (!solv->cleandeps_updatepkgs)
-    {
-      solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
-      queue_init(solv->cleandeps_updatepkgs);
-    }
-  queue_pushunique(solv->cleandeps_updatepkgs, p);
-}
-
-static void
-solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted)
-{
-  Pool *pool = solv->pool;
-  Solvable *ps, *s = pool->solvables + p;
-  Repo *installed = solv->installed;
-  Id pi, pip, obs, *obsp;
-
-  MAPSET(&solv->dupinvolvedmap, p);
-  if (targeted)
-    MAPSET(&solv->dupmap, p);
-  FOR_PROVIDES(pi, pip, s->name)
-    {
-      ps = pool->solvables + pi;
-      if (ps->name != s->name)
-       continue;
-      MAPSET(&solv->dupinvolvedmap, pi);
-      if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
-       {
-         Id *opp, pi2;
-         for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
-           if (pool->solvables[pi2].repo != installed)
-             MAPSET(&solv->dupinvolvedmap, pi2);
-       }
-      if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
-       {
-         if (!solv->bestupdatemap.size)
-           map_grow(&solv->bestupdatemap, installed->end - installed->start);
-         MAPSET(&solv->bestupdatemap, pi - installed->start);
-       }
-      if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
-       add_cleandeps_package(solv, pi);
-      if (!targeted && ps->repo != installed)
-       MAPSET(&solv->dupmap, pi);
-    }
-  if (s->repo == installed && solv->obsoletes && solv->obsoletes[p - installed->start])
-    {
-      Id *opp;
-      for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (pi = *opp++) != 0;)
-       {
-         ps = pool->solvables + pi;
-         if (ps->repo == installed)
-           continue;
-         MAPSET(&solv->dupinvolvedmap, pi);
-         if (!targeted)
-           MAPSET(&solv->dupmap, pi);
-       }
-    }
-  if (targeted && s->repo != installed && s->obsoletes)
-    {
-      /* XXX: check obsoletes/provides combination */
-      obsp = s->repo->idarraydata + s->obsoletes;
-      while ((obs = *obsp++) != 0)
-       {
-         FOR_PROVIDES(pi, pip, obs)
-           {
-             Solvable *ps = pool->solvables + pi;
-             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-               continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-               continue;
-             MAPSET(&solv->dupinvolvedmap, pi);
-             if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
-               {
-                 Id *opp, pi2;
-                 for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
-                   if (pool->solvables[pi2].repo != installed)
-                     MAPSET(&solv->dupinvolvedmap, pi2);
-               }
-             if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
-               {
-                 if (!solv->bestupdatemap.size)
-                   map_grow(&solv->bestupdatemap, installed->end - installed->start);
-                 MAPSET(&solv->bestupdatemap, pi - installed->start);
-               }
-             if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
-               add_cleandeps_package(solv, pi);
-           }
-       }
-    }
-}
-
-void
-solver_createdupmaps(Solver *solv)
-{
-  Queue *job = &solv->job;
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Id select, how, what, p, pp;
-  Solvable *s;
-  int i, targeted;
-
-  map_init(&solv->dupmap, pool->nsolvables);
-  map_init(&solv->dupinvolvedmap, pool->nsolvables);
-  for (i = 0; i < job->count; i += 2)
-    {
-      how = job->elements[i];
-      select = job->elements[i] & SOLVER_SELECTMASK;
-      what = job->elements[i + 1];
-      switch (how & SOLVER_JOBMASK)
-       {
-       case SOLVER_DISTUPGRADE:
-         if (select == SOLVER_SOLVABLE_REPO)
-           {
-             Repo *repo;
-             if (what <= 0 || what > pool->nrepos)
-               break;
-             repo = pool_id2repo(pool, what);
-             if (!repo)
-               break;
-             if (repo != installed && !(how & SOLVER_TARGETED) && solv->noautotarget)
-               break;
-             targeted = repo != installed || (how & SOLVER_TARGETED) != 0;
-             FOR_REPO_SOLVABLES(repo, p, s)
-               {
-                 if (repo != installed && !pool_installable(pool, s))
-                   continue;
-                 solver_addtodupmaps(solv, p, how, targeted);
-               }
-           }
-         else if (select == SOLVER_SOLVABLE_ALL)
-           {
-             FOR_POOL_SOLVABLES(p)
-               {
-                 MAPSET(&solv->dupinvolvedmap, p);
-                 if (installed && pool->solvables[p].repo != installed)
-                   MAPSET(&solv->dupmap, p);
-               }
-           }
-         else
-           {
-             targeted = how & SOLVER_TARGETED ? 1 : 0;
-             if (installed && !targeted && !solv->noautotarget)
-               {
-                 FOR_JOB_SELECT(p, pp, select, what)
-                   if (pool->solvables[p].repo == installed)
-                     break;
-                 targeted = p == 0;
-               }
-             else if (!installed && !solv->noautotarget)
-               targeted = 1;
-             FOR_JOB_SELECT(p, pp, select, what)
-               {
-                 Solvable *s = pool->solvables + p;
-                 if (!s->repo)
-                   continue;
-                 if (s->repo != installed && !targeted)
-                   continue;
-                 if (s->repo != installed && !pool_installable(pool, s))
-                   continue;
-                 solver_addtodupmaps(solv, p, how, targeted);
-               }
-           }
-         break;
-       default:
-         break;
-       }
-    }
-  MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
-}
-
-void
-solver_freedupmaps(Solver *solv)
-{
-  map_free(&solv->dupmap);
-  /* we no longer free solv->dupinvolvedmap as we need it in
-   * policy's priority pruning code. sigh. */
-}
-
-void
-solver_addduprules(Solver *solv, Map *addedmap)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Id p, pp;
-  Solvable *s, *ps;
-  int first, i;
-  Rule *r;
-
-  solv->duprules = solv->nrules;
-  for (i = 1; i < pool->nsolvables; i++)
-    {
-      if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
-       continue;
-      s = pool->solvables + i;
-      first = i;
-      FOR_PROVIDES(p, pp, s->name)
-       {
-         ps = pool->solvables + p;
-         if (ps->name != s->name || !MAPTST(addedmap, p))
-           continue;
-         if (p == i)
-           first = 0;
-         if (first)
-           break;
-         if (!MAPTST(&solv->dupinvolvedmap, p))
-           continue;
-         if (installed && ps->repo == installed)
-           {
-             if (!solv->updatemap.size)
-               map_grow(&solv->updatemap, installed->end - installed->start);
-             MAPSET(&solv->updatemap, p - installed->start);
-             if (!MAPTST(&solv->dupmap, p))
-               {
-                 Id ip, ipp;
-                 /* is installed identical to a good one? */
-                 FOR_PROVIDES(ip, ipp, ps->name)
-                   {
-                     Solvable *is = pool->solvables + ip;
-                     if (!MAPTST(&solv->dupmap, ip))
-                       continue;
-                     if (is->evr == ps->evr && solvable_identical(ps, is))
-                       break;
-                   }
-                 if (ip)
-                   {
-                     /* ok, found a good one. we may keep this package. */
-                     MAPSET(&solv->dupmap, p);         /* for best rules processing */
-                     continue;
-                   }
-                 r = solv->rules + solv->updaterules + (p - installed->start);
-                 if (!r->p)
-                     r = solv->rules + solv->featurerules + (p - installed->start);
-                 if (r->p && solv->specialupdaters && solv->specialupdaters[p - installed->start])
-                   {
-                     /* this is a multiversion orphan, we're good if an update is installed */
-                     solver_addrule(solv, -p, 0, solv->specialupdaters[p - installed->start]);
-                     continue;
-                   }
-                 solver_addrule(solv, -p, 0, 0);       /* no match, sorry */
-               }
-           }
-         else if (!MAPTST(&solv->dupmap, p))
-           solver_addrule(solv, -p, 0, 0);
-       }
-    }
-  solv->duprules_end = solv->nrules;
-}
-
-
-static inline void
-disableduprule(Solver *solv, Id name)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  int i;
-  for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
-    {
-      if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
-       solver_disablerule(solv, r);
-    }
-}
-
-static inline void
-reenableduprule(Solver *solv, Id name)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  int i;
-  for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
-    {
-      if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
-       {
-         solver_enablerule(solv, r);
-         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
-             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
-           }
-       }
-    }
-}
-
-
-/***********************************************************************
- ***
- ***  Policy rule disabling/reenabling
- ***
- ***  Disable all policy rules that conflict with our jobs. If a job
- ***  gets disabled later on, reenable the involved policy rules again.
- ***
- ***/
-
-#define DISABLE_UPDATE 1
-#define DISABLE_INFARCH        2
-#define DISABLE_DUP    3
-
-/*
- * add all installed packages that package p obsoletes to Queue q.
- * Package p is not installed. Also, we know that if
- * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
- * Entries may get added multiple times.
- */
-static void
-add_obsoletes(Solver *solv, Id p, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Id p2, pp2;
-  Solvable *s = pool->solvables + p;
-  Id obs, *obsp;
-  Id lastp2 = 0;
-
-  if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
-    {
-      FOR_PROVIDES(p2, pp2, s->name)
-       {
-         Solvable *ps = pool->solvables + p2;
-         if (ps->repo != installed)
-           continue;
-         if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
-           continue;
-         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
-           continue;
-         queue_push(q, p2);
-         lastp2 = p2;
-       }
-    }
-  if (!s->obsoletes)
-    return;
-  obsp = s->repo->idarraydata + s->obsoletes;
-  while ((obs = *obsp++) != 0)
-    FOR_PROVIDES(p2, pp2, obs)
-      {
-       Solvable *ps = pool->solvables + p2;
-       if (ps->repo != installed)
-         continue;
-       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-         continue;
-       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-         continue;
-       if (p2 == lastp2)
-         continue;
-       queue_push(q, p2);
-       lastp2 = p2;
-      }
-}
-
-/*
- * Call add_obsoletes and intersect the result with the
- * elements in Queue q starting at qstart.
- * Assumes that it's the first call if qstart == q->count.
- * May use auxillary map m for the intersection process, all
- * elements of q starting at qstart must have their bit cleared.
- * (This is also true after the function returns.)
- */
-static void
-intersect_obsoletes(Solver *solv, Id p, Queue *q, int qstart, Map *m)
-{
-  int i, j;
-  int qcount = q->count;
-
-  add_obsoletes(solv, p, q);
-  if (qcount == qstart)
-    return;    /* first call */
-  if (qcount == q->count)
-    j = qstart;        
-  else if (qcount == qstart + 1)
-    {
-      /* easy if there's just one element */
-      j = qstart;
-      for (i = qcount; i < q->count; i++)
-       if (q->elements[i] == q->elements[qstart])
-         {
-           j++;        /* keep the element */
-           break;
-         }
-    }
-  else if (!m->size && q->count - qstart <= 8)
-    {
-      /* faster than a map most of the time */
-      int k;
-      for (i = j = qstart; i < qcount; i++)
-       {
-         Id ip = q->elements[i];
-         for (k = qcount; k < q->count; k++)
-           if (q->elements[k] == ip)
-             {
-               q->elements[j++] = ip;
-               break;
-             }
-       }
-    }
-  else
-    {
-      /* for the really pathologic cases we use the map */
-      Repo *installed = solv->installed;
-      if (!m->size)
-       map_init(m, installed->end - installed->start);
-      for (i = qcount; i < q->count; i++)
-       MAPSET(m, q->elements[i] - installed->start);
-      for (i = j = qstart; i < qcount; i++)
-       if (MAPTST(m, q->elements[i] - installed->start))
-         {
-           MAPCLR(m, q->elements[i] - installed->start);
-           q->elements[j++] = q->elements[i];
-         }
-    }
-  queue_truncate(q, j);
-}
-
-static void
-jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Id select, p, pp;
-  Repo *installed;
-  Solvable *s;
-  int i, j, set, qstart;
-  Map omap;
-
-  installed = solv->installed;
-  select = how & SOLVER_SELECTMASK;
-  switch (how & SOLVER_JOBMASK)
-    {
-    case SOLVER_INSTALL:
-      set = how & SOLVER_SETMASK;
-      if (!(set & SOLVER_NOAUTOSET))
-       {
-         /* automatically add set bits by analysing the job */
-         if (select == SOLVER_SOLVABLE_NAME)
-           set |= SOLVER_SETNAME;
-         if (select == SOLVER_SOLVABLE)
-           set |= SOLVER_SETNAME | SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
-         else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
-           {
-             Reldep *rd = GETRELDEP(pool, what);
-             if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
-               {
-                 if (pool->disttype != DISTTYPE_DEB)
-                   {
-                     const char *rel = strrchr(pool_id2str(pool, rd->evr), '-');
-                     set |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
-                   }
-                 else
-                   set |= SOLVER_SETEVR;
-               }
-             if (rd->flags <= 7 && ISRELDEP(rd->name))
-               rd = GETRELDEP(pool, rd->name);
-             if (rd->flags == REL_ARCH)
-               set |= SOLVER_SETARCH;
-           }
-       }
-      else
-       set &= ~SOLVER_NOAUTOSET;
-      if (!set)
-       return;
-      if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
-       {
-         if (select == SOLVER_SOLVABLE)
-           queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
-         else
-           {
-             int qcnt = q->count;
-             /* does not work for SOLVER_SOLVABLE_ALL and SOLVER_SOLVABLE_REPO, but
-                they are not useful for SOLVER_INSTALL jobs anyway */
-             FOR_JOB_SELECT(p, pp, select, what)
-               {
-                 s = pool->solvables + p;
-                 /* unify names */
-                 for (i = qcnt; i < q->count; i += 2)
-                   if (q->elements[i + 1] == s->name)
-                     break;
-                 if (i < q->count)
-                   continue;
-                 queue_push2(q, DISABLE_INFARCH, s->name);
-               }
-           }
-       }
-      if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
-       {
-         if (select == SOLVER_SOLVABLE)
-           queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
-         else
-           {
-             int qcnt = q->count;
-             FOR_JOB_SELECT(p, pp, select, what)
-               {
-                 s = pool->solvables + p;
-                 /* unify names */
-                 for (i = qcnt; i < q->count; i += 2)
-                   if (q->elements[i + 1] == s->name)
-                     break;
-                 if (i < q->count)
-                   continue;
-                 queue_push2(q, DISABLE_DUP, s->name);
-               }
-           }
-       }
-      if (!installed || installed->end == installed->start)
-       return;
-      /* now the hard part: disable some update rules */
-
-      /* first check if we have multiversion or installed packages in the job */
-      i = j = 0;
-      FOR_JOB_SELECT(p, pp, select, what)
-       {
-         if (pool->solvables[p].repo == installed)
-           j = p;
-         else if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes)
-           return;
-         i++;
-       }
-      if (j)   /* have installed packages */
-       {
-         /* this is for dupmap_all jobs, it can go away if we create
-          * duprules for them */
-         if (i == 1 && (set & SOLVER_SETREPO) != 0)
-           queue_push2(q, DISABLE_UPDATE, j);
-         return;
-       }
-
-      omap.size = 0;
-      qstart = q->count;
-      FOR_JOB_SELECT(p, pp, select, what)
-       {
-         intersect_obsoletes(solv, p, q, qstart, &omap);
-         if (q->count == qstart)
-           break;
-       }
-      if (omap.size)
-        map_free(&omap);
-
-      if (qstart == q->count)
-       return;         /* nothing to prune */
-
-      /* convert result to (DISABLE_UPDATE, p) pairs */
-      i = q->count;
-      for (j = qstart; j < i; j++)
-       queue_push(q, q->elements[j]);
-      for (j = qstart; j < q->count; j += 2)
-       {
-         q->elements[j] = DISABLE_UPDATE;
-         q->elements[j + 1] = q->elements[i++];
-       }
-
-      /* now that we know which installed packages are obsoleted check each of them */
-      if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
-       return;         /* all is set, nothing to do */
-
-      for (i = j = qstart; i < q->count; i += 2)
-       {
-         Solvable *is = pool->solvables + q->elements[i + 1];
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             int illegal = 0;
-             s = pool->solvables + p;
-             if ((set & SOLVER_SETEVR) != 0)
-               illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
-             if ((set & SOLVER_SETNAME) != 0)
-               illegal |= POLICY_ILLEGAL_NAMECHANGE;   /* ignore */
-             if ((set & SOLVER_SETARCH) != 0)
-               illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
-             if ((set & SOLVER_SETVENDOR) != 0)
-               illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
-             illegal = policy_is_illegal(solv, is, s, illegal);
-             if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
-               {
-                 /* it's ok if the EV is different */
-                 if (pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
-                   illegal = 0;
-               }
-             if (illegal)
-               break;
-           }
-         if (!p)
-           {   
-             /* no package conflicts with the update rule */
-             /* thus keep the DISABLE_UPDATE */
-             q->elements[j + 1] = q->elements[i + 1];
-             j += 2;
-           }
-       }
-      queue_truncate(q, j);
-      return;
-
-    case SOLVER_ERASE:
-      if (!installed)
-       break;
-      if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-       FOR_REPO_SOLVABLES(installed, p, s)
-         queue_push2(q, DISABLE_UPDATE, p);
-      FOR_JOB_SELECT(p, pp, select, what)
-       if (pool->solvables[p].repo == installed)
-         {
-           queue_push2(q, DISABLE_UPDATE, p);
-#ifdef ENABLE_LINKED_PKGS
-           if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
-             queue_push2(q, DISABLE_UPDATE, solv->instbuddy[p - installed->start]);
-#endif
-         }
-      return;
-    default:
-      return;
-    }
-}
-
-/* disable all policy rules that are in conflict with our job list */
-void
-solver_disablepolicyrules(Solver *solv)
-{
-  Queue *job = &solv->job;
-  int i, j;
-  Queue allq;
-  Rule *r;
-  Id lastjob = -1;
-  Id allqbuf[128];
-
-  queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
-
-  for (i = solv->jobrules; i < solv->jobrules_end; i++)
-    {
-      r = solv->rules + i;
-      if (r->d < 0)    /* disabled? */
-       continue;
-      j = solv->ruletojob.elements[i - solv->jobrules];
-      if (j == lastjob)
-       continue;
-      lastjob = j;
-      jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
-    }
-  if (solv->cleandepsmap.size)
-    {
-      solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
-      for (i = solv->installed->start; i < solv->installed->end; i++)
-       if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
-         queue_push2(&allq, DISABLE_UPDATE, i);
-    }
-  MAPZERO(&solv->noupdate);
-  for (i = 0; i < allq.count; i += 2)
-    {
-      Id type = allq.elements[i], arg = allq.elements[i + 1];
-      switch(type)
-       {
-       case DISABLE_UPDATE:
-         disableupdaterule(solv, arg);
-         break;
-       case DISABLE_INFARCH:
-         disableinfarchrule(solv, arg);
-         break;
-       case DISABLE_DUP:
-         disableduprule(solv, arg);
-         break;
-       default:
-         break;
-       }
-    }
-  queue_free(&allq);
-}
-
-/* we just disabled job #jobidx, now reenable all policy rules that were
- * disabled because of this job */
-void
-solver_reenablepolicyrules(Solver *solv, int jobidx)
-{
-  Queue *job = &solv->job;
-  int i, j, k, ai;
-  Queue q, allq;
-  Rule *r;
-  Id lastjob = -1;
-  Id qbuf[32], allqbuf[32];
-
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  jobtodisablelist(solv, job->elements[jobidx - 1], job->elements[jobidx], &q);
-  if (!q.count)
-    {
-      queue_free(&q);
-      return;
-    }
-  /* now remove everything from q that is disabled by other jobs */
-
-  /* first remove cleandeps packages, they count as DISABLE_UPDATE */
-  if (solv->cleandepsmap.size)
-    {
-      solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
-      for (j = k = 0; j < q.count; j += 2)
-       {
-         if (q.elements[j] == DISABLE_UPDATE)
-           {
-             Id p = q.elements[j + 1];
-             if (p >= solv->installed->start && p < solv->installed->end && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
-               continue;       /* remove element from q */
-           }
-         q.elements[k++] = q.elements[j];
-         q.elements[k++] = q.elements[j + 1];
-       }
-      q.count = k;
-      if (!q.count)
-       {
-         queue_free(&q);
-         return;
-       }
-    }
-
-  /* now go through the disable list of all other jobs */
-  queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
-  for (i = solv->jobrules; i < solv->jobrules_end; i++)
-    {
-      r = solv->rules + i;
-      if (r->d < 0)    /* disabled? */
-       continue;
-      j = solv->ruletojob.elements[i - solv->jobrules];
-      if (j == lastjob)
-       continue;
-      lastjob = j;
-      jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
-      if (!allq.count)
-       continue;
-      /* remove all elements in allq from q */
-      for (j = k = 0; j < q.count; j += 2)
-       {
-         Id type = q.elements[j], arg = q.elements[j + 1];
-         for (ai = 0; ai < allq.count; ai += 2)
-           if (allq.elements[ai] == type && allq.elements[ai + 1] == arg)
-             break;
-         if (ai < allq.count)
-           continue;   /* found it in allq, remove element from q */
-         q.elements[k++] = q.elements[j];
-         q.elements[k++] = q.elements[j + 1];
-       }
-      q.count = k;
-      if (!q.count)
-       {
-         queue_free(&q);
-         queue_free(&allq);
-         return;
-       }
-      queue_empty(&allq);
-    }
-  queue_free(&allq);
-
-  /* now re-enable anything that's left in q */
-  for (j = 0; j < q.count; j += 2)
-    {
-      Id type = q.elements[j], arg = q.elements[j + 1];
-      switch(type)
-       {
-       case DISABLE_UPDATE:
-         reenableupdaterule(solv, arg);
-         break;
-       case DISABLE_INFARCH:
-         reenableinfarchrule(solv, arg);
-         break;
-       case DISABLE_DUP:
-         reenableduprule(solv, arg);
-         break;
-       }
-    }
-  queue_free(&q);
-}
-
-/* we just removed a package from the cleandeps map, now reenable all policy rules that were
- * disabled because of this */
-void
-solver_reenablepolicyrules_cleandeps(Solver *solv, Id pkg)
-{
-  Queue *job = &solv->job;
-  int i, j;
-  Queue allq;
-  Rule *r;
-  Id lastjob = -1;
-  Id allqbuf[128];
-
-  queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
-  for (i = solv->jobrules; i < solv->jobrules_end; i++)
-    {
-      r = solv->rules + i;
-      if (r->d < 0)    /* disabled? */
-       continue;
-      j = solv->ruletojob.elements[i - solv->jobrules];
-      if (j == lastjob)
-       continue;
-      lastjob = j;
-      jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
-    }
-  for (i = 0; i < allq.count; i += 2)
-    if (allq.elements[i] == DISABLE_UPDATE && allq.elements[i + 1] == pkg)
-      break;
-  if (i == allq.count)
-    reenableupdaterule(solv, pkg);
-  queue_free(&allq);
-}
-
-
-/***********************************************************************
- ***
- ***  Rule info part, tell the user what the rule is about.
- ***
- ***/
-
-static void
-addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-
-  if (d)
-    {
-      assert(!p2 && d > 0);
-      if (!pool->whatprovidesdata[d])
-       d = 0;
-      else if (!pool->whatprovidesdata[d + 1])
-       {
-         p2 = pool->whatprovidesdata[d];
-         d = 0;
-       }
-    }
-
-  /* check if this creates the rule we're searching for */
-  r = solv->rules + solv->ruleinfoq->elements[0];
-  if (d)
-    {
-      /* three or more literals */
-      Id od = r->d < 0 ? -r->d - 1 : r->d;
-      if (p != r->p && !od)
-       return;
-      if (d != od)
-       {
-         Id *dp = pool->whatprovidesdata + d;
-         Id *odp = pool->whatprovidesdata + od;
-         while (*dp)
-           if (*dp++ != *odp++)
-             return;
-         if (*odp)
-           return;
-       }
-      if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS)
-       p2 = pool->whatprovidesdata[d];
-    }
-  else
-    {
-      /* one or two literals */
-      Id op = p, op2 = p2;
-      if (op2 && op > op2)     /* normalize */
-       {
-         Id o = op;
-         op = op2;
-         op2 = o;
-       }
-      if (r->p != op || r->w2 != op2 || (r->d && r->d != -1))
-       return;
-      if (type == SOLVER_RULE_PKG_CONFLICTS && !p2)
-       p2 = -SYSTEMSOLVABLE;
-      if (type == SOLVER_RULE_PKG_SAME_NAME)
-       {
-         p = op;       /* we normalize same name order */
-         p2 = op2;
-       }
-    }
-  /* yep, rule matches. record info */
-  queue_push(solv->ruleinfoq, type);
-  queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
-  queue_push(solv->ruleinfoq, p2 < 0 ? -p2 : 0);
-  queue_push(solv->ruleinfoq, dep);
-}
-
-static int
-solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap, *b = bp;
-  int r;
-
-  r = a[0] - b[0];
-  if (r)
-    return r;
-  r = a[1] - b[1];
-  if (r)
-    return r;
-  r = a[2] - b[2];
-  if (r)
-    return r;
-  r = a[3] - b[3];
-  if (r)
-    return r;
-  return 0;
-}
-
-static void
-getpkgruleinfos(Solver *solv, Rule *r, Queue *rq)
-{
-  Pool *pool = solv->pool;
-  Id l, pp;
-  if (r->p >= 0)
-    return;
-  queue_push(rq, r - solv->rules);     /* push the rule we're interested in */
-  solv->ruleinfoq = rq;
-  FOR_RULELITERALS(l, pp, r)
-    {
-      if (l >= 0)
-       break;
-      solver_addpkgrulesforsolvable(solv, pool->solvables - l, 0);
-    }
-#ifdef ENABLE_LINKED_PKGS
-  FOR_RULELITERALS(l, pp, r)
-    {
-      if (l < 0)
-       {
-         if (l == r->p)
-           continue;
-         break;
-       }
-      if (!strchr(pool_id2str(pool, pool->solvables[l].name), ':') || !has_package_link(pool, pool->solvables + l))
-       break;
-      add_package_link(solv, pool->solvables + l, 0, 0);
-    }
-#endif
-  solv->ruleinfoq = 0;
-  queue_shift(rq);
-}
-
-int
-solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
-{
-  Rule *r = solv->rules + rid;
-  int i, j;
-
-  queue_empty(rq);
-  if (rid <= 0 || rid >= solv->pkgrules_end)
-    {
-      Id type, from, to, dep;
-      type = solver_ruleinfo(solv, rid, &from, &to, &dep);
-      queue_push(rq, type);
-      queue_push(rq, from);
-      queue_push(rq, to);
-      queue_push(rq, dep);
-      return 1;
-    }
-  getpkgruleinfos(solv, r, rq);
-  /* now sort & unify em */
-  if (!rq->count)
-    return 0;
-  solv_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
-  /* throw out identical entries */
-  for (i = j = 0; i < rq->count; i += 4)
-    {
-      if (j)
-       {
-         if (rq->elements[i] == rq->elements[j - 4] &&
-             rq->elements[i + 1] == rq->elements[j - 3] &&
-             rq->elements[i + 2] == rq->elements[j - 2] &&
-             rq->elements[i + 3] == rq->elements[j - 1])
-           continue;
-       }
-      rq->elements[j++] = rq->elements[i];
-      rq->elements[j++] = rq->elements[i + 1];
-      rq->elements[j++] = rq->elements[i + 2];
-      rq->elements[j++] = rq->elements[i + 3];
-    }
-  rq->count = j;
-  return j / 4;
-}
-
-SolverRuleinfo
-solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
-{
-  Pool *pool = solv->pool;
-  Rule *r = solv->rules + rid;
-  SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
-
-  if (fromp)
-    *fromp = 0;
-  if (top)
-    *top = 0;
-  if (depp)
-    *depp = 0;
-  if (rid > 0 && rid < solv->pkgrules_end)
-    {
-      Queue rq;
-      int i;
-
-      if (r->p >= 0)
-       return SOLVER_RULE_PKG;
-      if (fromp)
-       *fromp = -r->p;
-      queue_init(&rq);
-      getpkgruleinfos(solv, r, &rq);
-      type = SOLVER_RULE_PKG;
-      for (i = 0; i < rq.count; i += 4)
-       {
-         Id qt, qo, qp, qd;
-         qt = rq.elements[i];
-         qp = rq.elements[i + 1];
-         qo = rq.elements[i + 2];
-         qd = rq.elements[i + 3];
-         if (type == SOLVER_RULE_PKG || type > qt)
-           {
-             type = qt;
-             if (fromp)
-               *fromp = qp;
-             if (top)
-               *top = qo;
-             if (depp)
-               *depp = qd;
-           }
-       }
-      queue_free(&rq);
-      return type;
-    }
-  if (rid >= solv->jobrules && rid < solv->jobrules_end)
-    {
-      Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
-      if (fromp)
-       *fromp = jidx;
-      if (top)
-       *top = solv->job.elements[jidx];
-      if (depp)
-       *depp = solv->job.elements[jidx + 1];
-      if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
-       {
-         Id how = solv->job.elements[jidx];
-         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME))
-           return SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
-         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES))
-           return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
-         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME))
-           return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
-         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES))
-           return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
-         return SOLVER_RULE_JOB_UNSUPPORTED;
-       }
-      return SOLVER_RULE_JOB;
-    }
-  if (rid >= solv->updaterules && rid < solv->updaterules_end)
-    {
-      if (fromp)
-       *fromp = solv->installed->start + (rid - solv->updaterules);
-      return SOLVER_RULE_UPDATE;
-    }
-  if (rid >= solv->featurerules && rid < solv->featurerules_end)
-    {
-      if (fromp)
-       *fromp = solv->installed->start + (rid - solv->featurerules);
-      return SOLVER_RULE_FEATURE;
-    }
-  if (rid >= solv->duprules && rid < solv->duprules_end)
-    {
-      if (fromp)
-       *fromp = -r->p;
-      if (depp)
-       *depp = pool->solvables[-r->p].name;
-      return SOLVER_RULE_DISTUPGRADE;
-    }
-  if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
-    {
-      if (fromp)
-       *fromp = -r->p;
-      if (depp)
-       *depp = pool->solvables[-r->p].name;
-      return SOLVER_RULE_INFARCH;
-    }
-  if (rid >= solv->bestrules && rid < solv->bestrules_end)
-    {
-      if (fromp && solv->bestrules_pkg[rid - solv->bestrules] > 0)
-       *fromp = solv->bestrules_pkg[rid - solv->bestrules];
-      return SOLVER_RULE_BEST;
-    }
-  if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
-    {
-      if (fromp)
-       *fromp = -r->p;
-      if (top)
-       {
-         /* first solvable is enough, we just need it for the name */
-         if (!r->d || r->d == -1)
-           *top = r->w2;
-         else
-           *top = pool->whatprovidesdata[r->d < 0 ? -r->d : r->d];
-       }
-      if (depp)
-       *depp = solv->yumobsrules_info[rid - solv->yumobsrules];
-      return SOLVER_RULE_YUMOBS;
-    }
-  if (rid >= solv->choicerules && rid < solv->choicerules_end)
-    {
-      return SOLVER_RULE_CHOICE;
-    }
-  if (rid >= solv->learntrules)
-    {
-      return SOLVER_RULE_LEARNT;
-    }
-  return SOLVER_RULE_UNKNOWN;
-}
-
-SolverRuleinfo
-solver_ruleclass(Solver *solv, Id rid)
-{
-  if (rid <= 0)
-    return SOLVER_RULE_UNKNOWN;
-  if (rid > 0 && rid < solv->pkgrules_end)
-    return SOLVER_RULE_PKG;
-  if (rid >= solv->jobrules && rid < solv->jobrules_end)
-    return SOLVER_RULE_JOB;
-  if (rid >= solv->updaterules && rid < solv->updaterules_end)
-    return SOLVER_RULE_UPDATE;
-  if (rid >= solv->featurerules && rid < solv->featurerules_end)
-    return SOLVER_RULE_FEATURE;
-  if (rid >= solv->duprules && rid < solv->duprules_end)
-    return SOLVER_RULE_DISTUPGRADE;
-  if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
-    return SOLVER_RULE_INFARCH;
-  if (rid >= solv->bestrules && rid < solv->bestrules_end)
-    return SOLVER_RULE_BEST;
-  if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
-    return SOLVER_RULE_YUMOBS;
-  if (rid >= solv->choicerules && rid < solv->choicerules_end)
-    return SOLVER_RULE_CHOICE;
-  if (rid >= solv->learntrules && rid < solv->nrules)
-    return SOLVER_RULE_LEARNT;
-  return SOLVER_RULE_UNKNOWN;
-}
-
-void
-solver_ruleliterals(Solver *solv, Id rid, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  Rule *r;
-
-  queue_empty(q);
-  r = solv->rules + rid;
-  FOR_RULELITERALS(p, pp, r)
-    if (p != -SYSTEMSOLVABLE)
-      queue_push(q, p);
-  if (!q->count)
-    queue_push(q, -SYSTEMSOLVABLE);    /* hmm, better to return an empty result? */
-}
-
-int
-solver_rule2jobidx(Solver *solv, Id rid)
-{
-  if (rid < solv->jobrules || rid >= solv->jobrules_end)
-    return 0;
-  return solv->ruletojob.elements[rid - solv->jobrules] + 1;
-}
-
-/* job rule introspection */
-Id
-solver_rule2job(Solver *solv, Id rid, Id *whatp)
-{
-  int idx;
-  if (rid < solv->jobrules || rid >= solv->jobrules_end)
-    {
-      if (whatp)
-       *whatp = 0;
-      return 0;
-    }
-  idx = solv->ruletojob.elements[rid - solv->jobrules];
-  if (whatp)
-    *whatp = solv->job.elements[idx + 1];
-  return solv->job.elements[idx];
-}
-
-/* update/feature rule introspection */
-Id
-solver_rule2solvable(Solver *solv, Id rid)
-{
-  if (rid >= solv->updaterules && rid < solv->updaterules_end)
-    return rid - solv->updaterules;
-  if (rid >= solv->featurerules && rid < solv->featurerules_end)
-    return rid - solv->featurerules;
-  return 0;
-}
-
-Id
-solver_rule2pkgrule(Solver *solv, Id rid)
-{
-  if (rid >= solv->choicerules && rid < solv->choicerules_end)
-    return solv->choicerules_ref[rid - solv->choicerules];
-  return 0;
-}
-
-static void
-solver_rule2rules_rec(Solver *solv, Id rid, Queue *q, Map *seen)
-{
-  int i;
-  Id rid2;
-
-  if (seen)
-    MAPSET(seen, rid);
-  for (i = solv->learnt_why.elements[rid - solv->learntrules]; (rid2 = solv->learnt_pool.elements[i]) != 0; i++)
-    {
-      if (seen)
-       {
-         if (MAPTST(seen, rid2))
-           continue;
-         if (rid2 >= solv->learntrules)
-           solver_rule2rules_rec(solv, rid2, q, seen);
-         continue;
-       }
-      queue_push(q, rid2);
-    }
-}
-
-/* learnt rule introspection */
-void
-solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive)
-{
-  queue_empty(q);
-  if (rid < solv->learntrules || rid >= solv->nrules)
-    return;
-  if (recursive)
-    {
-      Map seen;
-      map_init(&seen, solv->nrules);
-      solver_rule2rules_rec(solv, rid, q, &seen);
-      map_free(&seen);
-    }
-  else
-    solver_rule2rules_rec(solv, rid, q, 0);
-}
-
-
-/* check if the newest versions of pi still provides the dependency we're looking for */
-static int
-solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Rule *ur;
-  Id p, pp;
-  int i;
-
-  if (!q->count || q->elements[0] != pi)
-    {
-      if (q->count)
-        queue_empty(q);
-      ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
-      if (!ur->p)
-        ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
-      if (!ur->p)
-       return 0;
-      queue_push2(q, pi, 0);
-      FOR_RULELITERALS(p, pp, ur)
-       if (p > 0)
-         queue_push(q, p);
-    }
-  if (q->count == 2)
-    return 1;
-  if (q->count == 3)
-    {
-      p = q->elements[2];
-      return MAPTST(m, p) ? 0 : 1;
-    }
-  if (!q->elements[1])
-    {
-      for (i = 2; i < q->count; i++)
-       if (!MAPTST(m, q->elements[i]))
-         break;
-      if (i == q->count)
-       return 0;       /* all provide it, no need to filter */
-      /* some don't provide it, have to filter */
-      queue_deleten(q, 0, 2);
-      policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
-      queue_unshift(q, 1);     /* filter mark */
-      queue_unshift(q, pi);
-    }
-  for (i = 2; i < q->count; i++)
-    if (MAPTST(m, q->elements[i]))
-      return 0;                /* at least one provides it */
-  return 1;    /* none of the new packages provided it */
-}
-
-static inline void
-queue_removeelement(Queue *q, Id el)
-{
-  int i, j;
-  for (i = 0; i < q->count; i++)
-    if (q->elements[i] == el)
-      break;
-  if (i < q->count)
-    {
-      for (j = i++; i < q->count; i++)
-       if (q->elements[i] != el)
-         q->elements[j++] = q->elements[i];
-      queue_truncate(q, j);
-    }
-}
-
-void
-solver_addchoicerules(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Map m, mneg;
-  Rule *r;
-  Queue q, qi, qcheck;
-  int i, j, rid, havechoice;
-  Id p, d, pp;
-  Id p2, pp2;
-  Solvable *s, *s2;
-  Id lastaddedp, lastaddedd;
-  int lastaddedcnt;
-  unsigned int now;
-
-  solv->choicerules = solv->nrules;
-  if (!pool->installed)
-    {
-      solv->choicerules_end = solv->nrules;
-      return;
-    }
-  now = solv_timems(0);
-  solv->choicerules_ref = solv_calloc(solv->pkgrules_end, sizeof(Id));
-  queue_init(&q);
-  queue_init(&qi);
-  queue_init(&qcheck);
-  map_init(&m, pool->nsolvables);
-  map_init(&mneg, pool->nsolvables);
-  /* set up negative assertion map from infarch and dup rules */
-  for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
-    if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
-      MAPSET(&mneg, -r->p);
-  for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
-    if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
-      MAPSET(&mneg, -r->p);
-  lastaddedp = 0;
-  lastaddedd = 0;
-  lastaddedcnt = 0;
-  for (rid = 1; rid < solv->pkgrules_end ; rid++)
-    {
-      r = solv->rules + rid;
-      if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 <= 0))
-       continue;       /* only look at requires rules */
-      /* solver_printrule(solv, SOLV_DEBUG_RESULT, r); */
-      queue_empty(&q);
-      queue_empty(&qi);
-      havechoice = 0;
-      FOR_RULELITERALS(p, pp, r)
-       {
-         if (p < 0)
-           continue;
-         s = pool->solvables + p;
-         if (!s->repo)
-           continue;
-         if (s->repo == pool->installed)
-           {
-             queue_push(&q, p);
-             continue;
-           }
-         /* check if this package is "blocked" by a installed package */
-         s2 = 0;
-         FOR_PROVIDES(p2, pp2, s->name)
-           {
-             s2 = pool->solvables + p2;
-             if (s2->repo != pool->installed)
-               continue;
-             if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
-               continue;
-             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
-               continue;
-             break;
-           }
-         if (p2)
-           {
-             /* found installed package p2 that we can update to p */
-             if (MAPTST(&mneg, p))
-               continue;
-             if (policy_is_illegal(solv, s2, s, 0))
-               continue;
-#if 0
-             if (solver_choicerulecheck(solv, p2, r, &m))
-               continue;
-             queue_push(&qi, p2);
-#else
-             queue_push2(&qi, p2, p);
-#endif
-             queue_push(&q, p);
-             continue;
-           }
-         if (s->obsoletes)
-           {
-             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-             s2 = 0;
-             while ((obs = *obsp++) != 0)
-               {
-                 FOR_PROVIDES(p2, pp2, obs)
-                   {
-                     s2 = pool->solvables + p2;
-                     if (s2->repo != pool->installed)
-                       continue;
-                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
-                       continue;
-                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
-                       continue;
-                     break;
-                   }
-                 if (p2)
-                   break;
-               }
-             if (obs)
-               {
-                 /* found installed package p2 that we can update to p */
-                 if (MAPTST(&mneg, p))
-                   continue;
-                 if (policy_is_illegal(solv, s2, s, 0))
-                   continue;
-#if 0
-                 if (solver_choicerulecheck(solv, p2, r, &m))
-                   continue;
-                 queue_push(&qi, p2);
-#else
-                 queue_push2(&qi, p2, p);
-#endif
-                 queue_push(&q, p);
-                 continue;
-               }
-           }
-         /* package p is independent of the installed ones */
-         havechoice = 1;
-       }
-      if (!havechoice || !q.count || !qi.count)
-       continue;       /* no choice */
-
-      FOR_RULELITERALS(p, pp, r)
-        if (p > 0)
-         MAPSET(&m, p);
-
-      /* do extra checking */
-      for (i = j = 0; i < qi.count; i += 2)
-       {
-         p2 = qi.elements[i];
-         if (!p2)
-           continue;
-         if (solver_choicerulecheck(solv, p2, r, &m, &qcheck))
-           {
-             /* oops, remove element p from q */
-             queue_removeelement(&q, qi.elements[i + 1]);
-             continue;
-           }
-         qi.elements[j++] = p2;
-       }
-      queue_truncate(&qi, j);
-
-      if (!q.count || !qi.count)
-       {
-         FOR_RULELITERALS(p, pp, r)
-           if (p > 0)
-             MAPCLR(&m, p);
-         continue;
-       }
-
-
-      /* now check the update rules of the installed package.
-       * if all packages of the update rules are contained in
-       * the dependency rules, there's no need to set up the choice rule */
-      for (i = 0; i < qi.count; i++)
-       {
-         Rule *ur;
-         if (!qi.elements[i])
-           continue;
-         ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
-         if (!ur->p)
-           ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
-         if (!ur->p)
-           continue;
-         FOR_RULELITERALS(p, pp, ur)
-           if (!MAPTST(&m, p))
-             break;
-         if (p)
-           break;
-         for (j = i + 1; j < qi.count; j++)
-           if (qi.elements[i] == qi.elements[j])
-             qi.elements[j] = 0;
-       }
-      /* empty map again */
-      FOR_RULELITERALS(p, pp, r)
-        if (p > 0)
-         MAPCLR(&m, p);
-      if (i == qi.count)
-       {
-#if 0
-         printf("skipping choice ");
-         solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
-#endif
-         continue;
-       }
-
-      /* don't add identical rules */
-      if (lastaddedp == r->p && lastaddedcnt == q.count)
-       {
-         for (i = 0; i < q.count; i++)
-           if (q.elements[i] != pool->whatprovidesdata[lastaddedd + i])
-             break;
-         if (i == q.count)
-           continue;   /* already added that one */
-       }
-      d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
-
-      lastaddedp = r->p;
-      lastaddedd = d;
-      lastaddedcnt = q.count;
-
-      solver_addrule(solv, r->p, 0, d);
-      queue_push(&solv->weakruleq, solv->nrules - 1);
-      solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
-#if 0
-      printf("OLD ");
-      solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
-      printf("WEAK CHOICE ");
-      solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + solv->nrules - 1);
-#endif
-    }
-  queue_free(&q);
-  queue_free(&qi);
-  queue_free(&qcheck);
-  map_free(&m);
-  map_free(&mneg);
-  solv->choicerules_end = solv->nrules;
-  /* shrink choicerules_ref */
-  solv->choicerules_ref = solv_realloc2(solv->choicerules_ref, solv->choicerules_end - solv->choicerules, sizeof(Id));
-  POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now));
-}
-
-/* called when a choice rule is disabled by analyze_unsolvable. We also
- * have to disable all other choice rules so that the best packages get
- * picked */
-void
-solver_disablechoicerules(Solver *solv, Rule *r)
-{
-  Id rid, p, pp;
-  Pool *pool = solv->pool;
-  Map m;
-  Rule *or;
-
-  or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
-  map_init(&m, pool->nsolvables);
-  FOR_RULELITERALS(p, pp, or)
-    if (p > 0)
-      MAPSET(&m, p);
-  FOR_RULELITERALS(p, pp, r)
-    if (p > 0)
-      MAPCLR(&m, p);
-  for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
-    {
-      r = solv->rules + rid;
-      if (r->d < 0)
-       continue;
-      or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
-      FOR_RULELITERALS(p, pp, or)
-        if (p > 0 && MAPTST(&m, p))
-         break;
-      if (p)
-       solver_disablerule(solv, r);
-    }
-}
-
-static void
-prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
-{
-  int i, j;
-  Id p, *cp2;
-  for (i = j = 0; i < q->count; i++)
-    {
-      p = q->elements[i];
-      for (cp2 = cp; *cp2; cp2++)
-        if (*cp2 == p)
-          {
-            q->elements[j++] = p;
-            break;
-          }
-    }
-  queue_truncate(q, j);
-}
-
-static void
-prune_to_dup_packages(Solver *solv, Id p, Queue *q)
-{
-  int i, j;
-  for (i = j = 0; i < q->count; i++)
-    {
-      Id p = q->elements[i];
-      if (MAPTST(&solv->dupmap, p))
-       q->elements[j++] = p;
-    }
-  queue_truncate(q, j);
-}
-
-void
-solver_addbestrules(Solver *solv, int havebestinstalljobs)
-{
-  Pool *pool = solv->pool;
-  Id p;
-  Solvable *s;
-  Repo *installed = solv->installed;
-  Queue q, q2;
-  Rule *r;
-  Queue r2pkg;
-  int i, oldcnt;
-
-  solv->bestrules = solv->nrules;
-  if (!installed)
-    {
-      solv->bestrules_end = solv->nrules;
-      return;
-    }
-  queue_init(&q);
-  queue_init(&q2);
-  queue_init(&r2pkg);
-
-  if (havebestinstalljobs)
-    {
-      for (i = 0; i < solv->job.count; i += 2)
-       {
-         if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
-           {
-             int j;
-             Id p2, pp2;
-             for (j = 0; j < solv->ruletojob.count; j++)
-               if (solv->ruletojob.elements[j] == i)
-                 break;
-             if (j == solv->ruletojob.count)
-               continue;
-             r = solv->rules + solv->jobrules + j;
-             queue_empty(&q);
-             FOR_RULELITERALS(p2, pp2, r)
-               if (p2 > 0)
-                 queue_push(&q, p2);
-             if (!q.count)
-               continue;       /* orphaned */
-             /* select best packages, just look at prio and version */
-             oldcnt = q.count;
-             policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
-             if (q.count == oldcnt)
-               continue;       /* nothing filtered */
-             p2 = queue_shift(&q);
-             if (q.count < 2)
-               solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
-             else
-               solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
-             queue_push(&r2pkg, -(solv->jobrules + j));
-           }
-       }
-    }
-
-  if (solv->bestupdatemap_all || solv->bestupdatemap.size)
-    {
-      FOR_REPO_SOLVABLES(installed, p, s)
-       {
-         Id d, p2, pp2;
-         if (!solv->updatemap_all && (!solv->updatemap.size || !MAPTST(&solv->updatemap, p - installed->start)))
-           continue;
-         if (!solv->bestupdatemap_all && (!solv->bestupdatemap.size || !MAPTST(&solv->bestupdatemap, p - installed->start)))
-           continue;
-         queue_empty(&q);
-         if (solv->bestobeypolicy)
-           r = solv->rules + solv->updaterules + (p - installed->start);
-         else
-           {
-             r = solv->rules + solv->featurerules + (p - installed->start);
-             if (!r->p)        /* identical to update rule? */
-               r = solv->rules + solv->updaterules + (p - installed->start);
-           }
-         if (solv->specialupdaters && (d = solv->specialupdaters[p - installed->start]) != 0 && r == solv->rules + solv->updaterules + (p - installed->start))
-           {
-             /* need to check specialupdaters */
-             if (r->p == p)    /* be careful with the dup case */
-               queue_push(&q, p);
-             while ((p2 = pool->whatprovidesdata[d++]) != 0)
-               queue_push(&q, p2);
-           }
-         else
-           {
-             FOR_RULELITERALS(p2, pp2, r)
-               if (p2 > 0)
-                 queue_push(&q, p2);
-           }
-         if (solv->update_targets && solv->update_targets->elements[p - installed->start])
-           prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
-         if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
-           prune_to_dup_packages(solv, p, &q);
-         /* select best packages, just look at prio and version */
-         policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
-         if (!q.count)
-           continue;   /* orphaned */
-         if (solv->bestobeypolicy)
-           {
-             /* also filter the best of the feature rule packages and add them */
-             r = solv->rules + solv->featurerules + (p - installed->start);
-             if (r->p)
-               {
-                 int j;
-                 queue_empty(&q2);
-                 FOR_RULELITERALS(p2, pp2, r)
-                   if (p2 > 0)
-                     queue_push(&q2, p2);
-                 if (solv->update_targets && solv->update_targets->elements[p - installed->start])
-                   prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q2);
-                 if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
-                   prune_to_dup_packages(solv, p, &q2);
-                 policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
-                 for (j = 0; j < q2.count; j++)
-                   queue_pushunique(&q, q2.elements[j]);
-               }
-           }
-         p2 = queue_shift(&q);
-         if (q.count < 2)
-           solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
-         else
-           solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
-         queue_push(&r2pkg, p);
-       }
-    }
-  if (r2pkg.count)
-    solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id));
-  solv->bestrules_end = solv->nrules;
-  queue_free(&q);
-  queue_free(&q2);
-  queue_free(&r2pkg);
-}
-
-
-
-
-/* yumobs rule handling */
-
-static void
-find_obsolete_group(Solver *solv, Id obs, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Queue qn;
-  Id p2, pp2, op, *opp, opp2;
-  int i, j, qnc, ncnt;
-
-  queue_empty(q);
-  FOR_PROVIDES(p2, pp2, obs)
-    {
-      Solvable *s2 = pool->solvables + p2;
-      if (s2->repo != pool->installed)
-       continue;
-      if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
-       continue;
-      /* we obsolete installed package s2 with obs. now find all other packages that have the same dep  */
-      for (opp = solv->obsoletes_data + solv->obsoletes[p2 - solv->installed->start]; (op = *opp++) != 0;)
-       {
-         Solvable *os = pool->solvables + op;
-         Id obs2, *obsp2;
-         if (!os->obsoletes)
-           continue;
-         if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
-           continue;
-         obsp2 = os->repo->idarraydata + os->obsoletes; 
-         while ((obs2 = *obsp2++) != 0)
-           if (obs2 == obs)
-             break;
-         if (obs2)
-           queue_pushunique(q, op);
-       }
-      /* also search packages with the same name */
-      FOR_PROVIDES(op, opp2, s2->name)
-       {
-         Solvable *os = pool->solvables + op;
-         Id obs2, *obsp2;
-         if (os->name != s2->name)
-           continue;
-         if (!os->obsoletes)
-           continue;
-         if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
-           continue;
-         obsp2 = os->repo->idarraydata + os->obsoletes; 
-         while ((obs2 = *obsp2++) != 0)
-           if (obs2 == obs)
-             break;
-         if (obs2)
-           queue_pushunique(q, op);
-       }
-    }
-  /* find names so that we can build groups */
-  queue_init_clone(&qn, q);
-  prune_to_best_version(solv->pool, &qn);
-#if 0
-{
-  for (i = 0; i < qn.count; i++)
-    printf(" + %s\n", pool_solvid2str(pool, qn.elements[i]));
-}
-#endif
-  /* filter into name groups */
-  qnc = qn.count;
-  if (qnc == 1)
-    {
-      queue_free(&qn);
-      queue_empty(q);
-      return;
-    }
-  ncnt = 0;
-  for (i = 0; i < qnc; i++)
-    {
-      Id n = pool->solvables[qn.elements[i]].name;
-      int got = 0;
-      for (j = 0; j < q->count; j++)
-       {
-         Id p = q->elements[j];
-         if (pool->solvables[p].name == n)
-           {
-             queue_push(&qn, p);
-             got = 1;
-           }
-       }
-      if (got)
-       {
-         queue_push(&qn, 0);
-         ncnt++;
-       }
-    }
-  if (ncnt <= 1)
-    {
-      queue_empty(q);
-    }
-  else
-    {
-      queue_empty(q);
-      queue_insertn(q, 0, qn.count - qnc, qn.elements + qnc);
-    }
-  queue_free(&qn);
-}
-
-void
-solver_addyumobsrules(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Id p, op, *opp;
-  Solvable *s;
-  Queue qo, qq, yumobsinfoq;
-  int i, j, k;
-  unsigned int now;
-
-  solv->yumobsrules = solv->nrules;
-  if (!installed || !solv->obsoletes)
-    {
-      solv->yumobsrules_end = solv->nrules;
-      return;
-    }
-  now = solv_timems(0);
-  queue_init(&qo);
-  FOR_REPO_SOLVABLES(installed, p, s)
-    {
-      if (!solv->obsoletes[p - installed->start])
-       continue;
-#if 0
-printf("checking yumobs for %s\n", pool_solvable2str(pool, s));
-#endif
-      queue_empty(&qo);
-      for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (op = *opp++) != 0;)
-       {
-         Solvable *os = pool->solvables + op;
-          Id obs, *obsp = os->repo->idarraydata + os->obsoletes;
-         Id p2, pp2;
-         while ((obs = *obsp++) != 0)
-           {
-             FOR_PROVIDES(p2, pp2, obs)
-               {
-                 Solvable *s2 = pool->solvables + p2;
-                 if (s2->repo != installed)
-                   continue;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
-                   continue;
-                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
-                   continue;
-                 queue_pushunique(&qo, obs);
-                 break;
-               }
-           }
-       }
-    }
-  if (!qo.count)
-    {
-      queue_free(&qo);
-      return;
-    }
-  queue_init(&yumobsinfoq);
-  queue_init(&qq);
-  for (i = 0; i < qo.count; i++)
-    {
-      int group, groupk, groupstart;
-      queue_empty(&qq);
-#if 0
-printf("investigating %s\n", pool_dep2str(pool, qo.elements[i]));
-#endif
-      find_obsolete_group(solv, qo.elements[i], &qq);
-#if 0
-printf("result:\n");
-for (j = 0; j < qq.count; j++)
-  if (qq.elements[j] == 0)
-    printf("---\n");
-  else
-    printf("%s\n", pool_solvid2str(pool, qq.elements[j]));
-#endif
-  
-      if (!qq.count)
-       continue;
-      /* at least two goups, build rules */
-      group = 0;
-      for (j = 0; j < qq.count; j++)
-       {
-         p = qq.elements[j];
-         if (!p)
-           {
-             group++;
-             continue;
-           }
-         if (pool->solvables[p].repo == installed)
-           continue;
-         groupk = 0;
-         groupstart = 0;
-         for (k = 0; k < qq.count; k++)
-           {
-             Id pk = qq.elements[k];
-             if (pk)
-               continue;
-             if (group != groupk && k > groupstart)
-               {
-                 /* add the rule */
-                 if (k - groupstart == 1)
-                   solver_addrule(solv, -p, qq.elements[groupstart], 0);
-                 else
-                   solver_addrule(solv, -p, 0, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart));
-                 queue_push(&yumobsinfoq, qo.elements[i]);
-               }
-             groupstart = k + 1;
-             groupk++;
-           }
-       }
-    }
-  if (yumobsinfoq.count)
-    solv->yumobsrules_info = solv_memdup2(yumobsinfoq.elements, yumobsinfoq.count, sizeof(Id));
-  queue_free(&yumobsinfoq);
-  queue_free(&qq);
-  queue_free(&qo);
-  solv->yumobsrules_end = solv->nrules;
-  POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now));
-}
-
-#undef CLEANDEPSDEBUG
-
-/*
- * This functions collects all packages that are looked at
- * when a dependency is checked. We need it to "pin" installed
- * packages when removing a supplemented package in createcleandepsmap.
- * Here's an not uncommon example:
- *   A contains "Supplements: packageand(B, C)"
- *   B contains "Requires: A"
- * Now if we remove C, the supplements is no longer true,
- * thus we also remove A. Without the dep_pkgcheck function, we
- * would now also remove B, but this is wrong, as adding back
- * C doesn't make the supplements true again. Thus we "pin" B
- * when we remove A.
- * There's probably a better way to do this, but I haven't come
- * up with it yet ;)
- */
-static inline void
-dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags >= 8)
-       {
-         if (rd->flags == REL_AND)
-           {
-             dep_pkgcheck(solv, rd->name, m, q);
-             dep_pkgcheck(solv, rd->evr, m, q);
-             return;
-           }
-         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-           return;
-       }
-    }
-  FOR_PROVIDES(p, pp, dep)
-    if (!m || MAPTST(m, p))
-      queue_push(q, p);
-}
-
-static int
-check_xsupp(Solver *solv, Queue *depq, Id dep)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags >= 8)
-       {
-         if (rd->flags == REL_AND)
-           {
-             if (!check_xsupp(solv, depq, rd->name))
-               return 0;
-             return check_xsupp(solv, depq, rd->evr);
-           }
-         if (rd->flags == REL_OR)
-           {
-             if (check_xsupp(solv, depq, rd->name))
-               return 1;
-             return check_xsupp(solv, depq, rd->evr);
-           }
-         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-#if 0
-           return solver_splitprovides(solv, rd->evr);
-#else
-           return 0;
-#endif
-       }
-      if (depq && rd->flags == REL_NAMESPACE)
-       {
-         int i;
-         for (i = 0; i < depq->count; i++)
-           if (depq->elements[i] == dep || depq->elements[i] == rd->name)
-            return 1;
-       }
-    }
-  FOR_PROVIDES(p, pp, dep)
-    if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed)
-      return 1;
-  return 0;
-}
-
-static inline int
-queue_contains(Queue *q, Id id)
-{
-  int i;
-  for (i = 0; i < q->count; i++)
-    if (q->elements[i] == id)
-      return 1;
-  return 0;
-}
-
-#ifdef ENABLE_COMPLEX_DEPS
-static void
-complex_cleandeps_remove(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq)
-{
-  int i;
-  Queue dq;
-  Id p;
-
-  queue_init(&dq);
-  i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    {
-      queue_free(&dq);
-      return;
-    }
-  for (i = 0; i < dq.count; i++)
-    {
-      for (; (p = dq.elements[i]) != 0; i++)
-       {
-         if (p < 0)
-           {
-             if (!MAPTST(installedm, -p))
-               break;
-             continue;
-           }
-         if (p != SYSTEMSOLVABLE && MAPTST(im, p))
-           {
-#ifdef CLEANDEPSDEBUG
-             printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
-             queue_push(iq, p);
-           }
-       }
-      while (dq.elements[i])
-       i++;
-    }
-  queue_free(&dq);
-}
-
-static void
-complex_cleandeps_addback(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq, Map *userinstalled)
-{
-  int i, blk;
-  Queue dq;
-  Id p;
-
-  queue_init(&dq);
-  i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    {
-      queue_free(&dq);
-      return;
-    }
-  for (i = 0; i < dq.count; i++)
-    {
-      blk = i;
-      for (; (p = dq.elements[i]) != 0; i++)
-       {
-         if (p < 0)
-           {
-             if (!MAPTST(installedm, -p))
-               break;
-             continue;
-           }
-         if (MAPTST(im, p))
-           break;
-       }
-      if (!p)
-       {
-         for (i = blk; (p = dq.elements[i]) != 0; i++)
-           {
-             if (p < 0)
-               continue;
-             if (!MAPTST(installedm, p))
-               continue;
-             if (p == ip || MAPTST(userinstalled, p - pool->installed->start))
-               continue;
-#ifdef CLEANDEPSDEBUG
-             printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
-             MAPSET(im, p);
-             queue_push(iq, p);
-           }
-       }
-      while (dq.elements[i])
-       i++;
-    }
-  queue_free(&dq);
-}
-
-#endif
-
-/*
- * Find all installed packages that are no longer
- * needed regarding the current solver job.
- *
- * The algorithm is:
- * - remove pass: remove all packages that could have
- *   been dragged in by the obsoleted packages.
- *   i.e. if package A is obsolete and contains "Requires: B",
- *   also remove B, as installing A will have pulled in B.
- *   after this pass, we have a set of still installed packages
- *   with broken dependencies.
- * - add back pass:
- *   now add back all packages that the still installed packages
- *   require.
- *
- * The cleandeps packages are the packages removed in the first
- * pass and not added back in the second pass.
- *
- * If we search for unneeded packages (unneeded is true), we
- * simply remove all packages except the userinstalled ones in
- * the first pass.
- */
-static void
-solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Queue *job = &solv->job;
-  Map userinstalled;
-  Map im;
-  Map installedm;
-  Rule *r;
-  Id rid, how, what, select;
-  Id p, pp, ip, jp;
-  Id req, *reqp, sup, *supp;
-  Solvable *s;
-  Queue iq, iqcopy, xsuppq;
-  int i;
-
-  map_empty(cleandepsmap);
-  if (!installed || installed->end == installed->start)
-    return;
-  map_init(&userinstalled, installed->end - installed->start);
-  map_init(&im, pool->nsolvables);
-  map_init(&installedm, pool->nsolvables);
-  queue_init(&iq);
-  queue_init(&xsuppq);
-
-  for (i = 0; i < job->count; i += 2)
-    {
-      how = job->elements[i];
-      if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
-       {
-         what = job->elements[i + 1];
-         select = how & SOLVER_SELECTMASK;
-         if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-           FOR_REPO_SOLVABLES(installed, p, s)
-             MAPSET(&userinstalled, p - installed->start);
-         FOR_JOB_SELECT(p, pp, select, what)
-           if (pool->solvables[p].repo == installed)
-             MAPSET(&userinstalled, p - installed->start);
-       }
-      if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES))
-       {
-         what = job->elements[i + 1];
-         if (ISRELDEP(what))
-           {
-             Reldep *rd = GETRELDEP(pool, what);
-             if (rd->flags != REL_NAMESPACE)
-               continue;
-             if (rd->evr == 0)
-               {
-                 queue_pushunique(&iq, rd->name);
-                 continue;
-               }
-             FOR_PROVIDES(p, pp, what)
-               if (p)
-                 break;
-             if (p)
-               continue;
-             queue_pushunique(&iq, what);
-           }
-       }
-    }
-
-  /* have special namespace cleandeps erases */
-  if (iq.count)
-    {
-      for (ip = installed->start; ip < installed->end; ip++)
-       {
-         s = pool->solvables + ip;
-         if (s->repo != installed)
-           continue;
-         if (!s->supplements)
-           continue;
-         supp = s->repo->idarraydata + s->supplements;
-         while ((sup = *supp++) != 0)
-           if (ISRELDEP(sup) && check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup))
-             {
-#ifdef CLEANDEPSDEBUG
-               printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip));
-#endif
-               queue_pushunique(&xsuppq, sup);
-             }
-       }
-      queue_empty(&iq);
-    }
-
-  /* also add visible patterns to userinstalled for openSUSE */
-  if (1)
-    {
-      Dataiterator di;
-      dataiterator_init(&di, pool, 0, 0, SOLVABLE_ISVISIBLE, 0, 0);
-      while (dataiterator_step(&di))
-       {
-         Id *dp;
-         if (di.solvid <= 0)
-           continue;
-         s = pool->solvables + di.solvid;
-         if (!s->repo || !s->requires)
-           continue;
-         if (s->repo != installed && !pool_installable(pool, s))
-           continue;
-         if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0)
-           continue;
-         dp = s->repo->idarraydata + s->requires;
-         for (dp = s->repo->idarraydata + s->requires; *dp; dp++)
-           FOR_PROVIDES(p, pp, *dp)
-             if (pool->solvables[p].repo == installed)
-               {
-                 if (strncmp(pool_id2str(pool, pool->solvables[p].name), "pattern", 7) != 0)
-                   continue;
-                 MAPSET(&userinstalled, p - installed->start);
-               }
-       }
-      dataiterator_free(&di);
-    }
-  if (1)
-    {
-      /* all products and their buddies are userinstalled */
-      for (p = installed->start; p < installed->end; p++)
-       {
-         Solvable *s = pool->solvables + p;
-         if (s->repo != installed)
-           continue;
-         if (!strncmp("product:", pool_id2str(pool, s->name), 8))
-           {
-             MAPSET(&userinstalled, p - installed->start);
-#ifdef ENABLE_LINKED_PKGS
-             if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
-               {
-                 Id buddy = solv->instbuddy[p - installed->start];
-                 if (buddy >= installed->start && buddy < installed->end)
-                   MAPSET(&userinstalled, buddy - installed->start);
-               }
-#endif
-           }
-       }
-    }
-
-  /* add all positive elements (e.g. locks) to "userinstalled" */
-  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
-    {
-      r = solv->rules + rid;
-      if (r->d < 0)
-       continue;
-      i = solv->ruletojob.elements[rid - solv->jobrules];
-      if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
-       continue;
-      FOR_RULELITERALS(p, jp, r)
-       if (p > 0 && pool->solvables[p].repo == installed)
-         MAPSET(&userinstalled, p - installed->start);
-    }
-
-  /* add all cleandeps candidates to iq */
-  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
-    {
-      r = solv->rules + rid;
-      if (r->d < 0)                            /* disabled? */
-       continue;
-      if (r->d == 0 && r->p < 0 && r->w2 == 0) /* negative assertion (erase job)? */
-       {
-         p = -r->p;
-         if (pool->solvables[p].repo != installed)
-           continue;
-         MAPCLR(&userinstalled, p - installed->start);
-         if (unneeded)
-           continue;
-         i = solv->ruletojob.elements[rid - solv->jobrules];
-         how = job->elements[i];
-         if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
-           queue_push(&iq, p);
-       }
-      else if (r->p > 0)                       /* install job */
-       {
-         if (unneeded)
-           continue;
-         i = solv->ruletojob.elements[rid - solv->jobrules];
-         if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
-           {
-             /* check if the literals all obsolete some installed package */
-             Map om;
-             int iqstart;
-
-             /* just one installed literal */
-             if (r->d == 0 && r->w2 == 0 && pool->solvables[r->p].repo == installed)
-               continue;
-             /* multiversion is bad */
-             if (solv->multiversion.size && !solv->keepexplicitobsoletes)
-               {
-                 FOR_RULELITERALS(p, jp, r)
-                   if (MAPTST(&solv->multiversion, p))
-                     break;
-                 if (p)
-                   continue;
-               }
-
-             om.size = 0;
-             iqstart = iq.count;
-             FOR_RULELITERALS(p, jp, r)
-               {
-                 if (p < 0)
-                   {
-                     queue_truncate(&iq, iqstart);     /* abort */
-                     break;
-                   }
-                 if (pool->solvables[p].repo == installed)
-                   {
-                     if (iq.count == iqstart)
-                       queue_push(&iq, p);
-                     else
-                       {
-                         for (i = iqstart; i < iq.count; i++)
-                           if (iq.elements[i] == p)
-                             break;
-                         queue_truncate(&iq, iqstart);
-                         if (i < iq.count)
-                           queue_push(&iq, p);
-                       }
-                   }
-                 else
-                   intersect_obsoletes(solv, p, &iq, iqstart, &om);
-                 if (iq.count == iqstart)
-                   break;
-               }
-             if (om.size)
-               map_free(&om);
-           }
-       }
-    }
-  queue_init_clone(&iqcopy, &iq);
-
-  if (!unneeded)
-    {
-      if (solv->cleandeps_updatepkgs)
-       for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
-         queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]);
-    }
-
-  if (unneeded)
-    queue_empty(&iq);  /* just in case... */
-
-  /* clear userinstalled bit for the packages we really want to delete/update */
-  for (i = 0; i < iq.count; i++)
-    {
-      p = iq.elements[i];
-      if (pool->solvables[p].repo != installed)
-       continue;
-      MAPCLR(&userinstalled, p - installed->start);
-    }
-
-  for (p = installed->start; p < installed->end; p++)
-    {
-      if (pool->solvables[p].repo != installed)
-       continue;
-      MAPSET(&installedm, p);
-      if (unneeded && !MAPTST(&userinstalled, p - installed->start))
-       continue;
-      MAPSET(&im, p);
-    }
-  MAPSET(&installedm, SYSTEMSOLVABLE);
-  MAPSET(&im, SYSTEMSOLVABLE);
-
-#ifdef CLEANDEPSDEBUG
-  printf("REMOVE PASS\n");
-#endif
-
-  for (;;)
-    {
-      if (!iq.count)
-       {
-         if (unneeded)
-           break;
-         /* supplements pass */
-         for (ip = installed->start; ip < installed->end; ip++)
-           {
-             if (!MAPTST(&installedm, ip))
-               continue;
-             s = pool->solvables + ip;
-             if (!s->supplements)
-               continue;
-             if (!MAPTST(&im, ip))
-               continue;
-             if (MAPTST(&userinstalled, ip - installed->start))
-               continue;
-             supp = s->repo->idarraydata + s->supplements;
-             while ((sup = *supp++) != 0)
-               if (dep_possible(solv, sup, &im))
-                 break;
-             if (!sup)
-               {
-                 supp = s->repo->idarraydata + s->supplements;
-                 while ((sup = *supp++) != 0)
-                   if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
-                     {
-                       /* no longer supplemented, also erase */
-                       int iqcount = iq.count;
-                       /* pin packages, see comment above dep_pkgcheck */
-                       dep_pkgcheck(solv, sup, &im, &iq);
-                       for (i = iqcount; i < iq.count; i++)
-                         {
-                           Id pqp = iq.elements[i];
-                           if (pool->solvables[pqp].repo == installed)
-                             MAPSET(&userinstalled, pqp - installed->start);
-                         }
-                       queue_truncate(&iq, iqcount);
-#ifdef CLEANDEPSDEBUG
-                       printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup));
-#endif
-                       queue_push(&iq, ip);
-                     }
-               }
-           }
-         if (!iq.count)
-           break;      /* no supplementing package found, we're done */
-       }
-      ip = queue_shift(&iq);
-      s = pool->solvables + ip;
-      if (!MAPTST(&im, ip))
-       continue;
-      if (!MAPTST(&installedm, ip))
-       continue;
-      if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
-       continue;
-      MAPCLR(&im, ip);
-#ifdef CLEANDEPSDEBUG
-      printf("removing %s\n", pool_solvable2str(pool, s));
-#endif
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)
-           {
-             if (req == SOLVABLE_PREREQMARKER)
-               continue;
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, req))
-               {
-                 complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
-                 continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
-                   {
-#ifdef CLEANDEPSDEBUG
-                     printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-      if (s->recommends)
-       {
-         reqp = s->repo->idarraydata + s->recommends;
-         while ((req = *reqp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, req))
-               {
-                 complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
-                 continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
-                   {
-#ifdef CLEANDEPSDEBUG
-                     printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-    }
-
-  /* turn userinstalled into remove set for pruning */
-  map_empty(&userinstalled);
-  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
-    {
-      r = solv->rules + rid;
-      if (r->p >= 0 || r->d != 0 || r->w2 != 0)
-       continue;       /* disabled or not erase */
-      p = -r->p;
-      MAPCLR(&im, p);
-      if (pool->solvables[p].repo == installed)
-        MAPSET(&userinstalled, p - installed->start);
-    }
-  if (!unneeded && solv->cleandeps_updatepkgs)
-    {
-      for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
-       {
-         p = solv->cleandeps_updatepkgs->elements[i];
-         if (pool->solvables[p].repo == installed)
-           MAPSET(&userinstalled, p - installed->start);
-       }
-    }
-  MAPSET(&im, SYSTEMSOLVABLE); /* in case we cleared it above */
-  for (p = installed->start; p < installed->end; p++)
-    if (MAPTST(&im, p))
-      queue_push(&iq, p);
-  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
-    {
-      r = solv->rules + rid;
-      if (r->d < 0)
-       continue;
-      FOR_RULELITERALS(p, jp, r)
-       if (p > 0)
-          queue_push(&iq, p);
-    }
-  /* also put directly addressed packages on the install queue
-   * so we can mark patterns as installed */
-  for (i = 0; i < job->count; i += 2)
-    {
-      how = job->elements[i];
-      if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
-       {
-         what = job->elements[i + 1];
-         select = how & SOLVER_SELECTMASK;
-         if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
-            queue_push(&iq, what);
-       }
-    }
-
-#ifdef CLEANDEPSDEBUG
-  printf("ADDBACK PASS\n");
-#endif
-  for (;;)
-    {
-      if (!iq.count)
-       {
-         /* supplements pass */
-         for (ip = installed->start; ip < installed->end; ip++)
-           {
-             if (!MAPTST(&installedm, ip))
-               continue;
-             if (MAPTST(&userinstalled, ip - installed->start))
-               continue;
-             s = pool->solvables + ip;
-             if (!s->supplements)
-               continue;
-             if (MAPTST(&im, ip))
-               continue;
-             supp = s->repo->idarraydata + s->supplements;
-             while ((sup = *supp++) != 0)
-               if (dep_possible(solv, sup, &im))
-                 break;
-             if (sup)
-               {
-#ifdef CLEANDEPSDEBUG
-                 printf("%s supplemented\n", pool_solvid2str(pool, ip));
-#endif
-                 MAPSET(&im, ip);
-                 queue_push(&iq, ip);
-               }
-           }
-         if (!iq.count)
-           break;
-       }
-      ip = queue_shift(&iq);
-      s = pool->solvables + ip;
-#ifdef CLEANDEPSDEBUG
-      printf("adding back %s\n", pool_solvable2str(pool, s));
-#endif
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, req))
-               {
-                 complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
-                 continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, req)
-               if (MAPTST(&im, p))
-                 break;
-             if (p)
-               continue;
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (MAPTST(&installedm, p))
-                   {
-                     if (p == ip)
-                       continue;
-                     if (MAPTST(&userinstalled, p - installed->start))
-                       continue;
-#ifdef CLEANDEPSDEBUG
-                     printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
-                     MAPSET(&im, p);
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-      if (s->recommends)
-       {
-         reqp = s->repo->idarraydata + s->recommends;
-         while ((req = *reqp++) != 0)
-           {
-#ifdef ENABLE_COMPLEX_DEPS
-             if (pool_is_complex_dep(pool, req))
-               {
-                 complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
-                 continue;
-               }
-#endif
-             FOR_PROVIDES(p, pp, req)
-               if (MAPTST(&im, p))
-                 break;
-             if (p)
-               continue;
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (MAPTST(&installedm, p))
-                   {
-                     if (p == ip)
-                       continue;
-                     if (MAPTST(&userinstalled, p - installed->start))
-                       continue;
-#ifdef CLEANDEPSDEBUG
-                     printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
-#endif
-                     MAPSET(&im, p);
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-    }
-
-  queue_free(&iq);
-  /* make sure the updatepkgs and mistakes are not in the cleandeps map */
-  if (solv->cleandeps_updatepkgs)
-    for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
-      MAPSET(&im, solv->cleandeps_updatepkgs->elements[i]);
-  if (solv->cleandeps_mistakes)
-    for (i = 0; i < solv->cleandeps_mistakes->count; i++)
-      MAPSET(&im, solv->cleandeps_mistakes->elements[i]);
-  /* also remove original iq packages */
-  for (i = 0; i < iqcopy.count; i++)
-    MAPSET(&im, iqcopy.elements[i]);
-  queue_free(&iqcopy);
-  for (p = installed->start; p < installed->end; p++)
-    {
-      if (pool->solvables[p].repo != installed)
-       continue;
-      if (!MAPTST(&im, p))
-        MAPSET(cleandepsmap, p - installed->start);
-    }
-  map_free(&im);
-  map_free(&installedm);
-  map_free(&userinstalled);
-  queue_free(&xsuppq);
-#ifdef CLEANDEPSDEBUG
-  printf("=== final cleandeps map:\n");
-  for (p = installed->start; p < installed->end; p++)
-    if (MAPTST(cleandepsmap, p - installed->start))
-      printf("  - %s\n", pool_solvid2str(pool, p));
-#endif
-}
-
-
-struct trj_data {
-  Queue *edges;
-  Id *low;
-  Id idx;
-  Id nstack;
-  Id firstidx;
-};
-
-/* Tarjan's SCC algorithm, slightly modifed */
-static void
-trj_visit(struct trj_data *trj, Id node)
-{
-  Id *low = trj->low;
-  Queue *edges = trj->edges;
-  Id nnode, myidx, stackstart;
-  int i;
-
-  low[node] = myidx = trj->idx++;
-  low[(stackstart = trj->nstack++)] = node;
-  for (i = edges->elements[node]; (nnode = edges->elements[i]) != 0; i++)
-    {
-      Id l = low[nnode];
-      if (!l)
-       {
-         if (!edges->elements[edges->elements[nnode]])
-           {
-             trj->idx++;
-             low[nnode] = -1;
-             continue;
-           }
-         trj_visit(trj, nnode);
-         l = low[nnode];
-       }
-      if (l < 0)
-       continue;
-      if (l < trj->firstidx)
-       {
-         int k;
-         for (k = l; low[low[k]] == l; k++)
-           low[low[k]] = -1;
-       }
-      else if (l < low[node])
-       low[node] = l;
-    }
-  if (low[node] == myidx)
-    {
-      if (myidx != trj->firstidx)
-       myidx = -1;
-      for (i = stackstart; i < trj->nstack; i++)
-       low[low[i]] = myidx;
-      trj->nstack = stackstart;
-    }
-}
-
-#ifdef ENABLE_COMPLEX_DEPS
-static void
-complex_unneeded(Pool *pool, Id ip, Id req, Queue *edges, Map *cleandepsmap, Queue *unneededq)
-{
-  int i, j;
-  Queue dq;
-  Id p;
-
-  queue_init(&dq);
-  i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    {
-      queue_free(&dq);
-      return;
-    }
-  for (i = 0; i < dq.count; i++)
-    {
-      for (; (p = dq.elements[i]) != 0; i++)
-       {
-         if (p < 0)
-           {
-             if (pool->solvables[-p].repo != pool->installed)
-               break;
-             continue;
-           }
-         if (p == ip || pool->solvables[p].repo != pool->installed || !MAPTST(cleandepsmap, p - pool->installed->start))
-           continue;
-         for (j = 0; j < unneededq->count; j++)
-           if (p == unneededq->elements[j])
-             {
-               if (edges->elements[edges->count - 1] != j + 1)
-                 queue_push(edges, j + 1);
-               break;
-             }
-       }
-      while (dq.elements[i])
-       i++;
-    }
-  queue_free(&dq);
-}
-#endif
-
-void
-solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered)
-{
-  Repo *installed = solv->installed;
-  int i;
-  Map cleandepsmap;
-
-  queue_empty(unneededq);
-  if (!installed || installed->end == installed->start)
-    return;
-
-  map_init(&cleandepsmap, installed->end - installed->start);
-  solver_createcleandepsmap(solv, &cleandepsmap, 1);
-  for (i = installed->start; i < installed->end; i++)
-    if (MAPTST(&cleandepsmap, i - installed->start))
-      queue_push(unneededq, i);
-
-  if (filtered && unneededq->count > 1)
-    {
-      Pool *pool = solv->pool;
-      Queue edges;
-      Id *nrequires;
-      Map installedm;
-      int j, pass, count = unneededq->count;
-      Id *low;
-
-      map_init(&installedm, pool->nsolvables);
-      for (i = installed->start; i < installed->end; i++)
-       if (pool->solvables[i].repo == installed)
-         MAPSET(&installedm, i);
-
-      nrequires = solv_calloc(count, sizeof(Id));
-      queue_init(&edges);
-      queue_prealloc(&edges, count * 4 + 10);  /* pre-size */
-
-      /*
-       * Go through the solvables in the nodes queue and create edges for
-       * all requires/recommends/supplements between the nodes.
-       * The edges are stored in the edges queue, we add 1 to the node
-       * index so that nodes in the edges queue are != 0 and we can
-       * terminate the edge list with 0.
-       * Thus for node element 5, the edges are stored starting at
-       * edges.elements[6] and are 0-terminated.
-       */
-      /* leave first element zero to make things easier */
-      /* also add trailing zero */
-      queue_insertn(&edges, 0, 1 + count + 1, 0);
-
-      /* first requires and recommends */
-      for (i = 0; i < count; i++)
-       {
-         Solvable *s = pool->solvables + unneededq->elements[i];
-         int oldcount = edges.count;
-         edges.elements[i + 1] = oldcount;
-         for (pass = 0; pass < 2; pass++)
-           {
-             unsigned int off = pass == 0 ? s->requires : s->recommends;
-             Id p, pp, dep, *dp;
-             if (off)
-               for (dp = s->repo->idarraydata + off; (dep = *dp) != 0; dp++)
-                 {
-#ifdef ENABLE_COMPLEX_DEPS
-                   if (pool_is_complex_dep(pool, dep))
-                     {
-                       complex_unneeded(pool, s - pool->solvables, dep, &edges, &cleandepsmap, unneededq);
-                       continue;
-                     }
-#endif
-                   FOR_PROVIDES(p, pp, dep)
-                     {
-                       Solvable *sp = pool->solvables + p;
-                       if (s == sp || sp->repo != installed || !MAPTST(&cleandepsmap, p - installed->start))
-                         continue;
-                       for (j = 0; j < count; j++)
-                         if (p == unneededq->elements[j])
-                           {
-                             if (edges.elements[edges.count - 1] != j + 1)
-                               queue_push(&edges, j + 1);
-                           }
-                     }
-                 }
-             if (pass == 0)
-               nrequires[i] = edges.count - oldcount;
-           }
-         queue_push(&edges, 0);
-       }
-#if 0
-      printf("requires + recommends\n");
-      for (i = 0; i < count; i++)
-       {
-         int j;
-         printf("  %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]);
-         for (j = edges.elements[i + 1]; edges.elements[j]; j++)
-           printf("    - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1]));
-       }
-#endif
-
-      /* then add supplements */
-      for (i = 0; i < count; i++)
-       {
-         Solvable *s = pool->solvables + unneededq->elements[i];
-         if (s->supplements)
-           {
-             Id *dp;
-             int k;
-             for (dp = s->repo->idarraydata + s->supplements; *dp; dp++)
-               if (dep_possible(solv, *dp, &installedm))
-                 {
-                   Queue iq;
-                   Id iqbuf[16];
-                   queue_init_buffer(&iq, iqbuf, sizeof(iqbuf)/sizeof(*iqbuf));
-                   dep_pkgcheck(solv, *dp, 0, &iq);
-                   for (k = 0; k < iq.count; k++)
-                     {
-                       Id p = iq.elements[k];
-                       Solvable *sp = pool->solvables + p;
-                       if (p == unneededq->elements[i] || sp->repo != installed || !MAPTST(&cleandepsmap, p - installed->start))
-                         continue;
-                       for (j = 0; j < count; j++)
-                         if (p == unneededq->elements[j])
-                           break;
-                       /* now add edge from j + 1 to i + 1 */
-                       queue_insert(&edges, edges.elements[j + 1] + nrequires[j], i + 1);
-                       /* addapt following edge pointers */
-                       for (j = j + 2; j < count + 1; j++)
-                         edges.elements[j]++;
-                     }
-                   queue_free(&iq);
-                 }
-           }
-       }
-#if 0
-      /* print result */
-      printf("+ supplements\n");
-      for (i = 0; i < count; i++)
-       {
-         int j;
-         printf("  %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]);
-         for (j = edges.elements[i + 1]; edges.elements[j]; j++)
-           printf("    - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1]));
-        }
-#endif
-      map_free(&installedm);
-
-      /* now run SCC algo two times, first with requires+recommends+supplements,
-       * then again without the requires. We run it the second time to get rid
-       * of packages that got dragged in via recommends/supplements */
-      /*
-       * low will contain the result of the SCC search.
-       * it must be of at least size 2 * (count + 1) and
-       * must be zero initialized.
-       * The layout is:
-       *    0  low low ... low stack stack ...stack 0
-       *            count              count
-       */
-      low = solv_calloc(count + 1, 2 * sizeof(Id));
-      for (pass = 0; pass < 2; pass++)
-       {
-         struct trj_data trj;
-         if (pass)
-           {
-             memset(low, 0, (count + 1) * (2 * sizeof(Id)));
-             for (i = 0; i < count; i++)
-               {
-                 edges.elements[i + 1] += nrequires[i];
-                 if (!unneededq->elements[i])
-                   low[i + 1] = -1;    /* ignore this node */
-               }
-           }
-         trj.edges = &edges;
-         trj.low = low;
-         trj.idx = count + 1;  /* stack starts here */
-         for (i = 1; i <= count; i++)
-           {
-             if (low[i])
-               continue;
-             if (edges.elements[edges.elements[i]])
-               {
-                 trj.firstidx = trj.nstack = trj.idx;
-                 trj_visit(&trj, i);
-               }
-             else
-               {
-                 Id myidx = trj.idx++;
-                 low[i] = myidx;
-                 low[myidx] = i;
-               }
-           }
-         /* prune packages */
-         for (i = 0; i < count; i++)
-           if (low[i + 1] <= 0)
-             unneededq->elements[i] = 0;
-       }
-      solv_free(low);
-      solv_free(nrequires);
-      queue_free(&edges);
-
-      /* finally remove all pruned entries from unneededq */
-      for (i = j = 0; i < count; i++)
-       if (unneededq->elements[i])
-         unneededq->elements[j++] = unneededq->elements[i];
-      queue_truncate(unneededq, j);
-    }
-  map_free(&cleandepsmap);
-}
-
-
-void
-solver_breakorphans(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  int i, rid;
-  Map m;
-
-  if (!installed || solv->droporphanedmap_all)
-    return;
-  solv->brokenorphanrules = solv_calloc(1, sizeof(Queue));
-  queue_init(solv->brokenorphanrules);
-  map_init(&m, installed->end - installed->start);
-  for (i = 0; i < solv->orphaned.count; i++)
-    {
-      Id p = solv->orphaned.elements[i];
-      if (pool->solvables[p].repo != installed)
-       continue;
-      if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - installed->start))
-       continue;
-      MAPSET(&m, p - installed->start);
-    }
-  for (rid = 1; rid < solv->pkgrules_end ; rid++)
-    {
-      Id p, *dp;
-      Rule *r = solv->rules + rid;
-      /* ignore non-deps and simple conflicts */
-      if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
-       continue;
-      p = -r->p;
-      if (p < installed->start || p >= installed->end || !MAPTST(&m, p - installed->start))
-       {
-         /* need to check other literals */
-         if (r->d == 0 || r->d == -1)
-           continue;
-         for (dp = pool->whatprovidesdata + (r->d < 0 ? -r->d - 1 : r->d); *dp < 0; dp++)
-           {
-             p = -*dp;
-             if (p >= installed->start && p < installed->end && MAPTST(&m, p - installed->start))
-               break;
-           }
-         if (*dp >= 0)
-           continue;
-       }
-      /* ok, disable this rule */
-      queue_push(solv->brokenorphanrules, rid);
-      if (r->d >= 0)
-       solver_disablerule(solv, r);
-    }
-  map_free(&m);
-  if (!solv->brokenorphanrules->count)
-    {
-      queue_free(solv->brokenorphanrules);
-      solv->brokenorphanrules = solv_free(solv->brokenorphanrules);
-    }
-}
-
-void
-solver_check_brokenorphanrules(Solver *solv, Queue *dq)
-{
-  Pool *pool = solv->pool;
-  int i;
-  Id l, pp;
-  
-  queue_empty(dq);
-  if (!solv->brokenorphanrules)
-    return;
-  for (i = 0; i < solv->brokenorphanrules->count; i++)
-    {
-      int rid = solv->brokenorphanrules->elements[i];
-      Rule *r = solv->rules + rid;
-      FOR_RULELITERALS(l, pp, r)
-       {
-         if (l < 0)
-           {
-             if (solv->decisionmap[-l] <= 0)
-               break;
-           }
-         else
-           {
-             if (solv->decisionmap[l] > 0 && pool->solvables[l].repo != solv->installed)
-               break;
-           }
-       }
-      if (l)
-       continue;
-      FOR_RULELITERALS(l, pp, r)
-        if (l > 0 && solv->decisionmap[l] == 0 && pool->solvables[l].repo != solv->installed)
-         queue_pushunique(dq, l);
-    }
-}
-
diff --git a/libsolv-0.6.15/src/rules.h b/libsolv-0.6.15/src/rules.h
deleted file mode 100644 (file)
index 606819b..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * rules.h
- *
- */
-
-#ifndef LIBSOLV_RULES_H
-#define LIBSOLV_RULES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* ----------------------------------------------
- * Rule
- *
- *   providerN(B) == Package Id of package providing tag B
- *   N = 1, 2, 3, in case of multiple providers
- *
- * A requires B : !A | provider1(B) | provider2(B)
- *
- * A conflicts B : (!A | !provider1(B)) & (!A | !provider2(B)) ...
- *
- * 'not' is encoded as a negative Id
- *
- * Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
- *
- * There are a lot of rules, so the struct is kept as small as
- * possible. Do not add new members unless there is no other way.
- */
-
-typedef struct _Rule {
-  Id p;                /* first literal in rule */
-  Id d;                /* Id offset into 'list of providers terminated by 0' as used by whatprovides; pool->whatprovides + d */
-               /* in case of binary rules, d == 0, w1 == p, w2 == other literal */
-               /* in case of disabled rules: ~d, aka -d - 1 */
-  Id w1, w2;   /* watches, literals not-yet-decided */
-               /* if !w2, assertion, not rule */
-  Id n1, n2;   /* next rules in linked list, corresponding to w1, w2 */
-} Rule;
-
-
-typedef enum {
-  SOLVER_RULE_UNKNOWN = 0,
-  SOLVER_RULE_PKG = 0x100,
-  SOLVER_RULE_PKG_NOT_INSTALLABLE,
-  SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP,
-  SOLVER_RULE_PKG_REQUIRES,
-  SOLVER_RULE_PKG_SELF_CONFLICT,
-  SOLVER_RULE_PKG_CONFLICTS,
-  SOLVER_RULE_PKG_SAME_NAME,
-  SOLVER_RULE_PKG_OBSOLETES,
-  SOLVER_RULE_PKG_IMPLICIT_OBSOLETES,
-  SOLVER_RULE_PKG_INSTALLED_OBSOLETES,
-  SOLVER_RULE_UPDATE = 0x200,
-  SOLVER_RULE_FEATURE = 0x300,
-  SOLVER_RULE_JOB = 0x400,
-  SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP,
-  SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM,
-  SOLVER_RULE_JOB_UNKNOWN_PACKAGE,
-  SOLVER_RULE_JOB_UNSUPPORTED,
-  SOLVER_RULE_DISTUPGRADE = 0x500,
-  SOLVER_RULE_INFARCH = 0x600,
-  SOLVER_RULE_CHOICE = 0x700,
-  SOLVER_RULE_LEARNT = 0x800,
-  SOLVER_RULE_BEST = 0x900,
-  SOLVER_RULE_YUMOBS = 0xa00
-} SolverRuleinfo;
-
-#define SOLVER_RULE_TYPEMASK    0xff00
-
-struct _Solver;
-
-/*-------------------------------------------------------------------
- * disable rule
- */
-
-static inline void
-solver_disablerule(struct _Solver *solv, Rule *r)
-{
-  if (r->d >= 0)
-    r->d = -r->d - 1;
-}
-
-/*-------------------------------------------------------------------
- * enable rule
- */
-
-static inline void
-solver_enablerule(struct _Solver *solv, Rule *r)
-{
-  if (r->d < 0)
-    r->d = -r->d - 1;
-}
-
-extern Rule *solver_addrule(struct _Solver *solv, Id p, Id p2, Id d);
-extern void solver_unifyrules(struct _Solver *solv);
-extern int solver_rulecmp(struct _Solver *solv, Rule *r1, Rule *r2);
-extern void solver_shrinkrules(struct _Solver *solv, int nrules);
-
-/* pkg rules */
-extern void solver_addpkgrulesforsolvable(struct _Solver *solv, Solvable *s, Map *m);
-extern void solver_addpkgrulesforweak(struct _Solver *solv, Map *m);
-extern void solver_addpkgrulesforlinked(struct _Solver *solv, Map *m);
-extern void solver_addpkgrulesforupdaters(struct _Solver *solv, Solvable *s, Map *m, int allow_all);
-
-/* update/feature rules */
-extern void solver_addupdaterule(struct _Solver *solv, Solvable *s, int allow_all);
-
-/* infarch rules */
-extern void solver_addinfarchrules(struct _Solver *solv, Map *addedmap);
-
-/* dup rules */
-extern void solver_createdupmaps(struct _Solver *solv);
-extern void solver_freedupmaps(struct _Solver *solv);
-extern void solver_addduprules(struct _Solver *solv, Map *addedmap);
-
-/* choice rules */
-extern void solver_addchoicerules(struct _Solver *solv);
-extern void solver_disablechoicerules(struct _Solver *solv, Rule *r);
-
-/* best rules */
-extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs);
-
-/* yumobs rules */
-extern void solver_addyumobsrules(struct _Solver *solv);
-
-/* policy rule disabling/reenabling */
-extern void solver_disablepolicyrules(struct _Solver *solv);
-extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx);
-extern void solver_reenablepolicyrules_cleandeps(struct _Solver *solv, Id pkg);
-
-/* rule info */
-extern int solver_allruleinfos(struct _Solver *solv, Id rid, Queue *rq);
-extern SolverRuleinfo solver_ruleinfo(struct _Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
-extern SolverRuleinfo solver_ruleclass(struct _Solver *solv, Id rid);
-extern void solver_ruleliterals(struct _Solver *solv, Id rid, Queue *q);
-extern int  solver_rule2jobidx(struct _Solver *solv, Id rid);
-extern Id   solver_rule2job(struct _Solver *solv, Id rid, Id *whatp);
-extern Id   solver_rule2solvable(struct _Solver *solv, Id rid);
-extern void solver_rule2rules(struct _Solver *solv, Id rid, Queue *q, int recursive);
-extern Id   solver_rule2pkgrule(struct _Solver *solv, Id rid);
-
-/* orphan handling */
-extern void solver_breakorphans(struct _Solver *solv);
-extern void solver_check_brokenorphanrules(struct _Solver *solv, Queue *dq);
-
-
-/* legacy */
-#define SOLVER_RULE_RPM SOLVER_RULE_PKG
-#define SOLVER_RULE_RPM_NOT_INSTALLABLE SOLVER_RULE_PKG_NOT_INSTALLABLE
-#define SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP
-#define SOLVER_RULE_RPM_PACKAGE_REQUIRES SOLVER_RULE_PKG_REQUIRES
-#define SOLVER_RULE_RPM_SELF_CONFLICT SOLVER_RULE_PKG_SELF_CONFLICT
-#define SOLVER_RULE_RPM_PACKAGE_CONFLICT SOLVER_RULE_PKG_CONFLICTS
-#define SOLVER_RULE_RPM_SAME_NAME SOLVER_RULE_PKG_SAME_NAME
-#define SOLVER_RULE_RPM_PACKAGE_OBSOLETES SOLVER_RULE_PKG_OBSOLETES
-#define SOLVER_RULE_RPM_IMPLICIT_OBSOLETES SOLVER_RULE_PKG_IMPLICIT_OBSOLETES
-#define SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES SOLVER_RULE_PKG_INSTALLED_OBSOLETES
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/libsolv-0.6.15/src/selection.c b/libsolv-0.6.15/src/selection.c
deleted file mode 100644 (file)
index 8856436..0000000
+++ /dev/null
@@ -1,1185 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * selection.c
- *
- */
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <fnmatch.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "selection.h"
-#include "solver.h"
-#include "evr.h"
-
-
-static int
-str2archid(Pool *pool, const char *arch)
-{
-  Id id;
-  if (!*arch)
-    return 0;
-  id = pool_str2id(pool, arch, 0);
-  if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
-    return id;
-  if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
-    return 0;
-  return id;
-}
-
-static void
-selection_prune(Pool *pool, Queue *selection)
-{
-  int i, j;
-  Id p, pp;
-  for (i = j = 0; i < selection->count; i += 2)
-    {
-      Id select = selection->elements[i] & SOLVER_SELECTMASK;
-      p = 0;
-      if (select == SOLVER_SOLVABLE_ALL)
-       p = 1;
-      else if (select == SOLVER_SOLVABLE_REPO)
-       {
-         Solvable *s;
-         Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
-         if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             break;
-       }
-      else
-       {
-         FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
-           break;
-       }
-      if (!p)
-       continue;
-      selection->elements[j] = selection->elements[i];
-      selection->elements[j + 1] = selection->elements[i + 1];
-      j += 2;
-    }
-  queue_truncate(selection, j);
-}
-
-
-static int
-selection_solvables_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  return *(const Id *)ap - *(const Id *)bp;
-}
-
-void
-selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
-{
-  int i, j;
-  Id p, pp, lastid;
-  queue_empty(pkgs);
-  for (i = 0; i < selection->count; i += 2)
-    {
-      Id select = selection->elements[i] & SOLVER_SELECTMASK;
-      if (select == SOLVER_SOLVABLE_ALL)
-       {
-         FOR_POOL_SOLVABLES(p)
-           queue_push(pkgs, p);
-       }
-      if (select == SOLVER_SOLVABLE_REPO)
-       {
-         Solvable *s;
-         Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
-         if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             queue_push(pkgs, p);
-       }
-      else
-       {
-         FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
-           queue_push(pkgs, p);
-       }
-    }
-  if (pkgs->count < 2)
-    return;
-  /* sort and unify */
-  solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL);
-  lastid = pkgs->elements[0];
-  for (i = j = 1; i < pkgs->count; i++)
-    if (pkgs->elements[i] != lastid)
-      pkgs->elements[j++] = lastid = pkgs->elements[i];
-  queue_truncate(pkgs, j);
-}
-
-static void
-selection_flatten(Pool *pool, Queue *selection)
-{
-  Queue q;
-  int i;
-  if (selection->count <= 2)
-    return;
-  for (i = 0; i < selection->count; i += 2)
-    if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
-      {
-       selection->elements[0] = selection->elements[i];
-       selection->elements[1] = selection->elements[i + 1];
-       queue_truncate(selection, 2);
-       return;
-      }
-  queue_init(&q);
-  selection_solvables(pool, selection, &q);
-  if (!q.count)
-    {
-      queue_empty(selection);
-      return;
-    }
-  queue_truncate(selection, 2);
-  if (q.count > 1)
-    {
-      selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
-      selection->elements[1] = pool_queuetowhatprovides(pool, &q);
-    }
-  else
-    {
-      selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
-      selection->elements[1] = q.elements[0];
-    }
-}
-
-static void
-selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
-{
-  int i;
-
-  for (i = 0; i < selection->count; i += 2)
-    {
-      Id select = selection->elements[i] & SOLVER_SELECTMASK;
-      Id id = selection->elements[i + 1];
-      if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
-       {
-         /* done by selection_addsrc, currently implies SELECTION_NAME */
-         Queue q;
-         Id p, pp;
-         Id rel = 0, relname = 0;
-         int miss = 0;
-
-         queue_init(&q);
-         FOR_JOB_SELECT(p, pp, select, id)
-           {
-             Solvable *s = pool->solvables + p;
-             if (!rel || s->name != relname)
-               {
-                 relname = s->name;
-                 rel = pool_rel2id(pool, relname, relevr, relflags, 1);
-               }
-             if (pool_match_nevr(pool, s, rel))
-               queue_push(&q, p);
-             else
-               miss = 1;
-           }
-         if (miss)
-           {
-             if (q.count == 1)
-               {
-                 selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
-                 selection->elements[i + 1] = q.elements[0];
-               }
-             else
-               {
-                 selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
-                 selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
-               }
-           }
-         queue_free(&q);
-       }
-      else if (select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES)
-       {
-         /* don't stack src reldeps */
-         if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id))
-           {
-             Reldep *rd = GETRELDEP(pool, id);
-             if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC)
-               id = rd->name;
-           }
-         selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
-       }
-      else
-       continue;       /* actually internal error */
-      if (relflags == REL_ARCH)
-        selection->elements[i] |= SOLVER_SETARCH;
-      if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES)
-        {
-         if (pool->disttype == DISTTYPE_DEB)
-            selection->elements[i] |= SOLVER_SETEVR;   /* debian can't match version only like rpm */
-         else
-           {
-             const char *rel =  strrchr(pool_id2str(pool, relevr), '-');
-             selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
-           }
-        }
-    }
-  selection_prune(pool, selection);
-}
-
-static void
-selection_filter_installed(Pool *pool, Queue *selection)
-{
-  Queue q;
-  int i, j;
-
-  if (!pool->installed)
-    queue_empty(selection);
-  queue_init(&q);
-  for (i = j = 0; i < selection->count; i += 2)
-    {
-      Id select = selection->elements[i] & SOLVER_SELECTMASK;
-      Id id = selection->elements[i + 1];
-      if (select == SOLVER_SOLVABLE_ALL)
-       {
-         select = SOLVER_SOLVABLE_REPO;
-         id = pool->installed->repoid;
-       }
-      else if (select == SOLVER_SOLVABLE_REPO)
-       {
-         if (id != pool->installed->repoid)
-           select = 0;
-       }
-      else
-       {
-         int bad = 0;
-         Id p, pp;
-         queue_empty(&q);
-         FOR_JOB_SELECT(p, pp, select, id)
-           {
-             if (pool->solvables[p].repo != pool->installed)
-               bad = 1;
-             else
-               queue_push(&q, p);
-           }
-         if (bad || !q.count)
-           {
-             if (!q.count)
-               select = 0;
-             else if (q.count == 1)
-               {
-                 select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
-                 id = q.elements[0];
-               }
-             else
-               {
-                 select = SOLVER_SOLVABLE_ONE_OF;
-                 id = pool_queuetowhatprovides(pool, &q);
-               }
-           }
-       }
-      if (select)
-       {
-         selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
-         selection->elements[j++] = id;
-       }
-    }
-  queue_truncate(selection, j);
-  queue_free(&q);
-}
-
-static void
-selection_addsrc(Pool *pool, Queue *selection, int flags)
-{
-  Queue q;
-  Id p, name;
-  int i, havesrc;
-
-  if ((flags & SELECTION_INSTALLED_ONLY) != 0)
-    return;    /* sources can't be installed */
-  queue_init(&q);
-  for (i = 0; i < selection->count; i += 2)
-    {
-      if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
-       continue;
-      name = selection->elements[i + 1];
-      havesrc = 0;
-      queue_empty(&q);
-      FOR_POOL_SOLVABLES(p)
-       {
-         Solvable *s = pool->solvables + p;
-         if (s->name != name)
-           continue;
-         if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-           {
-             if (pool_disabled_solvable(pool, s))
-               continue;
-             havesrc = 1;
-           }
-         else if (s->repo != pool->installed && !pool_installable(pool, s))
-           continue;
-         queue_push(&q, p);
-       }
-      if (!havesrc || !q.count)
-       continue;
-      if (q.count == 1)
-       {
-         selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
-         selection->elements[i + 1] = q.elements[0];
-       }
-      else
-       {
-         selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
-         selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
-       }
-    }
-  queue_free(&q);
-}
-
-static inline const char *
-skipkind(const char *n)
-{
-  const char *s;
-  for (s = n; *s >= 'a' && *s <= 'z'; s++)
-    ;
-  if (*s == ':' && s != n)
-     return s + 1;
-  return n;
-}
-
-static inline void
-queue_pushunique2(Queue *q, Id id1, Id id2)
-{
-  int i;
-  for (i = 0; i < q->count; i += 2)
-    if (q->elements[i] == id1 && q->elements[i + 1] == id2)
-      return;
-  queue_push2(q, id1, id2);
-}
-
-static int
-selection_depglob_id(Pool *pool, Queue *selection, Id id, int flags)
-{
-  Id p, pp;
-  int match = 0;
-
-  FOR_PROVIDES(p, pp, id)
-    {
-      Solvable *s = pool->solvables + p;
-      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
-       continue;
-      match = 1;
-      if (s->name == id && (flags & SELECTION_NAME) != 0)
-       {
-         if ((flags & SELECTION_SOURCE_ONLY) != 0)
-           id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
-         queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
-         if ((flags & SELECTION_WITH_SOURCE) != 0)
-           selection_addsrc(pool, selection, flags);
-         return SELECTION_NAME;
-       }
-    }
-  if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
-    {
-      /* src rpms don't have provides, so we must check every solvable */
-      FOR_POOL_SOLVABLES(p)    /* slow path */
-       {
-         Solvable *s = pool->solvables + p;
-         if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
-           {
-             if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
-               continue;       /* just in case... src rpms can't be installed */
-             if (pool_disabled_solvable(pool, s))
-               continue;
-             if ((flags & SELECTION_SOURCE_ONLY) != 0)
-               id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
-             queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
-             if ((flags & SELECTION_WITH_SOURCE) != 0)
-               selection_addsrc(pool, selection, flags);
-             return SELECTION_NAME;
-           }
-       }
-    }
-  if (match && (flags & SELECTION_PROVIDES) != 0)
-    {
-      queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
-      return SELECTION_PROVIDES;
-    }
-  return 0;
-}
-
-static int
-selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
-{
-  Id id, p, pp;
-  int match = 0;
-  int doglob = 0;
-  int nocase = 0;
-  int globflags = 0;
-
-  if ((flags & SELECTION_SOURCE_ONLY) != 0)
-    {
-      flags &= ~SELECTION_PROVIDES;    /* sources don't provide anything */
-      flags &= ~SELECTION_WITH_SOURCE;
-    }
-
-  if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
-    return 0;
-
-  if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
-    return 0;
-
-  nocase = flags & SELECTION_NOCASE;
-  if (!nocase && !(flags & SELECTION_SKIP_KIND))
-    {
-      id = pool_str2id(pool, name, 0);
-      if (id)
-       {
-         /* the id is know, do the fast id matching using the whatprovides lookup */
-         int ret = selection_depglob_id(pool, selection, id, flags);
-         if (ret)
-           return ret;
-       }
-    }
-
-  if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
-    doglob = 1;
-
-  if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
-    return 0;  /* all done above in depglob_id */
-
-  if (doglob && nocase)
-    globflags = FNM_CASEFOLD;
-
-  if ((flags & SELECTION_NAME) != 0)
-    {
-      /* looks like a name glob. hard work. */
-      FOR_POOL_SOLVABLES(p)
-       {
-         Solvable *s = pool->solvables + p;
-         const char *n;
-         if (s->repo != pool->installed && !pool_installable(pool, s))
-           {
-             if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
-               continue;
-             if (pool_disabled_solvable(pool, s))
-               continue;
-           }
-         if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
-           continue;
-         id = s->name;
-         n = pool_id2str(pool, id);
-         if (flags & SELECTION_SKIP_KIND)
-           n = skipkind(n);
-         if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
-           {
-             if ((flags & SELECTION_SOURCE_ONLY) != 0)
-               id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
-             queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
-             match = 1;
-           }
-       }
-      if (match)
-       {
-         if ((flags & SELECTION_WITH_SOURCE) != 0)
-           selection_addsrc(pool, selection, flags);
-          return SELECTION_NAME;
-       }
-    }
-
-  if ((flags & SELECTION_PROVIDES))
-    {
-      /* looks like a dep glob. really hard work. */
-      for (id = 1; id < pool->ss.nstrings; id++)
-       {
-         const char *n;
-         if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
-           continue;
-         n = pool_id2str(pool, id);
-         if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
-           {
-             if ((flags & SELECTION_INSTALLED_ONLY) != 0)
-               {
-                 FOR_PROVIDES(p, pp, id)
-                   if (pool->solvables[p].repo == pool->installed)
-                     break;
-                 if (!p)
-                   continue;
-               }
-             queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
-             match = 1;
-           }
-       }
-      if (match)
-        return SELECTION_PROVIDES;
-    }
-  return 0;
-}
-
-static int
-selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
-{
-  int ret;
-  const char *r;
-  Id archid;
-
-  if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
-    return ret;
-  if (!(flags & SELECTION_DOTARCH))
-    return 0;
-  /* check if there is an .arch suffix */
-  if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
-    {
-      char *rname = solv_strdup(name);
-      rname[r - name] = 0;
-      if (archid == ARCH_SRC || archid == ARCH_NOSRC)
-       flags |= SELECTION_SOURCE_ONLY;
-      if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
-       {
-         selection_filter_rel(pool, selection, REL_ARCH, archid);
-         solv_free(rname);
-         return ret | SELECTION_DOTARCH;
-       }
-      solv_free(rname);
-    }
-  return 0;
-}
-
-static int
-selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
-{
-  Dataiterator di;
-  Queue q;
-  int type;
-
-  /* all files in the file list start with a '/' */
-  if (*name != '/')
-    {
-      if (!(flags & SELECTION_GLOB))
-       return 0;
-      if (*name != '*' && *name != '[' && *name != '?')
-       return 0;
-    }
-  type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
-  if ((flags & SELECTION_NOCASE) != 0)
-    type |= SEARCH_NOCASE;
-  queue_init(&q);
-  dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
-  while (dataiterator_step(&di))
-    {
-      Solvable *s = pool->solvables + di.solvid;
-      if (!s->repo)
-       continue;
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       {
-         if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
-           continue;
-         if (pool_disabled_solvable(pool, s))
-           continue;
-       }
-      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
-       continue;
-      queue_push(&q, di.solvid);
-      dataiterator_skip_solvable(&di);
-    }
-  dataiterator_free(&di);
-  if (!q.count)
-    return 0;
-  if (q.count > 1)
-    queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
-  else
-    queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
-  queue_free(&q);
-  return SELECTION_FILELIST;
-}
-
-static char *
-splitrel(char *rname, char *r, int *rflagsp)
-{
-  int nend = r - rname;
-  int rflags = 0;
-  if (nend && *r == '=' && r[-1] == '!')
-    {
-      nend--;
-      r++;
-      rflags = REL_LT|REL_GT;
-    }
-  for (; *r; r++)
-    {
-      if (*r == '<')
-       rflags |= REL_LT;
-      else if (*r == '=')
-       rflags |= REL_EQ;
-      else if (*r == '>')
-       rflags |= REL_GT;
-      else
-       break;
-    }
-  while (*r && (*r == ' ' || *r == '\t'))
-    r++;
-  while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
-    nend--;
-  if (!*rname || !*r)
-    return 0;
-  *rflagsp = rflags;
-  rname[nend] = 0;
-  return r;
-}
-
-static int
-selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
-{
-  int ret, rflags = 0;
-  char *r, *rname;
-
-  /* relation case, support:
-   * depglob rel
-   * depglob.arch rel
-   */
-  rname = solv_strdup(name);
-  if ((r = strpbrk(rname, "<=>")) != 0)
-    {
-      if ((r = splitrel(rname, r, &rflags)) == 0)
-       {
-         solv_free(rname);
-         return 0;
-       }
-    }
-  if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
-    {
-      if (rflags)
-       selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
-      solv_free(rname);
-      return ret | SELECTION_REL;
-    }
-  solv_free(rname);
-  return 0;
-}
-
-#if defined(MULTI_SEMANTICS)
-# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
-#elif defined(DEBIAN)
-# define EVRCMP_DEPCMP EVRCMP_COMPARE
-#else
-# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
-#endif
-
-/* magic epoch promotion code, works only for SELECTION_NAME selections */
-static void
-selection_filter_evr(Pool *pool, Queue *selection, char *evr)
-{
-  int i, j;
-  Queue q;
-  Id qbuf[10];
-
-  queue_init(&q);
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  for (i = j = 0; i < selection->count; i += 2)
-    {
-      Id select = selection->elements[i] & SOLVER_SELECTMASK;
-      Id id = selection->elements[i + 1];
-      Id p, pp;
-      const char *lastepoch = 0;
-      int lastepochlen = 0;
-
-      queue_empty(&q);
-      FOR_JOB_SELECT(p, pp, select, id)
-       {
-         Solvable *s = pool->solvables + p;
-         const char *sevr = pool_id2str(pool, s->evr);
-         const char *sp;
-         for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
-           ;
-         if (*sp != ':')
-           sp = sevr;
-         /* compare vr part */
-         if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
-           {
-             int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
-             if (r == -1 || r == 1)
-               continue;       /* solvable does not match vr */
-           }
-         queue_push(&q, p);
-         if (sp > sevr)
-           {
-             while (sevr < sp && *sevr == '0') /* normalize epoch */
-               sevr++;
-           }
-         if (!lastepoch)
-           {
-             lastepoch = sevr;
-             lastepochlen = sp - sevr;
-           }
-         else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
-           lastepochlen = -1;  /* multiple different epochs */
-       }
-      if (!lastepoch || lastepochlen == 0)
-       id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
-      else if (lastepochlen >= 0)
-       {
-         /* found exactly one epoch, simply prepend */
-         char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
-         strncpy(evrx, lastepoch, lastepochlen + 1);
-         strcpy(evrx + lastepochlen + 1, evr);
-         id = pool_str2id(pool, evrx, 1);
-         solv_free(evrx);
-       }
-      else
-       {
-         /* multiple epochs in multiple solvables, convert to list of solvables */
-         selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
-         selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
-         j += 2;
-         continue;
-       }
-      queue_empty(&q);
-      queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
-      selection_filter_rel(pool, &q, REL_EQ, id);
-      if (!q.count)
-        continue;              /* oops, no match */
-      selection->elements[j] = q.elements[0];
-      selection->elements[j + 1] = q.elements[1];
-      j += 2;
-    }
-  queue_truncate(selection, j);
-  queue_free(&q);
-}
-
-/* match the "canonical" name of the package */
-static int
-selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
-{
-  char *rname, *r, *r2;
-  Id archid = 0;
-  int ret;
-
-  /*
-   * nameglob-version
-   * nameglob-version.arch
-   * nameglob-version-release
-   * nameglob-version-release.arch
-   */
-  flags |= SELECTION_NAME;
-  flags &= ~SELECTION_PROVIDES;
-
-  if (pool->disttype == DISTTYPE_DEB)
-    {
-      if ((r = strchr(name, '_')) == 0)
-       return 0;
-      rname = solv_strdup(name);       /* so we can modify it */
-      r = rname + (r - name);
-      *r++ = 0;
-      if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
-       {
-         solv_free(rname);
-         return 0;
-       }
-      /* is there a vaild arch? */
-      if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
-       {
-         *r2 = 0;      /* split off */
-          selection_filter_rel(pool, selection, REL_ARCH, archid);
-       }
-      selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
-      solv_free(rname);
-      return ret | SELECTION_CANON;
-    }
-
-  if (pool->disttype == DISTTYPE_HAIKU)
-    {
-      if ((r = strchr(name, '-')) == 0)
-       return 0;
-      rname = solv_strdup(name);       /* so we can modify it */
-      r = rname + (r - name);
-      *r++ = 0;
-      if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
-       {
-         solv_free(rname);
-         return 0;
-       }
-      /* is there a vaild arch? */
-      if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
-       {
-         *r2 = 0;      /* split off */
-          selection_filter_rel(pool, selection, REL_ARCH, archid);
-       }
-      selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
-      solv_free(rname);
-      return ret | SELECTION_CANON;
-    }
-
-  if ((r = strrchr(name, '-')) == 0)
-    return 0;
-  rname = solv_strdup(name);   /* so we can modify it */
-  r = rname + (r - name);
-  *r = 0;
-
-  /* split off potential arch part from version */
-  if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
-    *r2 = 0;   /* found valid arch, split it off */
-  if (archid == ARCH_SRC || archid == ARCH_NOSRC)
-    flags |= SELECTION_SOURCE_ONLY;
-
-  /* try with just the version */
-  if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
-    {
-      /* no luck, try with version-release */
-      if ((r2 = strrchr(rname, '-')) == 0)
-       {
-         solv_free(rname);
-         return 0;
-       }
-      *r = '-';
-      *r2 = 0;
-      r = r2;
-      if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
-       {
-         solv_free(rname);
-         return 0;
-       }
-    }
-  if (archid)
-    selection_filter_rel(pool, selection, REL_ARCH, archid);
-  selection_filter_evr(pool, selection, r + 1);        /* magic epoch promotion */
-  solv_free(rname);
-  return ret | SELECTION_CANON;
-}
-
-int
-selection_make(Pool *pool, Queue *selection, const char *name, int flags)
-{
-  int ret = 0;
-
-  queue_empty(selection);
-  if ((flags & SELECTION_FILELIST) != 0)
-    ret = selection_filelist(pool, selection, name, flags);
-  if (!ret && (flags & SELECTION_REL) != 0 && strpbrk(name, "<=>") != 0)
-    ret = selection_rel(pool, selection, name, flags);
-  if (!ret)
-    ret = selection_depglob_arch(pool, selection, name, flags);
-  if (!ret && (flags & SELECTION_CANON) != 0)
-    ret = selection_canon(pool, selection, name, flags);
-  if (selection->count && (flags & SELECTION_INSTALLED_ONLY) != 0)
-    selection_filter_installed(pool, selection);
-  if (ret && !selection->count)
-    ret = 0;   /* no match -> always return zero */
-  if (ret && (flags & SELECTION_FLAT) != 0)
-    selection_flatten(pool, selection);
-  return ret;
-}
-
-static int
-matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
-{
-  if (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH)
-       {
-         if (matchdep(pool, rd->name, rname, rflags, revr, flags))
-           return 1;
-         if (matchdep(pool, rd->evr, rname, rflags, revr, flags))
-           return 1;
-         return 0;
-       }
-      if (rd->flags == REL_ARCH)
-       return matchdep(pool, rd->name, rname, rflags, revr, flags);
-      if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
-       return 0;
-      if (rflags)
-       {
-         /* XXX: need pool_match_flags_evr here */
-         if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id))
-           return 0;
-       }
-      return 1;
-    }
-  if (flags & SELECTION_GLOB)
-    {
-      int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
-      return fnmatch(rname, pool_id2str(pool, id), globflags) == 0 ? 1 : 0;
-    }
-  if (flags & SELECTION_NOCASE)
-    return strcasecmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0;
-  return strcmp(rname, pool_id2str(pool, id)) == 0 ? 1 : 0;
-}
-
-/*
- *  select against the dependencies in keyname
- *  like SELECTION_REL and SELECTION_PROVIDES, but with the
- *  deps in keyname instead of provides.
- */
-int
-selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
-{
-  char *rname, *r;
-  int rflags = 0;
-  Id p;
-  Queue q;
-
-  queue_empty(selection);
-  rname = solv_strdup(name);
-  if ((r = strpbrk(rname, "<=>")) != 0)
-    {
-      if ((r = splitrel(rname, r, &rflags)) == 0)
-       {
-         solv_free(rname);
-         return 0;
-       }
-    }
-  if ((flags & SELECTION_GLOB) != 0 && !strpbrk(name, "[*?") != 0)
-    flags &= ~SELECTION_GLOB;
-
-  queue_init(&q);
-  FOR_POOL_SOLVABLES(p)
-    {
-      Solvable *s =  pool->solvables + p;
-      int i;
-
-      if (s->repo != pool->installed && !pool_installable(pool, s))
-       {
-         if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
-           continue;
-         if (pool_disabled_solvable(pool, s))
-           continue;
-       }
-      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
-       continue;
-      if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
-       continue;
-      queue_empty(&q);
-      repo_lookup_deparray(s->repo, p, keyname, &q, marker);
-      for (i = 0; i < q.count; i++)
-       {
-         Id id = q.elements[i];
-         if (matchdep(pool, id, rname, rflags, r, flags))
-           break;
-       }
-      if (i < q.count)
-       queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
-    }
-  queue_free(&q);
-  solv_free(rname);
-  if (!selection->count)
-    return 0;
-  if ((flags & SELECTION_FLAT) != 0)
-    selection_flatten(pool, selection);
-  return SELECTION_PROVIDES;
-}
-
-static inline int
-pool_is_kind(Pool *pool, Id name, Id kind)
-{
-  const char *n;
-  if (!kind)
-    return 1;
-  n = pool_id2str(pool, name);
-  if (kind != 1)
-    {
-      const char *kn = pool_id2str(pool, kind);
-      int knl = strlen(kn);
-      return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
-    }
-  else
-    {
-      if (*n == ':')
-        return 1;
-      while(*n >= 'a' && *n <= 'z')
-        n++;
-      return *n == ':' ? 0 : 1;
-    }
-}
-
-void
-selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
-{
-  int i, j, miss;
-  Id p, pp, q1filled = 0;
-  Queue q1;
-  Map m2;
-  Id setflags = 0;
-
-  if (!sel1->count || !sel2->count)
-    {
-      queue_empty(sel1);
-      return;
-    }
-  if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
-    {
-      /* XXX: not 100% correct, but very useful */
-      p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);   /* job & jobflags */
-      queue_free(sel1);
-      queue_init_clone(sel1, sel2);
-      for (i = 0; i < sel1->count; i += 2)
-        sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ;
-      return;
-    }
-  queue_init(&q1);
-  map_init(&m2, pool->nsolvables);
-  for (i = 0; i < sel2->count; i += 2)
-    {
-      Id select = sel2->elements[i] & SOLVER_SELECTMASK;
-      if (select == SOLVER_SOLVABLE_ALL)
-       {
-         queue_free(&q1);
-         map_free(&m2);
-         return;
-       }
-      if (select == SOLVER_SOLVABLE_REPO)
-       {
-         Solvable *s;
-         Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
-         if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             map_set(&m2, p);
-       }
-      else
-       {
-         if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1]))
-           {
-             Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]);
-             if (rd->flags == REL_ARCH && rd->name == 0)
-               {
-                 /* special arch filter */
-                 if (!q1filled++)
-                   selection_solvables(pool, sel1, &q1);
-                 for (j = 0; j < q1.count; j++)
-                   {
-                     Id p = q1.elements[j];
-                     Solvable *s = pool->solvables + p;
-                     if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC))
-                       map_set(&m2, p);
-                   }
-                 continue;
-               }
-             else if (rd->flags == REL_KIND && rd->name == 0)
-               {
-                 /* special kind filter */
-                 if (!q1filled++)
-                   selection_solvables(pool, sel1, &q1);
-                 for (j = 0; j < q1.count; j++)
-                   {
-                     Id p = q1.elements[j];
-                     Solvable *s = pool->solvables + p;
-                     if (pool_is_kind(pool, s->name, rd->evr))
-                       map_set(&m2, p);
-                   }
-                 continue;
-               }
-           }
-         FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
-           map_set(&m2, p);
-       }
-    }
-  if (sel2->count == 2)                /* XXX: AND all setmasks instead? */
-    setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
-  for (i = j = 0; i < sel1->count; i += 2)
-    {
-      Id select = sel1->elements[i] & SOLVER_SELECTMASK;
-      queue_empty(&q1);
-      miss = 0;
-      if (select == SOLVER_SOLVABLE_ALL)
-       {
-         FOR_POOL_SOLVABLES(p)
-           {
-             if (map_tst(&m2, p))
-               queue_push(&q1, p);
-             else
-               miss = 1;
-           }
-       }
-      else if (select == SOLVER_SOLVABLE_REPO)
-       {
-         Solvable *s;
-         Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
-         if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             {
-               if (map_tst(&m2, p))
-                 queue_push(&q1, p);
-               else
-                 miss = 1;
-             }
-       }
-      else
-       {
-         FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
-           {
-             if (map_tst(&m2, p))
-               queue_pushunique(&q1, p);
-             else
-               miss = 1;
-           }
-       }
-      if (!q1.count)
-       continue;
-      if (!miss)
-       {
-         sel1->elements[j] = sel1->elements[i] | setflags;
-         sel1->elements[j + 1] = sel1->elements[i + 1];
-       }
-      else if (q1.count > 1)
-       {
-         sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
-         sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
-       }
-      else
-       {
-         sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
-         sel1->elements[j + 1] = q1.elements[0];
-       }
-      j += 2;
-    }
-  queue_truncate(sel1, j);
-  queue_free(&q1);
-  map_free(&m2);
-}
-
-void
-selection_add(Pool *pool, Queue *sel1, Queue *sel2)
-{
-  int i;
-  for (i = 0; i < sel2->count; i++)
-    queue_push(sel1, sel2->elements[i]);
-}
-
-const char *
-pool_selection2str(Pool *pool, Queue *selection, Id flagmask)
-{
-  char *s;
-  const char *s2;
-  int i;
-  s = pool_tmpjoin(pool, 0, 0, 0);
-  for (i = 0; i < selection->count; i += 2)
-    {
-      Id how = selection->elements[i];
-      if (*s)
-       s = pool_tmpappend(pool, s, " + ", 0);
-      s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]);
-      s = pool_tmpappend(pool, s, s2, 0);
-      pool_freetmpspace(pool, s2);
-      how &= flagmask & SOLVER_SETMASK;
-      if (how)
-       {
-         int o = strlen(s);
-         s = pool_tmpappend(pool, s, " ", 0);
-         if (how & SOLVER_SETEV)
-           s = pool_tmpappend(pool, s, ",setev", 0);
-         if (how & SOLVER_SETEVR)
-           s = pool_tmpappend(pool, s, ",setevr", 0);
-         if (how & SOLVER_SETARCH)
-           s = pool_tmpappend(pool, s, ",setarch", 0);
-         if (how & SOLVER_SETVENDOR)
-           s = pool_tmpappend(pool, s, ",setvendor", 0);
-         if (how & SOLVER_SETREPO)
-           s = pool_tmpappend(pool, s, ",setrepo", 0);
-         if (how & SOLVER_NOAUTOSET)
-           s = pool_tmpappend(pool, s, ",noautoset", 0);
-         if (s[o + 1] != ',')
-           s = pool_tmpappend(pool, s, ",?", 0);
-         s[o + 1] = '[';
-         s = pool_tmpappend(pool, s, "]", 0);
-       }
-    }
-  return s;
-}
-
diff --git a/libsolv-0.6.15/src/selection.h b/libsolv-0.6.15/src/selection.h
deleted file mode 100644 (file)
index fc2b15d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * selection.h
- *
- */
-
-#ifndef LIBSOLV_SELECTION_H
-#define LIBSOLV_SELECTION_H
-
-#include "pool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SELECTION_NAME                 (1 << 0)
-#define SELECTION_PROVIDES             (1 << 1)
-#define SELECTION_FILELIST             (1 << 2)
-#define SELECTION_CANON                        (1 << 3)
-#define SELECTION_DOTARCH              (1 << 4)
-#define SELECTION_REL                  (1 << 5)
-
-#define SELECTION_INSTALLED_ONLY       (1 << 8)
-#define SELECTION_GLOB                 (1 << 9)
-#define SELECTION_FLAT                 (1 << 10)
-#define SELECTION_NOCASE               (1 << 11)
-#define SELECTION_SOURCE_ONLY          (1 << 12)
-#define SELECTION_WITH_SOURCE          (1 << 13)
-#define SELECTION_SKIP_KIND            (1 << 14)
-
-extern int  selection_make(Pool *pool, Queue *selection, const char *name, int flags);
-extern int  selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker);
-
-extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2);
-extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
-extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs);
-
-extern const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libsolv-0.6.15/src/sha1.c b/libsolv-0.6.15/src/sha1.c
deleted file mode 100644 (file)
index 668331f..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
-SHA-1 in C
-By Steve Reid <sreid@sea-to-sky.net>
-100% Public Domain
-
------------------
-Modified 7/98
-By James H. Brown <jbrown@burgoyne.com>
-Still 100% Public Domain
-
-Corrected a problem which generated improper hash values on 16 bit machines
-Routine SHA1Update changed from
-       void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
-len)
-to
-       void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
-long len)
-
-The 'len' parameter was declared an int which works fine on 32 bit machines.
-However, on 16 bit machines an int is too small for the shifts being done
-against
-it.  This caused the hash function to generate incorrect values if len was
-greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
-
-Since the file IO in main() reads 16K at a time, any file 8K or larger would
-be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
-"a"s).
-
-I also changed the declaration of variables i & j in SHA1Update to
-unsigned long from unsigned int for the same reason.
-
-These changes should make no difference to any 32 bit implementations since
-an
-int and a long are the same size in those environments.
-
---
-I also corrected a few compiler warnings generated by Borland C.
-1. Added #include <process.h> for exit() prototype
-2. Removed unused variable 'j' in SHA1Final
-3. Changed exit(0) to return(0) at end of main.
-
-ALL changes I made can be located by searching for comments containing 'JHB'
------------------
-Modified 8/98
-By Steve Reid <sreid@sea-to-sky.net>
-Still 100% public domain
-
-1- Removed #include <process.h> and used return() instead of exit()
-2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
-3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
-
------------------
-Modified 4/01
-By Saul Kravitz <Saul.Kravitz@celera.com>
-Still 100% PD
-Modified to run on Compaq Alpha hardware.
-
------------------
-Modified 07/2002
-By Ralph Giles <giles@ghostscript.com>
-Still 100% public domain
-modified for use with stdint types, autoconf
-code cleanup, removed attribution comments
-switched SHA1Final() argument order for consistency
-use SHA1_ prefix for public api
-move public api to sha1.h
-*/
-
-/*
-Test Vectors (from FIPS PUB 180-1)
-"abc"
-  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
-"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
-A million repetitions of "a"
-  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include "sha1.h"
-
-
-static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
-
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-/* blk0() and blk() perform the initial expand. */
-/* I got the idea of expanding during the round function from SSLeay */
-/* FIXME: can we do this in an endian-proof way? */
-#ifdef WORDS_BIGENDIAN
-#define blk0(i) block.l[i]
-#else
-#define blk0(i) (block.l[i] = (rol(block.l[i],24)&0xFF00FF00) \
-    |(rol(block.l[i],8)&0x00FF00FF))
-#endif
-#define blk(i) (block.l[i&15] = rol(block.l[(i+13)&15]^block.l[(i+8)&15] \
-    ^block.l[(i+2)&15]^block.l[i&15],1))
-
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
-
-
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
-{
-    uint32_t a, b, c, d, e;
-    typedef union {
-        uint8_t c[64];
-        uint32_t l[16];
-    } CHAR64LONG16;
-    CHAR64LONG16 block;
-
-    memcpy(&block, buffer, 64);
-
-    /* Copy context->state[] to working vars */
-    a = state[0];
-    b = state[1];
-    c = state[2];
-    d = state[3];
-    e = state[4];
-
-    /* 4 rounds of 20 operations each. Loop unrolled. */
-    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
-    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
-    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
-    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
-    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
-    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
-    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
-    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
-    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
-    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
-    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
-    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
-    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
-    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
-    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
-    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
-    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
-    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
-    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
-    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
-
-    /* Add the working vars back into context.state[] */
-    state[0] += a;
-    state[1] += b;
-    state[2] += c;
-    state[3] += d;
-    state[4] += e;
-
-    /* Wipe variables */
-    a = b = c = d = e = 0;
-}
-
-
-/* SHA1Init - Initialize new context */
-void solv_SHA1_Init(SHA1_CTX* context)
-{
-    /* SHA1 initialization constants */
-    context->state[0] = 0x67452301;
-    context->state[1] = 0xEFCDAB89;
-    context->state[2] = 0x98BADCFE;
-    context->state[3] = 0x10325476;
-    context->state[4] = 0xC3D2E1F0;
-    context->count[0] = context->count[1] = 0;
-}
-
-
-/* Run your data through this. */
-void solv_SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
-{
-    size_t i, j;
-
-#ifdef VERBOSE
-    SHAPrintContext(context, "before");
-#endif
-
-    j = (context->count[0] >> 3) & 63;
-    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
-    context->count[1] += (len >> 29);
-    if ((j + len) > 63) {
-        memcpy(&context->buffer[j], data, (i = 64-j));
-        SHA1_Transform(context->state, context->buffer);
-        for ( ; i + 63 < len; i += 64) {
-            SHA1_Transform(context->state, data + i);
-        }
-        j = 0;
-    }
-    else i = 0;
-    memcpy(&context->buffer[j], &data[i], len - i);
-
-#ifdef VERBOSE
-    SHAPrintContext(context, "after ");
-#endif
-}
-
-
-/* Add padding and return the message digest. */
-void solv_SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
-{
-    uint32_t i;
-    uint8_t  finalcount[8];
-
-    for (i = 0; i < 8; i++) {
-        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
-         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
-    }
-    solv_SHA1_Update(context, (uint8_t *)"\200", 1);
-    while ((context->count[0] & 504) != 448) {
-        solv_SHA1_Update(context, (uint8_t *)"\0", 1);
-    }
-    solv_SHA1_Update(context, finalcount, 8);  /* Should cause a SHA1_Transform() */
-    for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
-        digest[i] = (uint8_t)
-         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
-    }
-
-    /* Wipe variables */
-    i = 0;
-    memset(context->buffer, 0, 64);
-    memset(context->state, 0, 20);
-    memset(context->count, 0, 8);
-    memset(finalcount, 0, 8);  /* SWR */
-}
diff --git a/libsolv-0.6.15/src/sha1.h b/libsolv-0.6.15/src/sha1.h
deleted file mode 100644 (file)
index 0423164..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* public api for steve reid's public domain SHA-1 implementation */
-/* this file is in the public domain */
-
-#include <stdint.h>
-
-typedef struct {
-    uint32_t state[5];
-    uint32_t count[2];
-    uint8_t  buffer[64];
-} SHA1_CTX;
-
-#define SHA1_DIGEST_SIZE 20
-
-void solv_SHA1_Init(SHA1_CTX* context);
-void solv_SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);
-void solv_SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);
diff --git a/libsolv-0.6.15/src/sha2.c b/libsolv-0.6.15/src/sha2.c
deleted file mode 100644 (file)
index 3ca9404..0000000
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- * FILE:       sha2.c
- * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
- *
- * Copyright (c) 2000-2001, Aaron D. Gifford
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
- */
-
-#include <sys/types.h>
-#include <string.h>     /* memcpy()/memset() or bcopy()/bzero() */
-/* #include <assert.h> */   /* assert() */
-#include <stdio.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#include "sha2.h"
-
-
-/*
- * ASSERT NOTE:
- * Some sanity checking code is included using assert().  On my FreeBSD
- * system, this additional code can be removed by compiling with NDEBUG
- * defined.  Check your own systems manpage on assert() to see how to
- * compile WITHOUT the sanity checking code on your system.
- *
- * UNROLLED TRANSFORM LOOP NOTE:
- * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
- * loop version for the hash transform rounds (defined using macros
- * later in this file).  Either define on the command line, for example:
- *
- *   cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
- *
- * or define below:
- *
- *   #define SHA2_UNROLL_TRANSFORM
- *
- */
-
- #define SHA2_UNROLL_TRANSFORM
-
-
-/*** SHA-256/384/512 Machine Architecture Definitions *****************/
-/*
- * BYTE_ORDER NOTE:
- *
- * Please make sure that your system defines BYTE_ORDER.  If your
- * architecture is little-endian, make sure it also defines
- * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
- * equivilent.
- *
- * If your system does not define the above, then you can do so by
- * hand like this:
- *
- *   #define LITTLE_ENDIAN 1234
- *   #define BIG_ENDIAN    4321
- *
- * And for little-endian machines, add:
- *
- *   #define BYTE_ORDER LITTLE_ENDIAN
- *
- * Or for big-endian machines:
- *
- *   #define BYTE_ORDER BIG_ENDIAN
- *
- * The FreeBSD machine this was written on defines BYTE_ORDER
- * appropriately by including <sys/types.h> (which in turn includes
- * <machine/endian.h> where the appropriate definitions are actually
- * made).
- */
-
-/*
- * Define the following sha2_* types to types of the correct length on
- * the native archtecture.   Most BSD systems and Linux define u_intXX_t
- * types.  Machines with very recent ANSI C headers, can use the
- * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H
- * during compile or in the sha.h header file.
- *
- * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t
- * will need to define these three typedefs below (and the appropriate
- * ones in sha.h too) by hand according to their system architecture.
- *
- * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t
- * types and pointing out recent ANSI C support for uintXX_t in inttypes.h.
- */
-typedef uint8_t  sha2_byte;    /* Exactly 1 byte */
-typedef uint32_t sha2_word32;  /* Exactly 4 bytes */
-typedef uint64_t sha2_word64;  /* Exactly 8 bytes */
-
-
-/*** SHA-256/384/512 Various Length Definitions ***********************/
-/* NOTE: Most of these are in sha2.h */
-#define SHA256_SHORT_BLOCK_LENGTH      (SHA256_BLOCK_LENGTH - 8)
-#define SHA384_SHORT_BLOCK_LENGTH      (SHA384_BLOCK_LENGTH - 16)
-#define SHA512_SHORT_BLOCK_LENGTH      (SHA512_BLOCK_LENGTH - 16)
-
-
-/*** ENDIAN REVERSAL MACROS *******************************************/
-#ifndef WORDS_BIGENDIAN
-#define REVERSE32(w,x) { \
-       sha2_word32 tmp = (w); \
-       tmp = (tmp >> 16) | (tmp << 16); \
-       (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
-}
-#define REVERSE64(w,x) { \
-       sha2_word64 tmp = (w); \
-       tmp = (tmp >> 32) | (tmp << 32); \
-       tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
-             ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
-       (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
-             ((tmp & 0x0000ffff0000ffffULL) << 16); \
-}
-#endif /* !WORDS_BIGENDIAN */
-
-/*
- * Macro for incrementally adding the unsigned 64-bit integer n to the
- * unsigned 128-bit integer (represented using a two-element array of
- * 64-bit words):
- */
-#define ADDINC128(w,n) { \
-       (w)[0] += (sha2_word64)(n); \
-       if ((w)[0] < (n)) { \
-               (w)[1]++; \
-       } \
-}
-
-/*
- * Macros for copying blocks of memory and for zeroing out ranges
- * of memory.  Using these macros makes it easy to switch from
- * using memset()/memcpy() and using bzero()/bcopy().
- *
- * Please define either SHA2_USE_MEMSET_MEMCPY or define
- * SHA2_USE_BZERO_BCOPY depending on which function set you
- * choose to use:
- */
-#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
-/* Default to memset()/memcpy() if no option is specified */
-#define        SHA2_USE_MEMSET_MEMCPY  1
-#endif
-#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
-/* Abort with an error if BOTH options are defined */
-#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
-#endif
-
-#ifdef SHA2_USE_MEMSET_MEMCPY
-#define MEMSET_BZERO(p,l)      memset((p), 0, (l))
-#define MEMCPY_BCOPY(d,s,l)    memcpy((d), (s), (l))
-#endif
-#ifdef SHA2_USE_BZERO_BCOPY
-#define MEMSET_BZERO(p,l)      bzero((p), (l))
-#define MEMCPY_BCOPY(d,s,l)    bcopy((s), (d), (l))
-#endif
-
-
-/*** THE SIX LOGICAL FUNCTIONS ****************************************/
-/*
- * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
- *
- *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and
- *   S is a ROTATION) because the SHA-256/384/512 description document
- *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
- *   same "backwards" definition.
- */
-/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
-#define R(b,x)                 ((x) >> (b))
-/* 32-bit Rotate-right (used in SHA-256): */
-#define S32(b,x)       (((x) >> (b)) | ((x) << (32 - (b))))
-/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
-#define S64(b,x)       (((x) >> (b)) | ((x) << (64 - (b))))
-
-/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
-#define Ch(x,y,z)      (((x) & (y)) ^ ((~(x)) & (z)))
-#define Maj(x,y,z)     (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
-
-/* Four of six logical functions used in SHA-256: */
-#define Sigma0_256(x)  (S32(2,  (x)) ^ S32(13, (x)) ^ S32(22, (x)))
-#define Sigma1_256(x)  (S32(6,  (x)) ^ S32(11, (x)) ^ S32(25, (x)))
-#define sigma0_256(x)  (S32(7,  (x)) ^ S32(18, (x)) ^ R(3 ,   (x)))
-#define sigma1_256(x)  (S32(17, (x)) ^ S32(19, (x)) ^ R(10,   (x)))
-
-/* Four of six logical functions used in SHA-384 and SHA-512: */
-#define Sigma0_512(x)  (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
-#define Sigma1_512(x)  (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
-#define sigma0_512(x)  (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))
-#define sigma1_512(x)  (S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))
-
-/*** INTERNAL FUNCTION PROTOTYPES *************************************/
-/* NOTE: These should not be accessed directly from outside this
- * library -- they are intended for private internal visibility/use
- * only.
- */
-static void SHA256_Last(SHA256_CTX*);
-static void SHA512_Last(SHA512_CTX*);
-static void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
-static void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
-
-
-/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
-/* Hash constant words K for SHA-256: */
-const static sha2_word32 K256[64] = {
-       0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
-       0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
-       0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
-       0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
-       0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
-       0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
-       0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
-       0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
-       0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
-       0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
-       0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
-       0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
-       0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
-       0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
-       0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
-       0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
-};
-
-/* Initial hash value H for SHA-256: */
-const static sha2_word32 sha256_initial_hash_value[8] = {
-       0x6a09e667UL,
-       0xbb67ae85UL,
-       0x3c6ef372UL,
-       0xa54ff53aUL,
-       0x510e527fUL,
-       0x9b05688cUL,
-       0x1f83d9abUL,
-       0x5be0cd19UL
-};
-
-/* Hash constant words K for SHA-384 and SHA-512: */
-const static sha2_word64 K512[80] = {
-       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
-       0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
-       0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
-       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
-       0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
-       0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
-       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
-       0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
-       0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
-       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
-       0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
-       0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
-       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
-       0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
-       0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
-       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
-       0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
-       0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
-       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
-       0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
-       0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
-       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
-       0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
-       0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
-       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
-       0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
-       0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
-       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
-       0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
-       0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
-       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
-       0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
-       0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
-       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
-       0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
-       0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
-       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
-       0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
-       0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
-       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
-};
-
-/* Initial hash value H for SHA-384 */
-const static sha2_word64 sha384_initial_hash_value[8] = {
-       0xcbbb9d5dc1059ed8ULL,
-       0x629a292a367cd507ULL,
-       0x9159015a3070dd17ULL,
-       0x152fecd8f70e5939ULL,
-       0x67332667ffc00b31ULL,
-       0x8eb44a8768581511ULL,
-       0xdb0c2e0d64f98fa7ULL,
-       0x47b5481dbefa4fa4ULL
-};
-
-/* Initial hash value H for SHA-512 */
-const static sha2_word64 sha512_initial_hash_value[8] = {
-       0x6a09e667f3bcc908ULL,
-       0xbb67ae8584caa73bULL,
-       0x3c6ef372fe94f82bULL,
-       0xa54ff53a5f1d36f1ULL,
-       0x510e527fade682d1ULL,
-       0x9b05688c2b3e6c1fULL,
-       0x1f83d9abfb41bd6bULL,
-       0x5be0cd19137e2179ULL
-};
-
-/* Initial hash value H for SHA-224: */
-const static sha2_word32 sha224_initial_hash_value[8] = {
-       0xc1059ed8UL,
-       0x367cd507UL,
-       0x3070dd17UL,
-       0xf70e5939UL,
-       0xffc00b31UL,
-       0x68581511UL,
-       0x64f98fa7UL,
-       0xbefa4fa4UL
-};
-
-
-/*** SHA-256: *********************************************************/
-void solv_SHA256_Init(SHA256_CTX* context) {
-       if (context == (SHA256_CTX*)0) {
-               return;
-       }
-       MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
-       MEMSET_BZERO((char *)context->buffer, SHA256_BLOCK_LENGTH);
-       context->bitcount = 0;
-}
-
-#ifdef SHA2_UNROLL_TRANSFORM
-
-/* Unrolled SHA-256 round macros: */
-
-#ifndef WORDS_BIGENDIAN
-
-#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
-       REVERSE32(*data++, W256[j]); \
-       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
-             K256[j] + W256[j]; \
-       (d) += T1; \
-       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
-       j++
-
-
-#else /* !WORDS_BIGENDIAN */
-
-#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
-       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
-            K256[j] + (W256[j] = *data++); \
-       (d) += T1; \
-       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
-       j++
-
-#endif /* !WORDS_BIGENDIAN */
-
-#define ROUND256(a,b,c,d,e,f,g,h)      \
-       s0 = W256[(j+1)&0x0f]; \
-       s0 = sigma0_256(s0); \
-       s1 = W256[(j+14)&0x0f]; \
-       s1 = sigma1_256(s1); \
-       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
-            (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
-       (d) += T1; \
-       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
-       j++
-
-static void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
-       sha2_word32     a, b, c, d, e, f, g, h, s0, s1;
-       sha2_word32     T1, *W256;
-       int             j;
-
-       W256 = context->buffer;
-
-       /* Initialize registers with the prev. intermediate value */
-       a = context->state[0];
-       b = context->state[1];
-       c = context->state[2];
-       d = context->state[3];
-       e = context->state[4];
-       f = context->state[5];
-       g = context->state[6];
-       h = context->state[7];
-
-       j = 0;
-       do {
-               /* Rounds 0 to 15 (unrolled): */
-               ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
-               ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
-               ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
-               ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
-               ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
-               ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
-               ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
-               ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
-       } while (j < 16);
-
-       /* Now for the remaining rounds to 64: */
-       do {
-               ROUND256(a,b,c,d,e,f,g,h);
-               ROUND256(h,a,b,c,d,e,f,g);
-               ROUND256(g,h,a,b,c,d,e,f);
-               ROUND256(f,g,h,a,b,c,d,e);
-               ROUND256(e,f,g,h,a,b,c,d);
-               ROUND256(d,e,f,g,h,a,b,c);
-               ROUND256(c,d,e,f,g,h,a,b);
-               ROUND256(b,c,d,e,f,g,h,a);
-       } while (j < 64);
-
-       /* Compute the current intermediate hash value */
-       context->state[0] += a;
-       context->state[1] += b;
-       context->state[2] += c;
-       context->state[3] += d;
-       context->state[4] += e;
-       context->state[5] += f;
-       context->state[6] += g;
-       context->state[7] += h;
-
-       /* Clean up */
-       a = b = c = d = e = f = g = h = T1 = 0;
-}
-
-#else /* SHA2_UNROLL_TRANSFORM */
-
-static void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
-       sha2_word32     a, b, c, d, e, f, g, h, s0, s1;
-       sha2_word32     T1, T2, *W256;
-       int             j;
-
-       W256 = context->buffer;
-
-       /* Initialize registers with the prev. intermediate value */
-       a = context->state[0];
-       b = context->state[1];
-       c = context->state[2];
-       d = context->state[3];
-       e = context->state[4];
-       f = context->state[5];
-       g = context->state[6];
-       h = context->state[7];
-
-       j = 0;
-       do {
-#ifndef WORDS_BIGENDIAN
-               /* Copy data while converting to host byte order */
-               REVERSE32(*data++,W256[j]);
-               /* Apply the SHA-256 compression function to update a..h */
-               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
-#else /* !WORDS_BIGENDIAN */
-               /* Apply the SHA-256 compression function to update a..h with copy */
-               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
-#endif /* !WORDS_BIGENDIAN */
-               T2 = Sigma0_256(a) + Maj(a, b, c);
-               h = g;
-               g = f;
-               f = e;
-               e = d + T1;
-               d = c;
-               c = b;
-               b = a;
-               a = T1 + T2;
-
-               j++;
-       } while (j < 16);
-
-       do {
-               /* Part of the message block expansion: */
-               s0 = W256[(j+1)&0x0f];
-               s0 = sigma0_256(s0);
-               s1 = W256[(j+14)&0x0f]; 
-               s1 = sigma1_256(s1);
-
-               /* Apply the SHA-256 compression function to update a..h */
-               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
-                    (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
-               T2 = Sigma0_256(a) + Maj(a, b, c);
-               h = g;
-               g = f;
-               f = e;
-               e = d + T1;
-               d = c;
-               c = b;
-               b = a;
-               a = T1 + T2;
-
-               j++;
-       } while (j < 64);
-
-       /* Compute the current intermediate hash value */
-       context->state[0] += a;
-       context->state[1] += b;
-       context->state[2] += c;
-       context->state[3] += d;
-       context->state[4] += e;
-       context->state[5] += f;
-       context->state[6] += g;
-       context->state[7] += h;
-
-       /* Clean up */
-       a = b = c = d = e = f = g = h = T1 = T2 = 0;
-}
-
-#endif /* SHA2_UNROLL_TRANSFORM */
-
-void solv_SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
-       unsigned int    freespace, usedspace;
-
-       if (len == 0) {
-               /* Calling with no data is valid - we do nothing */
-               return;
-       }
-
-       /* Sanity check: */
-       /* assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); */
-
-       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
-       if (usedspace > 0) {
-               /* Calculate how much free space is available in the buffer */
-               freespace = SHA256_BLOCK_LENGTH - usedspace;
-
-               if (len >= freespace) {
-                       /* Fill the buffer completely and process it */
-                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, freespace);
-                       context->bitcount += freespace << 3;
-                       len -= freespace;
-                       data += freespace;
-                       SHA256_Transform(context, context->buffer);
-               } else {
-                       /* The buffer is not yet full */
-                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, len);
-                       context->bitcount += len << 3;
-                       /* Clean up: */
-                       usedspace = freespace = 0;
-                       return;
-               }
-       }
-       while (len >= SHA256_BLOCK_LENGTH) {
-               /* Process as many complete blocks as we can */
-               SHA256_Transform(context, (sha2_word32*)data);
-               context->bitcount += SHA256_BLOCK_LENGTH << 3;
-               len -= SHA256_BLOCK_LENGTH;
-               data += SHA256_BLOCK_LENGTH;
-       }
-       if (len > 0) {
-               /* There's left-overs, so save 'em */
-               MEMCPY_BCOPY((char *)context->buffer, data, len);
-               context->bitcount += len << 3;
-       }
-       /* Clean up: */
-       usedspace = freespace = 0;
-}
-
-static void SHA256_Last(SHA256_CTX* context) {
-       unsigned int    usedspace;
-
-       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
-#ifndef WORDS_BIGENDIAN
-       /* Convert FROM host byte order */
-       REVERSE64(context->bitcount,context->bitcount);
-#endif
-       if (usedspace > 0) {
-               /* Begin padding with a 1 bit: */
-               ((char *)context->buffer)[usedspace++] = 0x80;
-
-               if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
-                       /* Set-up for the last transform: */
-                       MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
-               } else {
-                       if (usedspace < SHA256_BLOCK_LENGTH) {
-                               MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA256_BLOCK_LENGTH - usedspace);
-                       }
-                       /* Do second-to-last transform: */
-                       SHA256_Transform(context, context->buffer);
-
-                       /* And set-up for the last transform: */
-                       MEMSET_BZERO((char *)context->buffer, SHA256_SHORT_BLOCK_LENGTH);
-               }
-       } else {
-               /* Set-up for the last transform: */
-               MEMSET_BZERO((char *)context->buffer, SHA256_SHORT_BLOCK_LENGTH);
-
-               /* Begin padding with a 1 bit: */
-               *((char *)context->buffer) = 0x80;
-       }
-       /* Set the bit count: */
-       MEMCPY_BCOPY(&((char *)context->buffer)[SHA256_SHORT_BLOCK_LENGTH], (char *)(&context->bitcount), 8);
-
-       /* Final transform: */
-       SHA256_Transform(context, context->buffer);
-}
-
-void solv_SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
-       sha2_word32     *d = (sha2_word32*)digest;
-
-       /* Sanity check: */
-       /* assert(context != (SHA256_CTX*)0); */
-
-       /* If no digest buffer is passed, we don't bother doing this: */
-       if (digest != (sha2_byte*)0) {
-               SHA256_Last(context);
-
-#ifndef WORDS_BIGENDIAN
-               {
-                       /* Convert TO host byte order */
-                       int     j;
-                       for (j = 0; j < 8; j++) {
-                               REVERSE32(context->state[j],context->state[j]);
-                               *d++ = context->state[j];
-                       }
-               }
-#else
-               MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);
-#endif
-       }
-
-       /* Clean up state data: */
-       MEMSET_BZERO(context, sizeof(*context));
-}
-
-
-/*** SHA-512: *********************************************************/
-void solv_SHA512_Init(SHA512_CTX* context) {
-       if (context == (SHA512_CTX*)0) {
-               return;
-       }
-       MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
-       MEMSET_BZERO((char *)context->buffer, SHA512_BLOCK_LENGTH);
-       context->bitcount[0] = context->bitcount[1] =  0;
-}
-
-#ifdef SHA2_UNROLL_TRANSFORM
-
-/* Unrolled SHA-512 round macros: */
-#ifndef WORDS_BIGENDIAN
-
-#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
-       REVERSE64(*data++, W512[j]); \
-       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
-             K512[j] + W512[j]; \
-       (d) += T1, \
-       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
-       j++
-
-
-#else /* !WORDS_BIGENDIAN */
-
-#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
-       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
-             K512[j] + (W512[j] = *data++); \
-       (d) += T1; \
-       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
-       j++
-
-#endif /* !WORDS_BIGENDIAN */
-
-#define ROUND512(a,b,c,d,e,f,g,h)      \
-       s0 = W512[(j+1)&0x0f]; \
-       s0 = sigma0_512(s0); \
-       s1 = W512[(j+14)&0x0f]; \
-       s1 = sigma1_512(s1); \
-       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
-             (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
-       (d) += T1; \
-       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
-       j++
-
-static void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
-       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
-       sha2_word64     T1, *W512 = context->buffer;
-       int             j;
-
-       /* Initialize registers with the prev. intermediate value */
-       a = context->state[0];
-       b = context->state[1];
-       c = context->state[2];
-       d = context->state[3];
-       e = context->state[4];
-       f = context->state[5];
-       g = context->state[6];
-       h = context->state[7];
-
-       j = 0;
-       do {
-               ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
-               ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
-               ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
-               ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
-               ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
-               ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
-               ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
-               ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
-       } while (j < 16);
-
-       /* Now for the remaining rounds up to 79: */
-       do {
-               ROUND512(a,b,c,d,e,f,g,h);
-               ROUND512(h,a,b,c,d,e,f,g);
-               ROUND512(g,h,a,b,c,d,e,f);
-               ROUND512(f,g,h,a,b,c,d,e);
-               ROUND512(e,f,g,h,a,b,c,d);
-               ROUND512(d,e,f,g,h,a,b,c);
-               ROUND512(c,d,e,f,g,h,a,b);
-               ROUND512(b,c,d,e,f,g,h,a);
-       } while (j < 80);
-
-       /* Compute the current intermediate hash value */
-       context->state[0] += a;
-       context->state[1] += b;
-       context->state[2] += c;
-       context->state[3] += d;
-       context->state[4] += e;
-       context->state[5] += f;
-       context->state[6] += g;
-       context->state[7] += h;
-
-       /* Clean up */
-       a = b = c = d = e = f = g = h = T1 = 0;
-}
-
-#else /* SHA2_UNROLL_TRANSFORM */
-
-static void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
-       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
-       sha2_word64     T1, T2, *W512 = context->buffer;
-       int             j;
-
-       /* Initialize registers with the prev. intermediate value */
-       a = context->state[0];
-       b = context->state[1];
-       c = context->state[2];
-       d = context->state[3];
-       e = context->state[4];
-       f = context->state[5];
-       g = context->state[6];
-       h = context->state[7];
-
-       j = 0;
-       do {
-#ifndef WORDS_BIGENDIAN
-               /* Convert TO host byte order */
-               REVERSE64(*data++, W512[j]);
-               /* Apply the SHA-512 compression function to update a..h */
-               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
-#else /* !WORDS_BIGENDIAN */
-               /* Apply the SHA-512 compression function to update a..h with copy */
-               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
-#endif /* !WORDS_BIGENDIAN */
-               T2 = Sigma0_512(a) + Maj(a, b, c);
-               h = g;
-               g = f;
-               f = e;
-               e = d + T1;
-               d = c;
-               c = b;
-               b = a;
-               a = T1 + T2;
-
-               j++;
-       } while (j < 16);
-
-       do {
-               /* Part of the message block expansion: */
-               s0 = W512[(j+1)&0x0f];
-               s0 = sigma0_512(s0);
-               s1 = W512[(j+14)&0x0f];
-               s1 =  sigma1_512(s1);
-
-               /* Apply the SHA-512 compression function to update a..h */
-               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
-                    (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
-               T2 = Sigma0_512(a) + Maj(a, b, c);
-               h = g;
-               g = f;
-               f = e;
-               e = d + T1;
-               d = c;
-               c = b;
-               b = a;
-               a = T1 + T2;
-
-               j++;
-       } while (j < 80);
-
-       /* Compute the current intermediate hash value */
-       context->state[0] += a;
-       context->state[1] += b;
-       context->state[2] += c;
-       context->state[3] += d;
-       context->state[4] += e;
-       context->state[5] += f;
-       context->state[6] += g;
-       context->state[7] += h;
-
-       /* Clean up */
-       a = b = c = d = e = f = g = h = T1 = T2 = 0;
-}
-
-#endif /* SHA2_UNROLL_TRANSFORM */
-
-void solv_SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
-       unsigned int    freespace, usedspace;
-
-       if (len == 0) {
-               /* Calling with no data is valid - we do nothing */
-               return;
-       }
-
-       /* Sanity check: */
-       /* assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); */
-
-       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
-       if (usedspace > 0) {
-               /* Calculate how much free space is available in the buffer */
-               freespace = SHA512_BLOCK_LENGTH - usedspace;
-
-               if (len >= freespace) {
-                       /* Fill the buffer completely and process it */
-                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, freespace);
-                       ADDINC128(context->bitcount, freespace << 3);
-                       len -= freespace;
-                       data += freespace;
-                       SHA512_Transform(context, context->buffer);
-               } else {
-                       /* The buffer is not yet full */
-                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, len);
-                       ADDINC128(context->bitcount, len << 3);
-                       /* Clean up: */
-                       usedspace = freespace = 0;
-                       return;
-               }
-       }
-       while (len >= SHA512_BLOCK_LENGTH) {
-               /* Process as many complete blocks as we can */
-               SHA512_Transform(context, (sha2_word64*)data);
-               ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
-               len -= SHA512_BLOCK_LENGTH;
-               data += SHA512_BLOCK_LENGTH;
-       }
-       if (len > 0) {
-               /* There's left-overs, so save 'em */
-               MEMCPY_BCOPY((char *)context->buffer, data, len);
-               ADDINC128(context->bitcount, len << 3);
-       }
-       /* Clean up: */
-       usedspace = freespace = 0;
-}
-
-static void SHA512_Last(SHA512_CTX* context) {
-       unsigned int    usedspace;
-
-       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
-#ifndef WORDS_BIGENDIAN
-       /* Convert FROM host byte order */
-       REVERSE64(context->bitcount[0],context->bitcount[0]);
-       REVERSE64(context->bitcount[1],context->bitcount[1]);
-#endif
-       if (usedspace > 0) {
-               /* Begin padding with a 1 bit: */
-               ((char *)context->buffer)[usedspace++] = 0x80;
-
-               if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
-                       /* Set-up for the last transform: */
-                       MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
-               } else {
-                       if (usedspace < SHA512_BLOCK_LENGTH) {
-                               MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA512_BLOCK_LENGTH - usedspace);
-                       }
-                       /* Do second-to-last transform: */
-                       SHA512_Transform(context, context->buffer);
-
-                       /* And set-up for the last transform: */
-                       MEMSET_BZERO((char *)context->buffer, SHA512_BLOCK_LENGTH - 2);
-               }
-       } else {
-               /* Prepare for final transform: */
-               MEMSET_BZERO((char *)context->buffer, SHA512_SHORT_BLOCK_LENGTH);
-
-               /* Begin padding with a 1 bit: */
-               *((char *)context->buffer) = 0x80;
-       }
-       /* Store the length of input data (in bits): */
-        MEMCPY_BCOPY(&((char *)context->buffer)[SHA512_SHORT_BLOCK_LENGTH], (char *)(&context->bitcount[1]), 8);
-        MEMCPY_BCOPY(&((char *)context->buffer)[SHA512_SHORT_BLOCK_LENGTH + 8], (char *)(&context->bitcount[0]), 8);
-
-       /* Final transform: */
-       SHA512_Transform(context, context->buffer);
-}
-
-void solv_SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
-       sha2_word64     *d = (sha2_word64*)digest;
-
-       /* Sanity check: */
-       /* assert(context != (SHA512_CTX*)0); */
-
-       /* If no digest buffer is passed, we don't bother doing this: */
-       if (digest != (sha2_byte*)0) {
-               SHA512_Last(context);
-
-               /* Save the hash data for output: */
-#ifndef WORDS_BIGENDIAN
-               {
-                       /* Convert TO host byte order */
-                       int     j;
-                       for (j = 0; j < 8; j++) {
-                               REVERSE64(context->state[j],context->state[j]);
-                               *d++ = context->state[j];
-                       }
-               }
-#else
-               MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
-#endif
-       }
-
-       /* Zero out state data */
-       MEMSET_BZERO(context, sizeof(*context));
-}
-
-
-/*** SHA-384: *********************************************************/
-void solv_SHA384_Init(SHA384_CTX* context) {
-       if (context == (SHA384_CTX*)0) {
-               return;
-       }
-       MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
-       MEMSET_BZERO((char *)context->buffer, SHA384_BLOCK_LENGTH);
-       context->bitcount[0] = context->bitcount[1] = 0;
-}
-
-void solv_SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
-       solv_SHA512_Update((SHA512_CTX*)context, data, len);
-}
-
-void solv_SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
-       sha2_word64     *d = (sha2_word64*)digest;
-
-       /* Sanity check: */
-       /* assert(context != (SHA384_CTX*)0); */
-
-       /* If no digest buffer is passed, we don't bother doing this: */
-       if (digest != (sha2_byte*)0) {
-               SHA512_Last((SHA512_CTX*)context);
-
-               /* Save the hash data for output: */
-#ifndef WORDS_BIGENDIAN
-               {
-                       /* Convert TO host byte order */
-                       int     j;
-                       for (j = 0; j < 6; j++) {
-                               REVERSE64(context->state[j],context->state[j]);
-                               *d++ = context->state[j];
-                       }
-               }
-#else
-               MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);
-#endif
-       }
-
-       /* Zero out state data */
-       MEMSET_BZERO(context, sizeof(*context));
-}
-
-
-/*** SHA-224: *********************************************************/
-
-void solv_SHA224_Init(SHA224_CTX* context) {
-       if (context == (SHA224_CTX*)0) {
-               return;
-       }
-       MEMCPY_BCOPY(context->state, sha224_initial_hash_value, SHA256_DIGEST_LENGTH);
-       MEMSET_BZERO((char *)context->buffer, SHA224_BLOCK_LENGTH);
-       context->bitcount = 0;
-}
-
-void solv_SHA224_Update(SHA224_CTX* context, const sha2_byte* data, size_t len) {
-       solv_SHA256_Update((SHA256_CTX*)context, data, len);
-}
-
-void solv_SHA224_Final(sha2_byte digest[], SHA224_CTX* context) {
-       sha2_word32     *d = (sha2_word32*)digest;
-
-       /* Sanity check: */
-       /* assert(context != (SHA224_CTX*)0); */
-
-       /* If no digest buffer is passed, we don't bother doing this: */
-       if (digest != (sha2_byte*)0) {
-               SHA256_Last(context);
-
-#ifndef WORDS_BIGENDIAN
-               {
-                       /* Convert TO host byte order */
-                       int     j;
-                       for (j = 0; j < 7; j++) {
-                               REVERSE32(context->state[j],context->state[j]);
-                               *d++ = context->state[j];
-                       }
-               }
-#else
-               MEMCPY_BCOPY(d, context->state, SHA224_DIGEST_LENGTH);
-#endif
-       }
-
-       /* Clean up state data: */
-       MEMSET_BZERO(context, sizeof(*context));
-}
diff --git a/libsolv-0.6.15/src/sha2.h b/libsolv-0.6.15/src/sha2.h
deleted file mode 100644 (file)
index 220af32..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * FILE:       sha2.h
- * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
- *
- * Copyright (c) 2000-2001, Aaron D. Gifford
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
- */
-
-#include <inttypes.h>
-
-
-/*** SHA-256/384/512 Various Length Definitions ***********************/
-#define SHA224_BLOCK_LENGTH            64
-#define SHA224_DIGEST_LENGTH           28
-#define SHA256_BLOCK_LENGTH            64
-#define SHA256_DIGEST_LENGTH           32
-#define SHA384_BLOCK_LENGTH            128
-#define SHA384_DIGEST_LENGTH           48
-#define SHA512_BLOCK_LENGTH            128
-#define SHA512_DIGEST_LENGTH           64
-
-
-/*** SHA-256/384/512 Context Structures *******************************/
-/* NOTE: If your architecture does not define either u_intXX_t types or
- * uintXX_t (from inttypes.h), you may need to define things by hand
- * for your system:
- */
-typedef struct _SHA256_CTX {
-       uint32_t        state[8];
-       uint64_t        bitcount;
-       uint32_t        buffer[SHA256_BLOCK_LENGTH/4];
-} SHA256_CTX;
-typedef struct _SHA512_CTX {
-       uint64_t        state[8];
-       uint64_t        bitcount[2];
-       uint64_t        buffer[SHA512_BLOCK_LENGTH/8];
-} SHA512_CTX;
-
-typedef SHA256_CTX SHA224_CTX;
-typedef SHA512_CTX SHA384_CTX;
-
-
-/*** SHA-224/256/384/512 Function Prototypes ******************************/
-void solv_SHA224_Init(SHA224_CTX *);
-void solv_SHA224_Update(SHA224_CTX*, const uint8_t*, size_t);
-void solv_SHA224_Final(uint8_t[SHA224_DIGEST_LENGTH], SHA224_CTX*);
-
-void solv_SHA256_Init(SHA256_CTX *);
-void solv_SHA256_Update(SHA256_CTX*, const uint8_t*, size_t);
-void solv_SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
-
-void solv_SHA384_Init(SHA384_CTX*);
-void solv_SHA384_Update(SHA384_CTX*, const uint8_t*, size_t);
-void solv_SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
-
-void solv_SHA512_Init(SHA512_CTX*);
-void solv_SHA512_Update(SHA512_CTX*, const uint8_t*, size_t);
-void solv_SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
diff --git a/libsolv-0.6.15/src/solvable.c b/libsolv-0.6.15/src/solvable.c
deleted file mode 100644 (file)
index cccc89d..0000000
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solvable.c
- *
- * set/retrieve data from solvables
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "util.h"
-#include "policy.h"
-#include "poolvendor.h"
-#include "chksum.h"
-#include "linkedpkg.h"
-
-const char *
-pool_solvable2str(Pool *pool, Solvable *s)
-{
-  const char *n, *e, *a;
-  int nl, el, al;
-  char *p;
-  n = pool_id2str(pool, s->name);
-  e = pool_id2str(pool, s->evr);
-  /* XXX: may want to skip the epoch here */
-  a = pool_id2str(pool, s->arch);
-  nl = strlen(n);
-  el = strlen(e);
-  al = strlen(a);
-  if (pool->havedistepoch)
-    {
-      /* strip the distepoch from the evr */
-      const char *de = strrchr(e, '-');
-      if (de && (de = strchr(de, ':')) != 0)
-       el = de - e;
-    }
-  p = pool_alloctmpspace(pool, nl + el + al + 3);
-  strcpy(p, n);
-  if (el)
-    {
-      p[nl++] = '-';
-      strncpy(p + nl, e, el);
-      p[nl + el] = 0;
-    }
-  if (al)
-    {
-      p[nl + el] = pool->disttype == DISTTYPE_HAIKU ? '-' : '.';
-      strcpy(p + nl + el + 1, a);
-    }
-  return p;
-}
-
-Id
-solvable_lookup_type(Solvable *s, Id keyname)
-{
-  if (!s->repo)
-    return 0;
-  return repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname);
-}
-
-Id
-solvable_lookup_id(Solvable *s, Id keyname)
-{
-  if (!s->repo)
-    return 0;
-  return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
-}
-
-int
-solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
-{
-  if (!s->repo)
-    {
-      queue_empty(q);
-      return 0;
-    }
-  return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
-}
-
-int
-solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
-{
-  if (!s->repo)
-    {
-      queue_empty(q);
-      return 0;
-    }
-  return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
-}
-
-static const char *
-solvable_lookup_str_joinarray(Solvable *s, Id keyname, const char *joinstr)
-{
-  Queue q;
-  Id qbuf[10];
-  char *str = 0;
-
-  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  if (solvable_lookup_idarray(s, keyname, &q) && q.count)
-    {
-      Pool *pool = s->repo->pool;
-      int i;
-      str = pool_tmpjoin(pool, pool_id2str(pool, q.elements[0]), 0, 0);
-      for (i = 1; i < q.count; i++)
-       str = pool_tmpappend(pool, str, joinstr, pool_id2str(pool, q.elements[i]));
-    }
-  queue_free(&q);
-  return str;
-}
-
-const char *
-solvable_lookup_str(Solvable *s, Id keyname)
-{
-  const char *str;
-  if (!s->repo)
-    return 0;
-  str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
-  if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP))
-    str = solvable_lookup_str_joinarray(s, keyname, ", ");
-  return str;
-}
-
-static const char *
-solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
-{
-  Pool *pool;
-  const char *str, *basestr;
-  Id p, pp, name;
-  Solvable *s2;
-  int pass;
-
-  if (!s->repo)
-    return 0;
-  pool = s->repo->pool;
-  str = solvable_lookup_str(s, keyname);
-  if (str || keyname == basekeyname)
-    return str;
-  basestr = solvable_lookup_str(s, basekeyname);
-  if (!basestr)
-    return 0;
-  /* search for a solvable with same name and same base that has the
-   * translation */
-  if (!pool->whatprovides)
-    return usebase ? basestr : 0;
-  name = s->name;
-  /* we do this in two passes, first same vendor, then all other vendors */
-  for (pass = 0; pass < 2; pass++)
-    {
-      FOR_PROVIDES(p, pp, name)
-       {
-         s2 = pool->solvables + p;
-         if (s2->name != name)
-           continue;
-         if ((s->vendor == s2->vendor) != (pass == 0))
-           continue;
-         str = solvable_lookup_str(s2, basekeyname);
-         if (!str || strcmp(str, basestr))
-           continue;
-         str = solvable_lookup_str(s2, keyname);
-         if (str)
-           return str;
-       }
-#ifdef ENABLE_LINKED_PKGS
-      /* autopattern/product translation magic */
-      if (pass)
-       {
-         const char *n = pool_id2str(pool, name);
-         if (*n == 'p')
-           {
-             if (!strncmp("pattern:", n, 8) && (name = find_autopattern_name(pool, s)) != 0)
-               pass = -1;
-             if (!strncmp("product:", n, 8) && (name = find_autoproduct_name(pool, s)) != 0)
-               pass = -1;
-           }
-       }
-#endif
-    }
-  return usebase ? basestr : 0;
-}
-
-const char *
-solvable_lookup_str_poollang(Solvable *s, Id keyname)
-{
-  Pool *pool;
-  int i, cols;
-  const char *str;
-  Id *row;
-
-  if (!s->repo)
-    return 0;
-  pool = s->repo->pool;
-  if (!pool->nlanguages)
-    return solvable_lookup_str(s, keyname);
-  cols = pool->nlanguages + 1;
-  if (!pool->languagecache)
-    {
-      pool->languagecache = solv_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
-      pool->languagecacheother = 0;
-    }
-  if (keyname >= ID_NUM_INTERNAL)
-    {
-      row = pool->languagecache + ID_NUM_INTERNAL * cols;
-      for (i = 0; i < pool->languagecacheother; i++, row += cols)
-       if (*row == keyname)
-         break;
-      if (i >= pool->languagecacheother)
-       {
-         pool->languagecache = solv_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
-         row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
-         *row = keyname;
-       }
-    }
-  else
-    row = pool->languagecache + keyname * cols;
-  row++;       /* skip keyname */
-  for (i = 0; i < pool->nlanguages; i++, row++)
-    {
-      if (!*row)
-        *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
-      str = solvable_lookup_str_base(s, *row, keyname, 0);
-      if (str)
-       return str;
-    }
-  return solvable_lookup_str(s, keyname);
-}
-
-const char *
-solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
-{
-  if (s->repo)
-    {
-      Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
-      if (id)
-        return solvable_lookup_str_base(s, id, keyname, usebase);
-      if (!usebase)
-       return 0;
-    }
-  return solvable_lookup_str(s, keyname);
-}
-
-unsigned long long
-solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
-{
-  if (!s->repo)
-    return notfound;
-  return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
-}
-
-unsigned int
-solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound)
-{
-  unsigned long long size;
-  if (!s->repo)
-    return notfound;
-  size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10);
-  return (unsigned int)((size + 1023) >> 10);
-}
-
-int
-solvable_lookup_void(Solvable *s, Id keyname)
-{
-  if (!s->repo)
-    return 0;
-  return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
-}
-
-int
-solvable_lookup_bool(Solvable *s, Id keyname)
-{
-  if (!s->repo)
-    return 0;
-  /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
-  if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
-    return 1;
-  return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
-}
-
-const unsigned char *
-solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
-{
-  Repo *repo = s->repo;
-
-  if (!repo)
-    {
-      *typep = 0;
-      return 0;
-    }
-  return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
-}
-
-const char *
-solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
-{
-  const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
-  return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
-}
-
-static inline const char *
-evrid2vrstr(Pool *pool, Id evrid)
-{
-  const char *p, *evr = pool_id2str(pool, evrid);
-  if (!evr)
-    return evr;
-  for (p = evr; *p >= '0' && *p <= '9'; p++)
-    ;
-  return p != evr && *p == ':' && p[1] ? p + 1 : evr;
-}
-
-const char *
-solvable_lookup_location(Solvable *s, unsigned int *medianrp)
-{
-  Pool *pool;
-  int l = 0;
-  char *loc;
-  const char *mediadir, *mediafile;
-
-  if (medianrp)
-    *medianrp = 0;
-  if (!s->repo)
-    return 0;
-  pool = s->repo->pool;
-  if (medianrp)
-    *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0);
-  if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
-    mediadir = pool_id2str(pool, s->arch);
-  else
-    mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
-  if (mediadir)
-    l = strlen(mediadir) + 1;
-  if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
-    {
-      const char *name, *evr, *arch;
-      name = pool_id2str(pool, s->name);
-      evr = evrid2vrstr(pool, s->evr);
-      arch = pool_id2str(pool, s->arch);
-      /* name-vr.arch.rpm */
-      loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
-      if (mediadir)
-       sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
-      else
-       sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
-    }
-  else
-    {
-      mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
-      if (!mediafile)
-       return 0;
-      loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
-      if (mediadir)
-       sprintf(loc, "%s/%s", mediadir, mediafile);
-      else
-       strcpy(loc, mediafile);
-    }
-  return loc;
-}
-
-const char *
-solvable_get_location(Solvable *s, unsigned int *medianrp)
-{
-  const char *loc = solvable_lookup_location(s, medianrp);
-  if (medianrp && *medianrp == 0)
-    *medianrp = 1;     /* compat, to be removed */
-  return loc;
-}
-
-const char *
-solvable_lookup_sourcepkg(Solvable *s)
-{
-  Pool *pool;
-  const char *evr, *name;
-  Id archid;
-
-  if (!s->repo)
-    return 0;
-  pool = s->repo->pool;
-  if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
-    name = pool_id2str(pool, s->name);
-  else
-    name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
-  if (!name)
-    return 0;
-  archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH);
-  if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
-    evr = evrid2vrstr(pool, s->evr);
-  else
-    evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
-  if (archid == ARCH_SRC || archid == ARCH_NOSRC)
-    {
-      char *str;
-      str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr);
-      str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid));
-      return pool_tmpappend(pool, str, ".rpm", 0);
-    }
-  else
-    return name;       /* FIXME */
-}
-
-
-/*****************************************************************************/
-
-static inline Id dep2name(Pool *pool, Id dep)
-{
-  while (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      dep = rd->name;
-    }
-  return dep;
-}
-
-static int providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con)
-{
-  Id p, pp;
-  Solvable *sn = pool->solvables + n;
-
-  FOR_PROVIDES(p, pp, sn->name)
-    {
-      Solvable *s = pool->solvables + p;
-      if (s->name != sn->name || s->arch != sn->arch)
-        continue;
-      if (!MAPTST(installed, p))
-        continue;
-      if (pool_match_nevr(pool, pool->solvables + p, con))
-        continue;
-      return 1;         /* found installed package that doesn't conflict */
-    }
-  return 0;
-}
-
-static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *multiversionmap)
-{
-  Id p, pp;
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (p == SYSTEMSOLVABLE)
-       return -1;
-      if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
-       continue;
-      if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
-       if (providedbyinstalled_multiversion(pool, installed, p, dep))
-         continue;
-      if (MAPTST(installed, p))
-       return 1;
-    }
-  return 0;
-}
-
-/*
- * solvable_trivial_installable_map - anwers is a solvable is installable
- * without any other installs/deinstalls.
- * The packages considered to be installed are provided via the
- * installedmap bitmap. A additional "conflictsmap" bitmap providing
- * information about the conflicts of the installed packages can be
- * used for extra speed up. Provide a NULL pointer if you do not
- * have this information.
- * Both maps can be created with pool_create_state_maps() or
- * solver_create_state_maps().
- *
- * returns:
- * 1:  solvable is installable without any other package changes
- * 0:  solvable is not installable
- * -1: solvable is installable, but doesn't constrain any installed packages
- */
-int
-solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap)
-{
-  Pool *pool = s->repo->pool;
-  Solvable *s2;
-  Id p, *dp;
-  Id *reqp, req;
-  Id *conp, con;
-  int r, interesting = 0;
-
-  if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
-    return 0;
-  if (s->requires)
-    {
-      reqp = s->repo->idarraydata + s->requires;
-      while ((req = *reqp++) != 0)
-       {
-         if (req == SOLVABLE_PREREQMARKER)
-           continue;
-          r = providedbyinstalled(pool, installedmap, req, 0, 0);
-         if (!r)
-           return 0;
-         if (r > 0)
-           interesting = 1;
-       }
-    }
-  if (s->conflicts)
-    {
-      int ispatch = 0;
-
-      if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
-       ispatch = 1;
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-       {
-         if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
-           {
-             if (ispatch && solvable_is_irrelevant_patch(s, installedmap))
-               return -1;
-             return 0;
-           }
-         if (!interesting && ISRELDEP(con))
-           {
-              con = dep2name(pool, con);
-             if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
-               interesting = 1;
-           }
-       }
-      if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap))
-       interesting = 0;
-    }
-#if 0
-  if (s->repo)
-    {
-      Id *obsp, obs;
-      Repo *installed = 0;
-      if (s->obsoletes && s->repo != installed)
-       {
-         obsp = s->repo->idarraydata + s->obsoletes;
-         while ((obs = *obsp++) != 0)
-           {
-             if (providedbyinstalled(pool, installedmap, obs, 0, 0))
-               return 0;
-           }
-       }
-      if (s->repo != installed)
-       {
-         Id pp;
-         FOR_PROVIDES(p, pp, s->name)
-           {
-             s2 = pool->solvables + p;
-             if (s2->repo == installed && s2->name == s->name)
-               return 0;
-           }
-       }
-    }
-#endif
-  if (!conflictsmap)
-    {
-      int i;
-
-      p = s - pool->solvables;
-      for (i = 1; i < pool->nsolvables; i++)
-       {
-         if (!MAPTST(installedmap, i))
-           continue;
-         s2 = pool->solvables + i;
-         if (!s2->conflicts)
-           continue;
-         conp = s2->repo->idarraydata + s2->conflicts;
-         while ((con = *conp++) != 0)
-           {
-             dp = pool_whatprovides_ptr(pool, con);
-             for (; *dp; dp++)
-               if (*dp == p)
-                 return 0;
-           }
-       }
-     }
-  return interesting ? 1 : -1;
-}
-
-/*
- * different interface for solvable_trivial_installable_map, where
- * the information about the installed packages is provided
- * by a queue.
- */
-int
-solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap)
-{
-  Pool *pool = s->repo->pool;
-  int i;
-  Id p;
-  Map installedmap;
-  int r;
-
-  map_init(&installedmap, pool->nsolvables);
-  for (i = 0; i < installed->count; i++)
-    {
-      p = installed->elements[i];
-      if (p > 0)               /* makes it work with decisionq */
-       MAPSET(&installedmap, p);
-    }
-  r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
-  map_free(&installedmap);
-  return r;
-}
-
-/*
- * different interface for solvable_trivial_installable_map, where
- * the information about the installed packages is provided
- * by a repo containing the installed solvables.
- */
-int
-solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *multiversionmap)
-{
-  Pool *pool = s->repo->pool;
-  Id p;
-  Solvable *s2;
-  Map installedmap;
-  int r;
-
-  map_init(&installedmap, pool->nsolvables);
-  FOR_REPO_SOLVABLES(installed, p, s2)
-    MAPSET(&installedmap, p);
-  r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
-  map_free(&installedmap);
-  return r;
-}
-
-/* FIXME: this mirrors policy_illegal_vendorchange */
-static int
-pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
-{
-  Id v1, v2;
-  Id vendormask1, vendormask2;
-
-  if (pool->custom_vendorcheck)
-    return pool->custom_vendorcheck(pool, s1, s2);
-  /* treat a missing vendor as empty string */
-  v1 = s1->vendor ? s1->vendor : ID_EMPTY;
-  v2 = s2->vendor ? s2->vendor : ID_EMPTY;
-  if (v1 == v2)
-    return 0;
-  vendormask1 = pool_vendor2mask(pool, v1);
-  if (!vendormask1)
-    return 1;   /* can't match */
-  vendormask2 = pool_vendor2mask(pool, v2);
-  if ((vendormask1 & vendormask2) != 0)
-    return 0;
-  return 1;     /* no class matches */
-}
-
-/* check if this patch is relevant according to the vendor. To bad that patches
- * don't have a vendor, so we need to do some careful repo testing. */
-int
-solvable_is_irrelevant_patch(Solvable *s, Map *installedmap)
-{
-  Pool *pool = s->repo->pool;
-  Id con, *conp;
-  int hadpatchpackage = 0;
-
-  if (!s->conflicts)
-    return 0;
-  conp = s->repo->idarraydata + s->conflicts;
-  while ((con = *conp++) != 0)
-    {
-      Reldep *rd;
-      Id p, pp, p2, pp2;
-      if (!ISRELDEP(con))
-       continue;
-      rd = GETRELDEP(pool, con);
-      if (rd->flags != REL_LT)
-       continue;
-      FOR_PROVIDES(p, pp, con)
-       {
-         Solvable *si;
-         if (!MAPTST(installedmap, p))
-           continue;
-         si = pool->solvables + p;
-         if (!pool_match_nevr(pool, si, con))
-           continue;
-         FOR_PROVIDES(p2, pp2, rd->name)
-           {
-             Solvable *s2 = pool->solvables + p2;
-             if (!pool_match_nevr(pool, s2, rd->name))
-               continue;
-             if (pool_match_nevr(pool, s2, con))
-               continue;       /* does not fulfill patch */
-             if (s2->repo == s->repo)
-               {
-                 hadpatchpackage = 1;
-                 /* ok, we have a package from the patch repo that solves the conflict. check vendor */
-                 if (si->vendor == s2->vendor)
-                   return 0;
-                 if (!pool_illegal_vendorchange(pool, si, s2))
-                   return 0;
-                 /* vendor change was illegal, ignore conflict */
-               }
-           }
-       }
-    }
-  /* if we didn't find a patchpackage don't claim that the patch is irrelevant */
-  if (!hadpatchpackage)
-    return 0;
-  return 1;
-}
-
-/*****************************************************************************/
-
-/*
- * Create maps containing the state of each solvable. Input is a "installed" queue,
- * it contains all solvable ids that are considered to be installed.
- *
- * The created maps can be used for solvable_trivial_installable_map(),
- * pool_calc_duchanges(), pool_calc_installsizechange().
- *
- */
-void
-pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
-{
-  int i;
-  Solvable *s;
-  Id p, *dp;
-  Id *conp, con;
-
-  map_init(installedmap, pool->nsolvables);
-  if (conflictsmap)
-    map_init(conflictsmap, pool->nsolvables);
-  for (i = 0; i < installed->count; i++)
-    {
-      p = installed->elements[i];
-      if (p <= 0)      /* makes it work with decisionq */
-       continue;
-      MAPSET(installedmap, p);
-      if (!conflictsmap)
-       continue;
-      s = pool->solvables + p;
-      if (!s->conflicts)
-       continue;
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-       {
-         dp = pool_whatprovides_ptr(pool, con);
-         for (; *dp; dp++)
-           MAPSET(conflictsmap, *dp);
-       }
-    }
-}
-
-/* Tests if two solvables have identical content. Currently
- * both solvables need to come from the same pool
- */
-
-int
-solvable_identical(Solvable *s1, Solvable *s2)
-{
-  unsigned int bt1, bt2;
-  Id rq1, rq2;
-  Id *reqp;
-  if (s1->name != s2->name)
-    return 0;
-  if (s1->arch != s2->arch)
-    return 0;
-  if (s1->evr != s2->evr)
-    return 0;
-
-  /* check vendor, map missing vendor to empty string */
-  if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
-    {
-      /* workaround for bug 881493 */
-      if (s1->repo && !strncmp(pool_id2str(s1->repo->pool, s1->name), "product:", 8))
-       return 1;
-      return 0;
-    }
-
-  /* looking good, try some fancier stuff */
-  /* might also look up the package checksum here */
-  bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
-  bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
-  if (bt1 && bt2)
-    {
-      if (bt1 != bt2)
-        return 0;
-    }
-  else
-    {
-      if (s1->repo)
-       {
-          /* workaround for bugs 881493 and 885830*/
-         const char *n = pool_id2str(s1->repo->pool, s1->name);
-         if (!strncmp(n, "product:", 8) || !strncmp(n, "application:", 12))
-           return 1;
-       }
-      /* look at requires in a last attempt to find recompiled packages */
-      rq1 = rq2 = 0;
-      if (s1->requires)
-       for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
-         rq1 ^= *reqp;
-      if (s2->requires)
-       for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
-         rq2 ^= *reqp;
-      if (rq1 != rq2)
-        return 0;
-    }
-  return 1;
-}
-
-/* return the self provide dependency of a solvable */
-Id
-solvable_selfprovidedep(Solvable *s)
-{
-  Pool *pool;
-  Reldep *rd;
-  Id prov, *provp;
-
-  if (!s->repo)
-    return s->name;
-  pool = s->repo->pool;
-  if (s->provides)
-    {
-      provp = s->repo->idarraydata + s->provides;
-      while ((prov = *provp++) != 0)
-       {
-         if (!ISRELDEP(prov))
-           continue;
-         rd = GETRELDEP(pool, prov);
-         if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
-           return prov;
-       }
-    }
-  return pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
-}
-
-/* setter functions, simply call the repo variants */
-void
-solvable_set_id(Solvable *s, Id keyname, Id id)
-{
-  repo_set_id(s->repo, s - s->repo->pool->solvables, keyname, id);
-}
-
-void
-solvable_set_num(Solvable *s, Id keyname, unsigned long long num)
-{
-  repo_set_num(s->repo, s - s->repo->pool->solvables, keyname, num);
-}
-
-void
-solvable_set_str(Solvable *s, Id keyname, const char *str)
-{
-  repo_set_str(s->repo, s - s->repo->pool->solvables, keyname, str);
-}
-
-void
-solvable_set_poolstr(Solvable *s, Id keyname, const char *str)
-{
-  repo_set_poolstr(s->repo, s - s->repo->pool->solvables, keyname, str);
-}
-
-void
-solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str)
-{
-  repo_add_poolstr_array(s->repo, s - s->repo->pool->solvables, keyname, str);
-}
-
-void
-solvable_add_idarray(Solvable *s, Id keyname, Id id)
-{
-  repo_add_idarray(s->repo, s - s->repo->pool->solvables, keyname, id);
-}
-
-void
-solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker)
-{
-  repo_add_deparray(s->repo, s - s->repo->pool->solvables, keyname, dep, marker);
-}
-
-void
-solvable_set_idarray(Solvable *s, Id keyname, Queue *q)
-{
-  repo_set_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
-}
-
-void
-solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
-{
-  repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
-}
-
-void
-solvable_unset(Solvable *s, Id keyname)
-{
-  repo_unset(s->repo, s - s->repo->pool->solvables, keyname);
-}
-
-/* return true if a dependency intersects dep in the keyname array */
-int
-solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker)
-{
-  int i;
-  Pool *pool = s->repo->pool;
-  Queue q;
-  queue_init(&q);
-  solvable_lookup_deparray(s, keyname, &q, marker);
-  for (i = 0; i < q.count; i++)
-    if (pool_match_dep(pool, q.elements[i], dep))
-      break;
-  i = i == q.count ? 0 : 1;
-  queue_free(&q);
-  return i;
-}
diff --git a/libsolv-0.6.15/src/solvable.h b/libsolv-0.6.15/src/solvable.h
deleted file mode 100644 (file)
index 85d20c4..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2007-2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solvable.h
- *
- * A solvable represents an object with name-epoch:version-release.arch
- * and dependencies
- */
-
-#ifndef LIBSOLV_SOLVABLE_H
-#define LIBSOLV_SOLVABLE_H
-
-#include "pooltypes.h"
-#include "queue.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _Repo;
-
-typedef struct _Solvable {
-  Id name;
-  Id arch;
-  Id evr;                      /* epoch:version-release */
-  Id vendor;
-
-  struct _Repo *repo;          /* repo we belong to */
-
-  /* dependencies are offsets into repo->idarraydata */
-  Offset provides;             /* terminated with Id 0 */
-  Offset obsoletes;
-  Offset conflicts;
-
-  Offset requires;
-  Offset recommends;
-  Offset suggests;
-
-  Offset supplements;
-  Offset enhances;
-
-} Solvable;
-
-/* lookup functions */
-Id solvable_lookup_type(Solvable *s, Id keyname);
-Id solvable_lookup_id(Solvable *s, Id keyname);
-unsigned long long solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound);
-unsigned int solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound);
-const char *solvable_lookup_str(Solvable *s, Id keyname);
-const char *solvable_lookup_str_poollang(Solvable *s, Id keyname);
-const char *solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase);
-int solvable_lookup_bool(Solvable *s, Id keyname);
-int solvable_lookup_void(Solvable *s, Id keyname);
-const char *solvable_get_location(Solvable *s, unsigned int *medianrp);        /* old name */
-const char *solvable_lookup_location(Solvable *s, unsigned int *medianrp);
-const char *solvable_lookup_sourcepkg(Solvable *s);
-const unsigned char *solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep);
-const char *solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep);
-int solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q);
-int solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker);
-
-/* setter functions */
-void solvable_set_id(Solvable *s, Id keyname, Id id);
-void solvable_set_num(Solvable *s, Id keyname, unsigned long long num);
-void solvable_set_str(Solvable *s, Id keyname, const char *str);
-void solvable_set_poolstr(Solvable *s, Id keyname, const char *str);
-void solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str);
-void solvable_add_idarray(Solvable *s, Id keyname, Id id);
-void solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker);
-void solvable_set_idarray(Solvable *s, Id keyname, Queue *q);
-void solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker);
-void solvable_unset(Solvable *s, Id keyname);
-
-int solvable_identical(Solvable *s1, Solvable *s2);
-Id solvable_selfprovidedep(Solvable *s);
-int solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_SOLVABLE_H */
diff --git a/libsolv-0.6.15/src/solver.c b/libsolv-0.6.15/src/solver.c
deleted file mode 100644 (file)
index 2e28b7d..0000000
+++ /dev/null
@@ -1,5238 +0,0 @@
-/*
- * Copyright (c) 2007-2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solver.c
- *
- * SAT based dependency solver
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "solver.h"
-#include "solver_private.h"
-#include "bitmap.h"
-#include "pool.h"
-#include "util.h"
-#include "policy.h"
-#include "poolarch.h"
-#include "solverdebug.h"
-#include "cplxdeps.h"
-#include "linkedpkg.h"
-
-#define RULES_BLOCK 63
-
-
-/********************************************************************
- *
- * dependency check helpers
- *
- */
-
-/*-------------------------------------------------------------------
- * handle split provides
- *
- * a splitprovides dep looks like
- *     namespace:splitprovides(pkg REL_WITH path)
- * and is only true if pkg is installed and contains the specified path.
- * we also make sure that pkg is selected for an update, otherwise the
- * update would always be forced onto the user.
- * Map m is the map used when called from dep_possible.
- */
-
-static int
-solver_is_updating(Solver *solv, Id p)
-{
-  /* check if the update rule is true */
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id l, pp;
-  if (solv->decisionmap[p] >= 0)
-    return 0;  /* old package stayed */
-  r = solv->rules + solv->updaterules + (p - solv->installed->start);
-  FOR_RULELITERALS(l, pp, r)
-    if (l > 0 && l != p && solv->decisionmap[l] > 0)
-      return 1;
-  return 0;
-}
-
-int
-solver_splitprovides(Solver *solv, Id dep, Map *m)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  Reldep *rd;
-  Solvable *s;
-
-  if (!solv->dosplitprovides || !solv->installed)
-    return 0;
-  if (!ISRELDEP(dep))
-    return 0;
-  rd = GETRELDEP(pool, dep);
-  if (rd->flags != REL_WITH)
-    return 0;
-  /*
-   * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
-   * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
-   * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
-   * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
-   * we filter the package name further down anyway).
-   */
-  if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
-    pp = pool_searchlazywhatprovidesq(pool, rd->evr);
-  else
-    pp = pool_whatprovides(pool, dep);
-  while ((p = pool->whatprovidesdata[pp++]) != 0)
-    {
-      /* here we have packages that provide the correct name and contain the path,
-       * now do extra filtering */
-      s = pool->solvables + p;
-      if (s->repo != solv->installed || s->name != rd->name)
-       continue;
-      /* check if the package is updated. if m is set, we're called from dep_possible */
-      if (m || solver_is_updating(solv, p))
-       return 1;
-    }
-  return 0;
-}
-
-
-/* mirrors solver_dep_fulfilled, but returns 2 if a new package
- * was involved */
-static int
-solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-  int r;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
-       {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
-               }
-           }
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_AND)
-        {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-          if (!r1)
-            return 0;
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
-        }
-      if (rd->flags == REL_OR)
-       {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-        return solver_splitprovides(solv, rd->evr, 0);
-      if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
-       {
-         Queue *q = solv->installsuppdepq;
-         int i;
-         for (i = 0; i < q->count; i++)
-           if (q->elements[i] == dep || q->elements[i] == rd->name)
-             return 2;
-       }
-    }
-  r = 0;
-  FOR_PROVIDES(p, pp, dep)
-    if (solv->decisionmap[p] > 0)
-      {
-       Solvable *s = pool->solvables + p;
-       if (s->repo && s->repo != solv->installed)
-         return 2;
-        r = 1;
-      }
-  return r;
-}
-
-static int
-solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
-{
-  Id sup, *supp;
-  supp = s->repo->idarraydata + s->supplements;
-  while ((sup = *supp++) != 0)
-    if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
-      return 1;
-  return 0;
-}
-
-static Id
-autouninstall(Solver *solv, Id *problem)
-{
-  Pool *pool = solv->pool;
-  int i;
-  int lastfeature = 0, lastupdate = 0;
-  Id v;
-  Id extraflags = -1;
-  Map *m = 0;
-
-  if (!solv->allowuninstall && !solv->allowuninstall_all)
-    {
-      if (!solv->allowuninstallmap.size)
-       return 0;               /* why did we get called? */
-      m = &solv->allowuninstallmap;
-    }
-  for (i = 0; (v = problem[i]) != 0; i++)
-    {
-      if (v < 0)
-       extraflags &= solv->job.elements[-v - 1];
-      if (v >= solv->updaterules && v < solv->updaterules_end)
-       {
-         Rule *r;
-         if (m && !MAPTST(m, v - solv->updaterules))
-           continue;
-         /* check if identical to feature rule, we don't like that (except for orphans) */
-         r = solv->rules + solv->featurerules + (v - solv->updaterules);
-         if (!r->p)
-           {
-             /* update rule == feature rule */
-             if (v > lastfeature)
-               lastfeature = v;
-             /* prefer orphaned packages in dup mode */
-             if (solv->keep_orphans)
-               {
-                 r = solv->rules + v;
-                 if (!r->d && r->p == (solv->installed->start + (v - solv->updaterules)))
-                   {
-                     lastfeature = v;
-                     lastupdate = 0;
-                     break;
-                   }
-               }
-             continue;
-           }
-         if (v > lastupdate)
-           lastupdate = v;
-       }
-    }
-  if (!lastupdate && !lastfeature)
-    return 0;
-  v = lastupdate ? lastupdate : lastfeature;
-  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
-  solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
-  solver_disableproblem(solv, v);
-  if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
-    {
-      /* add the package to the updatepkgs list, this will automatically turn
-       * on cleandeps mode */
-      Id p = solv->rules[v].p;
-      if (!solv->cleandeps_updatepkgs)
-       {
-         solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
-         queue_init(solv->cleandeps_updatepkgs);
-       }
-      if (p > 0)
-       {
-         int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
-          queue_pushunique(solv->cleandeps_updatepkgs, p);
-         if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
-           solver_disablepolicyrules(solv);
-       }
-    }
-  return v;
-}
-
-/************************************************************************/
-
-/*
- * enable/disable learnt rules
- *
- * we have enabled or disabled some of our rules. We now reenable all
- * of our learnt rules except the ones that were learnt from rules that
- * are now disabled.
- */
-static void
-enabledisablelearntrules(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id why, *whyp;
-  int i;
-
-  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
-  for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
-    {
-      whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
-      while ((why = *whyp++) != 0)
-       {
-         assert(why > 0 && why < i);
-         if (solv->rules[why].d < 0)
-           break;
-       }
-      /* why != 0: we found a disabled rule, disable the learnt rule */
-      if (why && r->d >= 0)
-       {
-         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
-             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
-           }
-          solver_disablerule(solv, r);
-       }
-      else if (!why && r->d < 0)
-       {
-         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
-           {
-             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
-             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
-           }
-          solver_enablerule(solv, r);
-       }
-    }
-}
-
-
-/*
- * make assertion rules into decisions
- *
- * Go through rules and add direct assertions to the decisionqueue.
- * If we find a conflict, disable rules and add them to problem queue.
- */
-
-static void
-makeruledecisions(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  int i, ri, ii;
-  Rule *r, *rr;
-  Id v, vv;
-  int decisionstart;
-  int record_proof = 1;
-  int oldproblemcount;
-  int havedisabled = 0;
-
-  /* The system solvable is always installed first */
-  assert(solv->decisionq.count == 0);
-  queue_push(&solv->decisionq, SYSTEMSOLVABLE);
-  queue_push(&solv->decisionq_why, 0);
-  solv->decisionmap[SYSTEMSOLVABLE] = 1;       /* installed at level '1' */
-
-  decisionstart = solv->decisionq.count;
-  for (;;)
-    {
-      /* if we needed to re-run, back up decisions to decisionstart */
-      while (solv->decisionq.count > decisionstart)
-       {
-         v = solv->decisionq.elements[--solv->decisionq.count];
-         --solv->decisionq_why.count;
-         vv = v > 0 ? v : -v;
-         solv->decisionmap[vv] = 0;
-       }
-
-      /* note that the ruleassertions queue is ordered */
-      for (ii = 0; ii < solv->ruleassertions.count; ii++)
-       {
-         ri = solv->ruleassertions.elements[ii];
-         r = solv->rules + ri;
-
-          if (havedisabled && ri >= solv->learntrules)
-           {
-             /* just started with learnt rule assertions. If we have disabled
-               * some rules, adapt the learnt rule status */
-             enabledisablelearntrules(solv);
-             havedisabled = 0;
-           }
-
-         if (r->d < 0 || !r->p || r->w2)       /* disabled, dummy or no assertion */
-           continue;
-
-         /* do weak rules in phase 2 */
-         if (ri < solv->learntrules && solv->weakrulemap.size && MAPTST(&solv->weakrulemap, ri))
-           continue;
-
-         v = r->p;
-         vv = v > 0 ? v : -v;
-
-         if (!solv->decisionmap[vv])          /* if not yet decided */
-           {
-             queue_push(&solv->decisionq, v);
-             queue_push(&solv->decisionq_why, r - solv->rules);
-             solv->decisionmap[vv] = v > 0 ? 1 : -1;
-             IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-               {
-                 Solvable *s = solv->pool->solvables + vv;
-                 if (v < 0)
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
-                 else
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
-               }
-             continue;
-           }
-
-         /* check against previous decision: is there a conflict? */
-         if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
-           continue;
-         if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
-           continue;
-
-         /*
-          * found a conflict!
-          *
-          * The rule (r) we're currently processing says something
-          * different (v = r->p) than a previous decision (decisionmap[abs(v)])
-          * on this literal
-          */
-
-         if (ri >= solv->learntrules)
-           {
-             /* conflict with a learnt rule */
-             /* can happen when packages cannot be installed for multiple reasons. */
-             /* we disable the learnt rule in this case */
-             /* (XXX: we should really call analyze_unsolvable_rule here!) */
-             solver_disablerule(solv, r);
-             continue;
-           }
-
-         /*
-          * find the decision which is the "opposite" of the rule
-          */
-         for (i = 0; i < solv->decisionq.count; i++)
-           if (solv->decisionq.elements[i] == -v)
-             break;
-         assert(i < solv->decisionq.count);         /* assert that we found it */
-         oldproblemcount = solv->problems.count;
-
-         /*
-          * conflict with system solvable ?
-          */
-         if (v == -SYSTEMSOLVABLE)
-           {
-             if (record_proof)
-               {
-                 queue_push(&solv->problems, solv->learnt_pool.count);
-                 queue_push(&solv->learnt_pool, ri);
-                 queue_push(&solv->learnt_pool, 0);
-               }
-             else
-               queue_push(&solv->problems, 0);
-             POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
-             if  (ri >= solv->jobrules && ri < solv->jobrules_end)
-               v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
-             else
-               v = ri;
-             queue_push(&solv->problems, v);
-             queue_push(&solv->problems, 0);
-             if (v >= solv->featurerules && v < solv->updaterules_end)
-               {
-                 if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
-                   if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
-                     {
-                       solv->problems.count = oldproblemcount;
-                       havedisabled = 1;
-                       break;  /* start over */
-                     }
-               }
-             solver_disableproblem(solv, v);
-             havedisabled = 1;
-             break;    /* start over */
-           }
-
-         assert(solv->decisionq_why.elements[i] > 0);
-
-         /*
-          * conflict with a pkg rule ?
-          */
-         if (solv->decisionq_why.elements[i] < solv->pkgrules_end)
-           {
-             if (record_proof)
-               {
-                 queue_push(&solv->problems, solv->learnt_pool.count);
-                 queue_push(&solv->learnt_pool, ri);
-                 queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
-                 queue_push(&solv->learnt_pool, 0);
-               }
-             else
-               queue_push(&solv->problems, 0);
-             assert(v > 0 || v == -SYSTEMSOLVABLE);
-             POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
-             if (ri >= solv->jobrules && ri < solv->jobrules_end)
-               v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
-             else
-               v = ri;
-             queue_push(&solv->problems, v);
-             queue_push(&solv->problems, 0);
-             if (v >= solv->featurerules && v < solv->updaterules_end)
-               {
-                 if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
-                   if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
-                     {
-                       solv->problems.count = oldproblemcount;
-                       havedisabled = 1;
-                       break;  /* start over */
-                     }
-               }
-             solver_disableproblem(solv, v);
-             havedisabled = 1;
-             break;    /* start over */
-           }
-
-         /*
-          * conflict with another job or update/feature rule
-          */
-
-         /* record proof */
-         if (record_proof)
-           {
-             queue_push(&solv->problems, solv->learnt_pool.count);
-             queue_push(&solv->learnt_pool, ri);
-             queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
-             queue_push(&solv->learnt_pool, 0);
-           }
-         else
-           queue_push(&solv->problems, 0);
-
-         POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
-
-         /*
-          * push all of our rules (can only be feature or job rules)
-          * asserting this literal on the problem stack
-          */
-         for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
-           {
-             if (rr->d < 0                          /* disabled */
-                 || rr->w2)                         /*  or no assertion */
-               continue;
-             if (rr->p != vv                        /* not affecting the literal */
-                 && rr->p != -vv)
-               continue;
-             if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
-               continue;
-               
-             POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
-             solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
-               
-             v = i;
-             if (i >= solv->jobrules && i < solv->jobrules_end)
-               v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
-             queue_push(&solv->problems, v);
-           }
-         queue_push(&solv->problems, 0);
-
-         if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
-           if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
-             {
-               solv->problems.count = oldproblemcount;
-               havedisabled = 1;
-               break;  /* start over */
-             }
-
-         for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
-           solver_disableproblem(solv, solv->problems.elements[i]);
-         havedisabled = 1;
-         break;        /* start over */
-       }
-      if (ii < solv->ruleassertions.count)
-       continue;
-
-      /*
-       * phase 2: now do the weak assertions
-       */
-      if (!solv->weakrulemap.size)
-       break;                          /* no weak rules, no phase 2 */
-      for (ii = 0; ii < solv->ruleassertions.count; ii++)
-       {
-         ri = solv->ruleassertions.elements[ii];
-         r = solv->rules + ri;
-         if (r->d < 0 || r->w2)                         /* disabled or no assertion */
-           continue;
-         if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
-           continue;
-         v = r->p;
-         vv = v > 0 ? v : -v;
-
-         if (!solv->decisionmap[vv])          /* if not yet decided */
-           {
-             queue_push(&solv->decisionq, v);
-             queue_push(&solv->decisionq_why, r - solv->rules);
-             solv->decisionmap[vv] = v > 0 ? 1 : -1;
-             IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-               {
-                 Solvable *s = solv->pool->solvables + vv;
-                 if (v < 0)
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
-                 else
-                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
-               }
-             continue;
-           }
-         /* check against previous decision: is there a conflict? */
-         if (v > 0 && solv->decisionmap[vv] > 0)
-           continue;
-         if (v < 0 && solv->decisionmap[vv] < 0)
-           continue;
-
-         POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
-         solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
-
-         if (ri >= solv->jobrules && ri < solv->jobrules_end)
-           v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
-         else
-           v = ri;
-         solver_disableproblem(solv, v);
-         if (v < 0)
-           solver_reenablepolicyrules(solv, -v);
-         havedisabled = 1;
-         break;        /* start over */
-       }
-      if (ii == solv->ruleassertions.count)
-       break;  /* finished! */
-    }
-}
-
-
-/********************************************************************/
-/* watches */
-
-
-/*-------------------------------------------------------------------
- * makewatches
- *
- * initial setup for all watches
- */
-
-static void
-makewatches(Solver *solv)
-{
-  Rule *r;
-  int i;
-  int nsolvables = solv->pool->nsolvables;
-
-  solv_free(solv->watches);
-  /* lower half for removals, upper half for installs */
-  solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
-  for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
-    {
-      if (!r->w2)              /* assertions do not need watches */
-       continue;
-
-      /* see addwatches_rule(solv, r) */
-      r->n1 = solv->watches[nsolvables + r->w1];
-      solv->watches[nsolvables + r->w1] = r - solv->rules;
-
-      r->n2 = solv->watches[nsolvables + r->w2];
-      solv->watches[nsolvables + r->w2] = r - solv->rules;
-    }
-}
-
-
-/*-------------------------------------------------------------------
- *
- * add watches (for a new learned rule)
- * sets up watches for a single rule
- *
- * see also makewatches() above.
- */
-
-static inline void
-addwatches_rule(Solver *solv, Rule *r)
-{
-  int nsolvables = solv->pool->nsolvables;
-
-  r->n1 = solv->watches[nsolvables + r->w1];
-  solv->watches[nsolvables + r->w1] = r - solv->rules;
-
-  r->n2 = solv->watches[nsolvables + r->w2];
-  solv->watches[nsolvables + r->w2] = r - solv->rules;
-}
-
-
-/********************************************************************/
-/*
- * rule propagation
- */
-
-
-/* shortcuts to check if a literal (positive or negative) assignment
- * evaluates to 'true' or 'false'
- */
-#define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
-#define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
-#define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
-
-/*-------------------------------------------------------------------
- *
- * propagate
- *
- * make decision and propagate to all rules
- *
- * Evaluate each term affected by the decision (linked through watches).
- * If we find unit rules we make new decisions based on them.
- *
- * return : 0 = everything is OK
- *          rule = conflict found in this rule
- */
-
-static Rule *
-propagate(Solver *solv, int level)
-{
-  Pool *pool = solv->pool;
-  Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
-  Rule *r;                    /* rule */
-  Id p, pkg, other_watch;
-  Id *dp;
-  Id *decisionmap = solv->decisionmap;
-  Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
-
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
-
-  /* foreach non-propagated decision */
-  while (solv->propagate_index < solv->decisionq.count)
-    {
-      /*
-       * 'pkg' was just decided
-       * negate because our watches trigger if literal goes FALSE
-       */
-      pkg = -solv->decisionq.elements[solv->propagate_index++];
-       
-      IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-        {
-         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
-         solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
-        }
-
-      /* foreach rule where 'pkg' is now FALSE */
-      for (rp = watches + pkg; *rp; rp = next_rp)
-       {
-         r = solv->rules + *rp;
-         if (r->d < 0)
-           {
-             /* rule is disabled, goto next */
-             if (pkg == r->w1)
-               next_rp = &r->n1;
-             else
-               next_rp = &r->n2;
-             continue;
-           }
-
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-           {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
-             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
-           }
-
-         /*
-           * 'pkg' was just decided (was set to FALSE), so this rule
-          * may now be unit.
-          */
-         /* find the other watch */
-         if (pkg == r->w1)
-           {
-             other_watch = r->w2;
-             next_rp = &r->n1;
-           }
-         else
-           {
-             other_watch = r->w1;
-             next_rp = &r->n2;
-           }
-
-         /*
-          * if the other watch is true we have nothing to do
-          */
-         if (DECISIONMAP_TRUE(other_watch))
-           continue;
-
-         /*
-          * The other literal is FALSE or UNDEF
-          *
-          */
-
-          if (r->d)
-           {
-             /* Not a binary clause, try to move our watch.
-              *
-              * Go over all literals and find one that is
-              *   not other_watch
-              *   and not FALSE
-              *
-              * (TRUE is also ok, in that case the rule is fulfilled)
-              * As speed matters here we do not use the FOR_RULELITERALS
-              * macro.
-              */
-             if (r->p                                /* we have a 'p' */
-                 && r->p != other_watch              /* which is not watched */
-                 && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
-               {
-                 p = r->p;
-               }
-             else                                    /* go find a 'd' to make 'true' */
-               {
-                 /* foreach p in 'd'
-                    we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
-                  */
-                 for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
-                   {
-                     if (p != other_watch              /* which is not watched */
-                         && !DECISIONMAP_FALSE(p))     /* and not FALSE */
-                       break;
-                   }
-               }
-
-             if (p)
-               {
-                 /*
-                  * if we found some p that is UNDEF or TRUE, move
-                  * watch to it
-                  */
-                 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-                   {
-                     if (p > 0)
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
-                     else
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
-                   }
-
-                 *rp = *next_rp;
-                 next_rp = rp;
-
-                 if (pkg == r->w1)
-                   {
-                     r->w1 = p;
-                     r->n1 = watches[p];
-                   }
-                 else
-                   {
-                     r->w2 = p;
-                     r->n2 = watches[p];
-                   }
-                 watches[p] = r - solv->rules;
-                 continue;
-               }
-             /* search failed, thus all unwatched literals are FALSE */
-               
-           } /* not binary */
-
-          /*
-          * unit clause found, set literal other_watch to TRUE
-          */
-
-         if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
-           return r;                              /* eek, a conflict! */
-
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-           {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "  unit ");
-             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
-           }
-
-         if (other_watch > 0)
-            decisionmap[other_watch] = level;    /* install! */
-         else
-           decisionmap[-other_watch] = -level;  /* remove! */
-
-         queue_push(&solv->decisionq, other_watch);
-         queue_push(&solv->decisionq_why, r - solv->rules);
-
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-           {
-             if (other_watch > 0)
-               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
-             else
-               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
-           }
-
-       } /* foreach rule involving 'pkg' */
-       
-    } /* while we have non-decided decisions */
-
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
-
-  return 0;    /* all is well */
-}
-
-
-/********************************************************************/
-/* Analysis */
-
-/*-------------------------------------------------------------------
- *
- * revert
- * revert decisionq to a level
- */
-
-static void
-revert(Solver *solv, int level)
-{
-  Pool *pool = solv->pool;
-  Id v, vv;
-  while (solv->decisionq.count)
-    {
-      v = solv->decisionq.elements[solv->decisionq.count - 1];
-      vv = v > 0 ? v : -v;
-      if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
-        break;
-      POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
-      solv->decisionmap[vv] = 0;
-      solv->decisionq.count--;
-      solv->decisionq_why.count--;
-      solv->propagate_index = solv->decisionq.count;
-    }
-  while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level)
-    solv->branches.count -= solv->branches.elements[solv->branches.count - 2];
-  if (solv->recommends_index > solv->decisionq.count)
-    solv->recommends_index = -1;       /* rebuild recommends/suggests maps */
-  if (solv->decisionq.count < solv->decisioncnt_jobs)
-    solv->decisioncnt_jobs = 0;
-  if (solv->decisionq.count < solv->decisioncnt_update)
-    solv->decisioncnt_update = 0;
-  if (solv->decisionq.count < solv->decisioncnt_keep)
-    solv->decisioncnt_keep = 0;
-  if (solv->decisionq.count < solv->decisioncnt_resolve)
-    solv->decisioncnt_resolve = 0;
-  if (solv->decisionq.count < solv->decisioncnt_weak)
-    solv->decisioncnt_weak= 0;
-  if (solv->decisionq.count < solv->decisioncnt_orphan)
-    solv->decisioncnt_orphan = 0;
-}
-
-/*-------------------------------------------------------------------
- *
- * watch2onhighest - put watch2 on literal with highest level
- */
-
-static inline void
-watch2onhighest(Solver *solv, Rule *r)
-{
-  int l, wl = 0;
-  Id d, v, *dp;
-
-  d = r->d < 0 ? -r->d - 1 : r->d;
-  if (!d)
-    return;    /* binary rule, both watches are set */
-  dp = solv->pool->whatprovidesdata + d;
-  while ((v = *dp++) != 0)
-    {
-      l = solv->decisionmap[v < 0 ? -v : v];
-      if (l < 0)
-       l = -l;
-      if (l > wl)
-       {
-         r->w2 = dp[-1];
-         wl = l;
-       }
-    }
-}
-
-
-/*-------------------------------------------------------------------
- *
- * analyze
- *   and learn
- */
-
-static int
-analyze(Solver *solv, int level, Rule *c, Rule **lrp)
-{
-  Pool *pool = solv->pool;
-  Queue q;
-  Rule *r;
-  Id q_buf[8];
-  int rlevel = 1;
-  Map seen;            /* global? */
-  Id p = 0, pp, v, vv, why;
-  int l, i, idx;
-  int num = 0, l1num = 0;
-  int learnt_why = solv->learnt_pool.count;
-  Id *decisionmap = solv->decisionmap;
-
-  queue_init_buffer(&q, q_buf, sizeof(q_buf)/sizeof(*q_buf));
-
-  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
-  map_init(&seen, pool->nsolvables);
-  idx = solv->decisionq.count;
-  for (;;)
-    {
-      IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
-       solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
-      queue_push(&solv->learnt_pool, c - solv->rules);
-      FOR_RULELITERALS(v, pp, c)
-       {
-         if (DECISIONMAP_TRUE(v))      /* the one true literal */
-           continue;
-         vv = v > 0 ? v : -v;
-         if (MAPTST(&seen, vv))
-           continue;
-         MAPSET(&seen, vv);            /* mark that we also need to look at this literal */
-         l = solv->decisionmap[vv];
-         if (l < 0)
-           l = -l;
-         if (l == 1)
-           l1num++;                    /* need to do this one in level1 pass */
-         else if (l == level)
-           num++;                      /* need to do this one as well */
-         else
-           {
-             queue_push(&q, v);        /* not level1 or conflict level, add to new rule */
-             if (l > rlevel)
-               rlevel = l;
-           }
-       }
-l1retry:
-      if (!num && !--l1num)
-       break;  /* all literals done */
-
-      /* find the next literal to investigate */
-      /* (as num + l1num > 0, we know that we'll always find one) */
-      for (;;)
-       {
-         assert(idx > 0);
-         v = solv->decisionq.elements[--idx];
-         vv = v > 0 ? v : -v;
-         if (MAPTST(&seen, vv))
-           break;
-       }
-      MAPCLR(&seen, vv);
-
-      if (num && --num == 0)
-       {
-         /* done with normal literals, now start level 1 literal processing */
-         p = -v;       /* so that v doesn't get lost */
-         if (!l1num)
-           break;
-         POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
-         /* clear non-l1 bits from seen map */
-         for (i = 0; i < q.count; i++)
-           {
-             v = q.elements[i];
-             MAPCLR(&seen, v > 0 ? v : -v);
-           }
-         /* only level 1 marks left in seen map */
-         l1num++;      /* as l1retry decrements it */
-         goto l1retry;
-       }
-
-      why = solv->decisionq_why.elements[idx];
-      if (why <= 0)    /* just in case, maybe for SYSTEMSOLVABLE */
-       goto l1retry;
-      c = solv->rules + why;
-    }
-  map_free(&seen);
-  assert(p != 0);
-  assert(rlevel > 0 && rlevel < level);
-  IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
-    {
-      POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
-      solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
-      for (i = 0; i < q.count; i++)
-        solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, q.elements[i]);
-    }
-  /* push end marker on learnt reasons stack */
-  queue_push(&solv->learnt_pool, 0);
-  solv->stats_learned++;
-
-  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, rlevel);
-  level = rlevel;
-  revert(solv, level);
-  if (q.count < 2)
-    {
-      Id d = q.count ? q.elements[0] : 0;
-      queue_free(&q);
-      r = solver_addrule(solv, p, d, 0);
-    }
-  else
-    {
-      Id d = pool_queuetowhatprovides(pool, &q);
-      queue_free(&q);
-      r = solver_addrule(solv, p, 0, d);
-    }
-  assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
-  queue_push(&solv->learnt_why, learnt_why);
-  if (r->w2)
-    {
-      /* needs watches */
-      watch2onhighest(solv, r);
-      addwatches_rule(solv, r);
-    }
-  else
-    {
-      /* rule is an assertion */
-      queue_push(&solv->ruleassertions, r - solv->rules);
-    }
-  *lrp = r;
-  return level;
-}
-
-
-/*-------------------------------------------------------------------
- *
- * solver_reset
- *
- * reset all solver decisions
- * called after rules have been enabled/disabled
- */
-
-void
-solver_reset(Solver *solv)
-{
-  int i;
-  Id v;
-
-  /* rewind all decisions */
-  for (i = solv->decisionq.count - 1; i >= 0; i--)
-    {
-      v = solv->decisionq.elements[i];
-      solv->decisionmap[v > 0 ? v : -v] = 0;
-    }
-  queue_empty(&solv->decisionq_why);
-  queue_empty(&solv->decisionq);
-  solv->recommends_index = -1;
-  solv->propagate_index = 0;
-  solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
-  queue_empty(&solv->branches);
-
-  /* adapt learnt rule status to new set of enabled/disabled rules */
-  enabledisablelearntrules(solv);
-}
-
-
-/*-------------------------------------------------------------------
- *
- * analyze_unsolvable_rule
- *
- * recursion helper used by analyze_unsolvable
- */
-
-static void
-analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
-{
-  Pool *pool = solv->pool;
-  int i;
-  Id why = r - solv->rules;
-
-  IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
-    solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
-  if (solv->learntrules && why >= solv->learntrules)
-    {
-      if (MAPTST(rseen, why - solv->learntrules))
-       return;
-      MAPSET(rseen, why - solv->learntrules);
-      for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
-       if (solv->learnt_pool.elements[i] > 0)
-         analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
-      return;
-    }
-  if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why))
-    if (!*lastweakp || why > *lastweakp)
-      *lastweakp = why;
-  /* do not add pkg rules to problem */
-  if (why < solv->pkgrules_end)
-    return;
-  /* turn rule into problem */
-  if (why >= solv->jobrules && why < solv->jobrules_end)
-    why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
-  /* normalize dup/infarch rules */
-  if (why > solv->infarchrules && why < solv->infarchrules_end)
-    {
-      Id name = pool->solvables[-solv->rules[why].p].name;
-      while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
-       why--;
-    }
-  if (why > solv->duprules && why < solv->duprules_end)
-    {
-      Id name = pool->solvables[-solv->rules[why].p].name;
-      while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
-       why--;
-    }
-
-  /* return if problem already countains our rule */
-  if (solv->problems.count)
-    {
-      for (i = solv->problems.count - 1; i >= 0; i--)
-       if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
-         break;
-       else if (solv->problems.elements[i] == why)
-         return;
-    }
-  queue_push(&solv->problems, why);
-}
-
-
-/*-------------------------------------------------------------------
- *
- * analyze_unsolvable (called from setpropagatelearn)
- *
- * We know that the problem is not solvable. Record all involved
- * rules (i.e. the "proof") into solv->learnt_pool.
- * Record the learnt pool index and all non-pkg rules into
- * solv->problems. (Our solutions to fix the problems are to
- * disable those rules.)
- *
- * If the proof contains at least one weak rule, we disable the
- * last of them.
- *
- * Otherwise we return -1 if disablerules is not set or disable
- * _all_ of the problem rules and return 0.
- *
- * return:  0 - disabled some rules, try again
- *         -1 - hopeless
- */
-
-static int
-analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  Map involved;                /* global to speed things up? */
-  Map rseen;
-  Id pp, v, vv, why;
-  int i, idx;
-  Id *decisionmap = solv->decisionmap;
-  int oldproblemcount;
-  int oldlearntpoolcount;
-  Id lastweak;
-  int record_proof = 1;
-
-  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
-  solv->stats_unsolvable++;
-  oldproblemcount = solv->problems.count;
-  oldlearntpoolcount = solv->learnt_pool.count;
-
-  /* make room for proof index */
-  /* must update it later, as analyze_unsolvable_rule would confuse
-   * it with a rule index if we put the real value in already */
-  queue_push(&solv->problems, 0);
-
-  r = cr;
-  map_init(&involved, pool->nsolvables);
-  map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
-  if (record_proof)
-    queue_push(&solv->learnt_pool, r - solv->rules);
-  lastweak = 0;
-  analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
-  FOR_RULELITERALS(v, pp, r)
-    {
-      if (DECISIONMAP_TRUE(v)) /* the one true literal */
-         continue;
-      vv = v > 0 ? v : -v;
-      MAPSET(&involved, vv);
-    }
-  idx = solv->decisionq.count;
-  while (idx > 0)
-    {
-      v = solv->decisionq.elements[--idx];
-      vv = v > 0 ? v : -v;
-      if (!MAPTST(&involved, vv) || vv == SYSTEMSOLVABLE)
-       continue;
-      why = solv->decisionq_why.elements[idx];
-      assert(why > 0);
-      if (record_proof)
-        queue_push(&solv->learnt_pool, why);
-      r = solv->rules + why;
-      analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
-      FOR_RULELITERALS(v, pp, r)
-       {
-         if (DECISIONMAP_TRUE(v))      /* the one true literal */
-             continue;
-         vv = v > 0 ? v : -v;
-         MAPSET(&involved, vv);
-       }
-    }
-  map_free(&involved);
-  map_free(&rseen);
-  queue_push(&solv->problems, 0);      /* mark end of this problem */
-
-  if (lastweak)
-    {
-      /* disable last weak rule */
-      solv->problems.count = oldproblemcount;
-      solv->learnt_pool.count = oldlearntpoolcount;
-      if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
-       v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
-      else
-        v = lastweak;
-      POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
-      solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
-      if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
-       solver_disablechoicerules(solv, solv->rules + lastweak);
-      solver_disableproblem(solv, v);
-      if (v < 0)
-       solver_reenablepolicyrules(solv, -v);
-      solver_reset(solv);
-      return 0;
-    }
-
-  if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
-    if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
-      {
-       solv->problems.count = oldproblemcount;
-       solv->learnt_pool.count = oldlearntpoolcount;
-       solver_reset(solv);
-       return 0;
-      }
-
-  /* finish proof */
-  if (record_proof)
-    {
-      queue_push(&solv->learnt_pool, 0);
-      solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
-    }
-
-  /* + 2: index + trailing zero */
-  if (disablerules && oldproblemcount + 2 < solv->problems.count)
-    {
-      for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
-        solver_disableproblem(solv, solv->problems.elements[i]);
-      /* XXX: might want to enable all weak rules again */
-      solver_reset(solv);
-      return 0;
-    }
-  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
-  return -1;
-}
-
-
-/*-------------------------------------------------------------------
- *
- * setpropagatelearn
- *
- * add free decision (solvable to install) to decisionq
- * increase level and propagate decision
- * return if no conflict.
- *
- * in conflict case, analyze conflict rule, add resulting
- * rule to learnt rule set, make decision from learnt
- * rule (always unit) and re-propagate.
- *
- * returns the new solver level or -1 if unsolvable
- *
- */
-
-static int
-setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
-{
-  Pool *pool = solv->pool;
-  Rule *r, *lr;
-
-  if (decision)
-    {
-      level++;
-      if (decision > 0)
-        solv->decisionmap[decision] = level;
-      else
-        solv->decisionmap[-decision] = -level;
-      queue_push(&solv->decisionq, decision);
-      queue_push(&solv->decisionq_why, -ruleid);       /* <= 0 -> free decision */
-    }
-  assert(ruleid >= 0 && level > 0);
-  for (;;)
-    {
-      r = propagate(solv, level);
-      if (!r)
-       break;
-      if (level == 1)
-       return analyze_unsolvable(solv, r, disablerules);
-      POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
-      level = analyze(solv, level, r, &lr);
-      /* the new rule is unit by design */
-      decision = lr->p;
-      solv->decisionmap[decision > 0 ? decision : -decision] = decision > 0 ? level : -level;
-      queue_push(&solv->decisionq, decision);
-      queue_push(&solv->decisionq_why, lr - solv->rules);
-      IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
-       {
-         POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
-         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, decision);
-         POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
-         solver_printrule(solv, SOLV_DEBUG_ANALYZE, lr);
-       }
-    }
-  return level;
-}
-
-static void
-reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq)
-{
-  Pool *pool = solv->pool;
-  int i, j, haveone = 0, dqcount = dq->count;
-  int decisionqcount = solv->decisionq.count;
-  Id p;
-  Solvable *s;
-
-  /* at the time we process jobrules the installed packages are not kept yet */
-  /* reorder so that "future-supplemented" packages come first */
-  FOR_REPO_SOLVABLES(solv->installed, p, s)
-    {
-      if (MAPTST(&solv->noupdate, p - solv->installed->start))
-       continue;
-      if (solv->decisionmap[p] == 0)
-       {
-         if (s->recommends || s->suggests)
-           queue_push(&solv->decisionq, p);
-         solv->decisionmap[p] = level + 1;
-         haveone = 1;
-       }
-    }
-  if (!haveone)
-    return;
-  policy_update_recommendsmap(solv);
-  for (i = 0; i < dqcount; i++)
-    {
-      p = dq->elements[i];
-      if (!(pool->solvables[p].repo == solv->installed || MAPTST(&solv->suggestsmap, p) || solver_is_enhancing(solv, pool->solvables + p)))
-        {
-         queue_push(dq, p);
-         dq->elements[i] = 0;
-        }
-    }
-  dqcount = dq->count;
-  for (i = 0; i < dqcount; i++)
-    {
-      p = dq->elements[i];
-      if (p && !(pool->solvables[p].repo == solv->installed || MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
-        {
-         queue_push(dq, p);
-         dq->elements[i] = 0;
-        }
-    }
-  for (i = j = 0; i < dq->count; i++)
-    if (dq->elements[i])
-      dq->elements[j++] = dq->elements[i];
-  queue_truncate(dq, j);
-  FOR_REPO_SOLVABLES(solv->installed, p, s)
-    if (solv->decisionmap[p] == level + 1)
-      solv->decisionmap[p] = 0;
-  if (solv->decisionq.count != decisionqcount)
-    {
-      solv->recommends_index = -1;
-      queue_truncate(&solv->decisionq, decisionqcount);
-    }
-}
-
-/*-------------------------------------------------------------------
- *
- * branch handling
- */
-
-static void
-createbranch(Solver *solv, int level, Queue *dq, Id p, Id data)
-{
-  Pool *pool = solv->pool;
-  int i;
-  IF_POOLDEBUG (SOLV_DEBUG_POLICY)
-    {
-      POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch:\n");
-      for (i = 0; i < dq->count; i++)
-       POOL_DEBUG (SOLV_DEBUG_POLICY, "  - %s\n", pool_solvid2str(pool, dq->elements[i]));
-    }
-  queue_push(&solv->branches, -dq->elements[0]);
-  for (i = 1; i < dq->count; i++)
-    queue_push(&solv->branches, dq->elements[i]);
-  queue_push2(&solv->branches, p, data);
-  queue_push2(&solv->branches, dq->count + 4, level);
-}
-
-static int
-takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
-{
-  Pool *pool = solv->pool;
-  int level;
-  Id p, why;
-#if 0
-  {
-    int i;
-    printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], start, end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]);
-    for (i = end - solv->branches.elements[end - 2]; i < end - 4; i++)
-      printf("%c %c%s\n", i == pos ? 'x' : ' ', solv->branches.elements[i] >= 0 ? ' ' : '-', pool_solvid2str(pool, solv->branches.elements[i] >= 0 ? solv->branches.elements[i] : -solv->branches.elements[i]));
-  }
-#endif
-  level = solv->branches.elements[end - 1];
-  p = solv->branches.elements[pos];
-  solv->branches.elements[pos] = -p;
-  POOL_DEBUG(SOLV_DEBUG_SOLVER, "%s %d -> %d with %s\n", msg, solv->decisionmap[p], level, pool_solvid2str(pool, p));
-  /* hack: set level to zero so that revert does not remove the branch */
-  solv->branches.elements[end - 1] = 0;
-  revert(solv, level);
-  solv->branches.elements[end - 1] = level;
-  /* hack: revert simply sets the count, so we can still access the reverted elements */
-  why = -solv->decisionq_why.elements[solv->decisionq_why.count];
-  assert(why >= 0);
-  return setpropagatelearn(solv, level, p, disablerules, why);
-}
-
-/*-------------------------------------------------------------------
- *
- * select and install
- *
- * install best package from the queue. We add an extra package, inst, if
- * provided. See comment in weak install section.
- *
- * returns the new solver level or -1 if unsolvable
- *
- */
-
-static int
-selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
-{
-  Pool *pool = solv->pool;
-  Id p;
-
-  if (dq->count > 1)
-    policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
-  /* if we're resolving job rules and didn't resolve the installed packages yet,
-   * do some special supplements ordering */
-  if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed && !solv->focus_installed)
-    reorder_dq_for_jobrules(solv, level, dq);
-  /* if we have multiple candidates we open a branch */
-  if (dq->count > 1)
-    createbranch(solv, level, dq, 0, ruleid);
-  p = dq->elements[0];
-  POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
-  return setpropagatelearn(solv, level, p, disablerules, ruleid);
-}
-
-
-/********************************************************************/
-/* Main solver interface */
-
-
-/*-------------------------------------------------------------------
- *
- * solver_create
- * create solver structure
- *
- * pool: all available solvables
- * installed: installed Solvables
- *
- *
- * Upon solving, rules are created to flag the Solvables
- * of the 'installed' Repo as installed.
- */
-
-Solver *
-solver_create(Pool *pool)
-{
-  Solver *solv;
-  solv = (Solver *)solv_calloc(1, sizeof(Solver));
-  solv->pool = pool;
-  solv->installed = pool->installed;
-
-  solv->allownamechange = 1;
-
-  solv->dup_allowdowngrade = 1;
-  solv->dup_allownamechange = 1;
-  solv->dup_allowarchchange = 1;
-  solv->dup_allowvendorchange = 1;
-
-  solv->keepexplicitobsoletes = pool->noobsoletesmultiversion ? 0 : 1;
-
-  queue_init(&solv->ruletojob);
-  queue_init(&solv->decisionq);
-  queue_init(&solv->decisionq_why);
-  queue_init(&solv->problems);
-  queue_init(&solv->orphaned);
-  queue_init(&solv->learnt_why);
-  queue_init(&solv->learnt_pool);
-  queue_init(&solv->branches);
-  queue_init(&solv->weakruleq);
-  queue_init(&solv->ruleassertions);
-  queue_init(&solv->addedmap_deduceq);
-
-  queue_push(&solv->learnt_pool, 0);   /* so that 0 does not describe a proof */
-
-  map_init(&solv->recommendsmap, pool->nsolvables);
-  map_init(&solv->suggestsmap, pool->nsolvables);
-  map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
-  solv->recommends_index = 0;
-
-  solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
-  solv->nrules = 1;
-  solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
-  memset(solv->rules, 0, sizeof(Rule));
-
-  return solv;
-}
-
-
-static int
-resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
-{
-  Pool *pool = solv->pool;
-  int oldlevel = level;
-  int i, olevel;
-  Rule *r;
-
-  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
-  if (!solv->decisioncnt_jobs)
-    solv->decisioncnt_jobs = solv->decisionq.count;
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
-    {
-      Id l, pp;
-      if (r->d < 0)            /* ignore disabled rules */
-       continue;
-      queue_empty(dq);
-      FOR_RULELITERALS(l, pp, r)
-       {
-         if (l < 0)
-           {
-             if (solv->decisionmap[-l] <= 0)
-               break;
-           }
-         else
-           {
-             if (solv->decisionmap[l] > 0)
-               break;
-             if (solv->decisionmap[l] == 0)
-               queue_push(dq, l);
-           }
-       }
-      if (l || !dq->count)
-       continue;
-      /* prune to installed if not updating */
-      if (dq->count > 1 && solv->installed && !solv->updatemap_all &&
-         !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
-       {
-         int j, k;
-         for (j = k = 0; j < dq->count; j++)
-           {
-             Solvable *s = pool->solvables + dq->elements[j];
-             if (s->repo == solv->installed)
-               {
-                 dq->elements[k++] = dq->elements[j];
-                 if (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start))
-                   {
-                     k = 0;    /* package wants to be updated, do not prune */
-                     break;
-                   }
-               }
-           }
-         if (k)
-           dq->count = k;
-       }
-      olevel = level;
-      level = selectandinstall(solv, level, dq, disablerules, i);
-      if (level <= olevel)
-       {
-         if (level == olevel)
-           {
-             i--;
-             r--;
-             continue; /* try something else */
-           }
-         if (level < oldlevel)
-           return level;
-         /* redo from start of jobrules */
-         i = solv->jobrules - 1;
-         r = solv->rules + i;
-       }
-    }
-  return level;
-}
-
-/*-------------------------------------------------------------------
- *
- * solver_free
- */
-
-static inline void
-queuep_free(Queue **qp)
-{
-  if (!*qp)
-    return;
-  queue_free(*qp);
-  *qp = solv_free(*qp);
-}
-
-static inline void
-map_zerosize(Map *m)
-{
-  if (m->size)
-    {
-      map_free(m);
-      map_init(m, 0);
-    }
-}
-
-void
-solver_free(Solver *solv)
-{
-  queue_free(&solv->job);
-  queue_free(&solv->ruletojob);
-  queue_free(&solv->decisionq);
-  queue_free(&solv->decisionq_why);
-  queue_free(&solv->learnt_why);
-  queue_free(&solv->learnt_pool);
-  queue_free(&solv->problems);
-  queue_free(&solv->solutions);
-  queue_free(&solv->orphaned);
-  queue_free(&solv->branches);
-  queue_free(&solv->weakruleq);
-  queue_free(&solv->ruleassertions);
-  queue_free(&solv->addedmap_deduceq);
-  queuep_free(&solv->cleandeps_updatepkgs);
-  queuep_free(&solv->cleandeps_mistakes);
-  queuep_free(&solv->update_targets);
-  queuep_free(&solv->installsuppdepq);
-  queuep_free(&solv->recommendscplxq);
-  queuep_free(&solv->suggestscplxq);
-  queuep_free(&solv->brokenorphanrules);
-
-  map_free(&solv->recommendsmap);
-  map_free(&solv->suggestsmap);
-  map_free(&solv->noupdate);
-  map_free(&solv->weakrulemap);
-  map_free(&solv->multiversion);
-
-  map_free(&solv->updatemap);
-  map_free(&solv->bestupdatemap);
-  map_free(&solv->fixmap);
-  map_free(&solv->dupmap);
-  map_free(&solv->dupinvolvedmap);
-  map_free(&solv->droporphanedmap);
-  map_free(&solv->cleandepsmap);
-  map_free(&solv->allowuninstallmap);
-
-  solv_free(solv->decisionmap);
-  solv_free(solv->rules);
-  solv_free(solv->watches);
-  solv_free(solv->obsoletes);
-  solv_free(solv->obsoletes_data);
-  solv_free(solv->specialupdaters);
-  solv_free(solv->choicerules_ref);
-  solv_free(solv->bestrules_pkg);
-  solv_free(solv->yumobsrules_info);
-  solv_free(solv->instbuddy);
-  solv_free(solv);
-}
-
-int
-solver_get_flag(Solver *solv, int flag)
-{
-  switch (flag)
-  {
-  case SOLVER_FLAG_ALLOW_DOWNGRADE:
-    return solv->allowdowngrade;
-  case SOLVER_FLAG_ALLOW_NAMECHANGE:
-    return solv->allownamechange;
-  case SOLVER_FLAG_ALLOW_ARCHCHANGE:
-    return solv->allowarchchange;
-  case SOLVER_FLAG_ALLOW_VENDORCHANGE:
-    return solv->allowvendorchange;
-  case SOLVER_FLAG_ALLOW_UNINSTALL:
-    return solv->allowuninstall;
-  case SOLVER_FLAG_NO_UPDATEPROVIDE:
-    return solv->noupdateprovide;
-  case SOLVER_FLAG_SPLITPROVIDES:
-    return solv->dosplitprovides;
-  case SOLVER_FLAG_IGNORE_RECOMMENDED:
-    return solv->dontinstallrecommended;
-  case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
-    return solv->addalreadyrecommended;
-  case SOLVER_FLAG_NO_INFARCHCHECK:
-    return solv->noinfarchcheck;
-  case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
-    return solv->keepexplicitobsoletes;
-  case SOLVER_FLAG_BEST_OBEY_POLICY:
-    return solv->bestobeypolicy;
-  case SOLVER_FLAG_NO_AUTOTARGET:
-    return solv->noautotarget;
-  case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
-    return solv->dup_allowdowngrade;
-  case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
-    return solv->dup_allownamechange;
-  case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
-    return solv->dup_allowarchchange;
-  case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
-    return solv->dup_allowvendorchange;
-  case SOLVER_FLAG_KEEP_ORPHANS:
-    return solv->keep_orphans;
-  case SOLVER_FLAG_BREAK_ORPHANS:
-    return solv->break_orphans;
-  case SOLVER_FLAG_FOCUS_INSTALLED:
-    return solv->focus_installed;
-  case SOLVER_FLAG_YUM_OBSOLETES:
-    return solv->do_yum_obsoletes;
-  case SOLVER_FLAG_NEED_UPDATEPROVIDE:
-    return solv->needupdateprovide;
-  default:
-    break;
-  }
-  return -1;
-}
-
-int
-solver_set_flag(Solver *solv, int flag, int value)
-{
-  int old = solver_get_flag(solv, flag);
-  switch (flag)
-  {
-  case SOLVER_FLAG_ALLOW_DOWNGRADE:
-    solv->allowdowngrade = value;
-    break;
-  case SOLVER_FLAG_ALLOW_NAMECHANGE:
-    solv->allownamechange = value;
-    break;
-  case SOLVER_FLAG_ALLOW_ARCHCHANGE:
-    solv->allowarchchange = value;
-    break;
-  case SOLVER_FLAG_ALLOW_VENDORCHANGE:
-    solv->allowvendorchange = value;
-    break;
-  case SOLVER_FLAG_ALLOW_UNINSTALL:
-    solv->allowuninstall = value;
-    break;
-  case SOLVER_FLAG_NO_UPDATEPROVIDE:
-    solv->noupdateprovide = value;
-    break;
-  case SOLVER_FLAG_SPLITPROVIDES:
-    solv->dosplitprovides = value;
-    break;
-  case SOLVER_FLAG_IGNORE_RECOMMENDED:
-    solv->dontinstallrecommended = value;
-    break;
-  case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
-    solv->addalreadyrecommended = value;
-    break;
-  case SOLVER_FLAG_NO_INFARCHCHECK:
-    solv->noinfarchcheck = value;
-    break;
-  case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
-    solv->keepexplicitobsoletes = value;
-    break;
-  case SOLVER_FLAG_BEST_OBEY_POLICY:
-    solv->bestobeypolicy = value;
-    break;
-  case SOLVER_FLAG_NO_AUTOTARGET:
-    solv->noautotarget = value;
-    break;
-  case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
-    solv->dup_allowdowngrade = value;
-    break;
-  case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
-    solv->dup_allownamechange = value;
-    break;
-  case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
-    solv->dup_allowarchchange = value;
-    break;
-  case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
-    solv->dup_allowvendorchange = value;
-    break;
-  case SOLVER_FLAG_KEEP_ORPHANS:
-    solv->keep_orphans = value;
-    break;
-  case SOLVER_FLAG_BREAK_ORPHANS:
-    solv->break_orphans = value;
-    break;
-  case SOLVER_FLAG_FOCUS_INSTALLED:
-    solv->focus_installed = value;
-    break;
-  case SOLVER_FLAG_YUM_OBSOLETES:
-    solv->do_yum_obsoletes = value;
-    break;
-  case SOLVER_FLAG_NEED_UPDATEPROVIDE:
-    solv->needupdateprovide = value;
-    break;
-  default:
-    break;
-  }
-  return old;
-}
-
-static int
-cleandeps_check_mistakes(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Rule *r;
-  Id p, pp;
-  int i;
-  int mademistake = 0;
-
-  if (!solv->cleandepsmap.size)
-    return 0;
-  /* check for mistakes */
-  for (i = solv->installed->start; i < solv->installed->end; i++)
-    {
-      if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
-       continue;
-      r = solv->rules + solv->featurerules + (i - solv->installed->start);
-      /* a mistake is when the featurerule is true but the updaterule is false */
-      if (!r->p)
-       continue;
-      FOR_RULELITERALS(p, pp, r)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         break;
-      if (!p)
-       continue;       /* feature rule is not true */
-      r = solv->rules + solv->updaterules + (i - solv->installed->start);
-      if (!r->p)
-       continue;
-      FOR_RULELITERALS(p, pp, r)
-       if (p > 0 && solv->decisionmap[p] > 0)
-         break;
-      if (p)
-       continue;       /* update rule is true */
-      POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
-      solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
-      POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
-      solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
-      if (!solv->cleandeps_mistakes)
-       {
-         solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
-         queue_init(solv->cleandeps_mistakes);
-       }
-      queue_push(solv->cleandeps_mistakes, i);
-      MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
-      solver_reenablepolicyrules_cleandeps(solv, i);
-      mademistake = 1;
-    }
-  return mademistake;
-}
-
-static void
-prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
-{
-  int i, j;
-  Id p, *cp2;
-  for (i = j = 0; i < q->count; i++)
-    {
-      p = q->elements[i];
-      for (cp2 = cp; *cp2; cp2++)
-       if (*cp2 == p)
-         {
-           q->elements[j++] = p;
-           break;
-         }
-    }
-  queue_truncate(q, j);
-}
-
-#ifdef ENABLE_COMPLEX_DEPS
-
-static void
-add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
-{
-  Pool *pool = solv->pool;
-  int oldcnt = dq->count;
-  int cutcnt, blkcnt;
-  Id p;
-  int i, j;
-
-#if 0
-  printf("ADD_COMPLEX_RECOMMENDS %s\n", pool_dep2str(pool, rec));
-#endif
-  i = pool_normalize_complex_dep(pool, rec, dq, CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    return;
-  cutcnt = dq->count;
-  for (i = oldcnt; i < cutcnt; i++)
-    {
-      blkcnt = dq->count;
-      for (; (p = dq->elements[i]) != 0; i++)
-       {
-         if (p < 0)
-           {
-             if (solv->decisionmap[-p] <= 0)
-               break;
-             continue;
-           }
-         if (solv->decisionmap[p] > 0)
-           {
-             queue_truncate(dq, blkcnt);
-             break;
-           }
-         if (dqmap)
-           {
-             if (!MAPTST(dqmap, p))
-               continue;
-           }
-         else
-           {
-             if (solv->decisionmap[p] < 0)
-               continue;
-             if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
-               continue;
-           }
-         queue_push(dq, p);
-       }
-      while (dq->elements[i])
-       i++;
-    }
-  queue_deleten(dq, oldcnt, cutcnt - oldcnt);
-  /* unify */
-  if (dq->count != oldcnt)
-    {
-      for (j = oldcnt; j < dq->count; j++)
-       {
-         p = dq->elements[j];
-         for (i = 0; i < j; i++)
-           if (dq->elements[i] == p)
-             {
-               dq->elements[j] = 0;
-               break;
-             }
-       }
-      for (i = j = oldcnt; j < dq->count; j++)
-       if (dq->elements[j])
-         dq->elements[i++] = dq->elements[j];
-      queue_truncate(dq, i);
-    }
-#if 0
-  printf("RETURN:\n");
-  for (i = oldcnt; i < dq->count; i++)
-    printf("  - %s\n", pool_solvid2str(pool, dq->elements[i]));
-#endif
-}
-
-static void
-do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected)
-{
-  Pool *pool = solv->pool;
-  Queue dq;
-  Id p;
-  int i, blk;
-
-#if 0
-  printf("DO_COMPLEX_RECOMMENDATIONS %s\n", pool_dep2str(pool, rec));
-#endif
-  queue_init(&dq);
-  i = pool_normalize_complex_dep(pool, rec, &dq, CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    {
-      queue_free(&dq);
-      return;
-    }
-  for (i = 0; i < dq.count; i++)
-    {
-      blk = i;
-      for (; (p = dq.elements[i]) != 0; i++)
-       {
-         if (p < 0)
-           {
-             if (solv->decisionmap[-p] <= 0)
-               break;
-             continue;
-           }
-         if (solv->decisionmap[p] > 0)
-           {
-             if (noselected)
-               break;
-             MAPSET(m, p);
-             for (i++; (p = dq.elements[i]) != 0; i++)
-               if (p > 0 && solv->decisionmap[p] > 0)
-                 MAPSET(m, p);
-             p = 1;
-             break;
-           }
-       }
-      if (!p)
-       {
-         for (i = blk; (p = dq.elements[i]) != 0; i++)
-           if (p > 0)
-             MAPSET(m, p);
-       }
-      while (dq.elements[i])
-       i++;
-    }
-  queue_free(&dq);
-}
-
-#endif
-
-/*-------------------------------------------------------------------
- *
- * solver_run_sat
- *
- * all rules have been set up, now actually run the solver
- *
- */
-
-void
-solver_run_sat(Solver *solv, int disablerules, int doweak)
-{
-  Queue dq;            /* local decisionqueue */
-  Queue dqs;           /* local decisionqueue for supplements */
-  int systemlevel;
-  int level, olevel;
-  Rule *r;
-  int i, j, n;
-  Solvable *s;
-  Pool *pool = solv->pool;
-  Id p, pp, *dp, postponed;
-  int minimizationsteps;
-  int installedpos = solv->installed ? solv->installed->start : 0;
-
-  IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
-    {
-      POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
-      for (i = 1; i < solv->nrules; i++)
-       solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
-    }
-
-  /* start SAT algorithm */
-  level = 0;
-  systemlevel = level + 1;
-  POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
-
-  queue_init(&dq);
-  queue_init(&dqs);
-
-  /*
-   * here's the main loop:
-   * 1) decide assertion rules and propagate
-   * 2) fulfill jobs
-   * 3) try to keep installed packages
-   * 4) fulfill all unresolved rules
-   * 5) install recommended packages
-   * 6) minimalize solution if we had choices
-   * if we encounter a problem, we rewind to a safe level and restart
-   * with step 1
-   */
-
-  minimizationsteps = 0;
-  for (;;)
-    {
-      /*
-       * initial propagation of the assertions
-       */
-      if (level <= 0)
-       {
-         if (level < 0)
-           break;
-         makeruledecisions(solv);
-         level = 1;
-         if (!disablerules && solv->problems.count)
-           {
-             level = -1;
-             break;
-           }
-         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
-         if ((r = propagate(solv, level)) != 0)
-           {
-             level = analyze_unsolvable(solv, r, disablerules);
-             continue;
-           }
-         systemlevel = level + 1;
-       }
-
-      /*
-       * resolve jobs first (unless focus_installed is set)
-       */
-     if (level < systemlevel && !solv->focus_installed)
-       {
-         olevel = level;
-         level = resolve_jobrules(solv, level, disablerules, &dq);
-         if (level < olevel)
-           continue;
-         systemlevel = level + 1;
-       }
-
-
-      /*
-       * installed packages
-       */
-      if (!solv->decisioncnt_update)
-       solv->decisioncnt_update = solv->decisionq.count;
-      if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
-       {
-         Repo *installed = solv->installed;
-         int pass;
-
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
-         /* we use two passes if we need to update packages
-           * to create a better user experience */
-         for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
-           {
-             int passlevel = level;
-             Id *specialupdaters = solv->specialupdaters;
-             if (pass == 1 && !solv->decisioncnt_keep)
-               solv->decisioncnt_keep = solv->decisionq.count;
-             /* start with installedpos, the position that gave us problems the last time */
-             for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
-               {
-                 Rule *rr;
-                 Id d;
-
-                 if (i == installed->end)
-                   i = installed->start;
-                 s = pool->solvables + i;
-                 if (s->repo != installed)
-                   continue;
-
-                 if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start]))
-                   continue;           /* already decided */
-                 if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
-                   continue;           /* updates first */
-                 r = solv->rules + solv->updaterules + (i - installed->start);
-                 rr = r;
-                 if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
-                   rr -= solv->installed->end - solv->installed->start;
-                 if (!rr->p)           /* identical to update rule? */
-                   rr = r;
-                 if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start]))
-                   continue;           /* orpaned package */
-
-                 /* check if we should update this package to the latest version
-                  * noupdate is set for erase jobs, in that case we want to deinstall
-                  * the installed package and not replace it with a newer version
-                  * rr->p != i is for dup jobs where the installed package cannot be kept */
-                 queue_empty(&dq);
-                 if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i)))
-                   {
-                     if (!rr->p)
-                       {
-                         /* specialupdater with no update/feature rule */
-                         for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; )
-                           {
-                             if (solv->decisionmap[p] > 0)
-                               {
-                                 dq.count = 0;
-                                 break;
-                               }
-                             if (!solv->decisionmap[p])
-                               queue_push(&dq, p);
-                           }
-                       }
-                     else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
-                       {
-                         /* special multiversion handling, make sure best version is chosen */
-                         if (rr->p == i && solv->decisionmap[i] >= 0)
-                           queue_push(&dq, i);
-                         while ((p = pool->whatprovidesdata[d++]) != 0)
-                           if (solv->decisionmap[p] >= 0)
-                             queue_push(&dq, p);
-                         if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
-                           prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
-                         if (dq.count)
-                           {
-                             policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
-                             p = dq.elements[0];
-                             if (p != i && solv->decisionmap[p] == 0)
-                               {
-                                 rr = solv->rules + solv->featurerules + (i - solv->installed->start);
-                                 if (!rr->p)           /* update rule == feature rule? */
-                                   rr = rr - solv->featurerules + solv->updaterules;
-                                 dq.count = 1;
-                               }
-                             else
-                               dq.count = 0;
-                           }
-                       }
-                     else
-                       {
-                         /* update to best package of the update rule */
-                         FOR_RULELITERALS(p, pp, rr)
-                           {
-                             if (solv->decisionmap[p] > 0)
-                               {
-                                 dq.count = 0;         /* already fulfilled */
-                                 break;
-                               }
-                             if (!solv->decisionmap[p])
-                               queue_push(&dq, p);
-                           }
-                       }
-                   }
-                 if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
-                   prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
-                 /* install best version */
-                 if (dq.count)
-                   {
-                     olevel = level;
-                     level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
-                     if (level <= olevel)
-                       {
-                         if (level < passlevel)
-                           break;      /* trouble */
-                         if (level < olevel)
-                           n = installed->start;       /* redo all */
-                         i--;
-                         n--;
-                         continue;
-                       }
-                   }
-                 /* if still undecided keep package */
-                 if (solv->decisionmap[i] == 0)
-                   {
-                     olevel = level;
-                     if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
-                       {
-#if 0
-                         POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
-                         level = setpropagatelearn(solv, level, -i, disablerules, 0);
-#else
-                         continue;
-#endif
-                       }
-                     else
-                       {
-                         POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
-                         level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
-                       }
-                     if (level <= olevel)
-                       {
-                         if (level < passlevel)
-                           break;      /* trouble */
-                         if (level < olevel)
-                           n = installed->start;       /* redo all */
-                         i--;
-                         n--;
-                         continue;     /* retry with learnt rule */
-                       }
-                   }
-               }
-             if (n < installed->end)
-               {
-                 installedpos = i;     /* retry problem solvable next time */
-                 break;                /* ran into trouble */
-               }
-             installedpos = installed->start;  /* reset installedpos */
-           }
-         systemlevel = level + 1;
-         if (pass < 2)
-           continue;           /* had trouble, retry */
-       }
-      if (!solv->decisioncnt_keep)
-       solv->decisioncnt_keep = solv->decisionq.count;
-
-     if (level < systemlevel && solv->focus_installed)
-       {
-         olevel = level;
-         level = resolve_jobrules(solv, level, disablerules, &dq);
-         if (level < olevel)
-           continue;
-         systemlevel = level + 1;
-       }
-
-      if (level < systemlevel)
-        systemlevel = level;
-
-      /*
-       * decide
-       */
-      if (!solv->decisioncnt_resolve)
-        solv->decisioncnt_resolve = solv->decisionq.count;
-      POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
-      postponed = 0;
-      for (i = 1, n = 1; ; i++, n++)
-       {
-         if (n >= solv->nrules)
-           {
-             if (postponed <= 0)
-               break;
-             i = postponed;
-             postponed = -1;
-             n = 1;
-           }
-         if (i == solv->nrules)
-           i = 1;
-         r = solv->rules + i;
-         if (r->d < 0)         /* ignore disabled rules */
-           continue;
-         if (r->p < 0)         /* most common cases first */
-           {
-             if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
-               continue;
-           }
-         if (dq.count)
-           queue_empty(&dq);
-         if (r->d == 0)
-           {
-             /* binary or unary rule */
-             /* need two positive undecided literals, r->p already checked above */
-             if (r->w2 <= 0)
-               continue;
-             if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
-               continue;
-             queue_push(&dq, r->p);
-             queue_push(&dq, r->w2);
-           }
-         else
-           {
-             /* make sure that
-               * all negative literals are installed
-               * no positive literal is installed
-              * i.e. the rule is not fulfilled and we
-               * just need to decide on the positive literals
-              * (decisionmap[-r->p] for the r->p < 0 case is already checked above)
-               */
-             if (r->p >= 0)
-               {
-                 if (solv->decisionmap[r->p] > 0)
-                   continue;
-                 if (solv->decisionmap[r->p] == 0)
-                   queue_push(&dq, r->p);
-               }
-             dp = pool->whatprovidesdata + r->d;
-             while ((p = *dp++) != 0)
-               {
-                 if (p < 0)
-                   {
-                     if (solv->decisionmap[-p] <= 0)
-                       break;
-                   }
-                 else
-                   {
-                     if (solv->decisionmap[p] > 0)
-                       break;
-                     if (solv->decisionmap[p] == 0)
-                       queue_push(&dq, p);
-                   }
-               }
-             if (p)
-               continue;
-           }
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
-           {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
-             solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
-           }
-         /* dq.count < 2 cannot happen as this means that
-          * the rule is unit */
-         assert(dq.count > 1);
-
-         /* prune to cleandeps packages */
-         if (solv->cleandepsmap.size && solv->installed)
-           {
-             Repo *installed = solv->installed;
-             for (j = 0; j < dq.count; j++)
-               if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
-                 break;
-             if (j < dq.count)
-               {
-                 dq.elements[0] = dq.elements[j];
-                 queue_truncate(&dq, 1);
-               }
-           }
-
-         if (dq.count > 1 && postponed >= 0)
-           {
-             policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE_NOREORDER);
-             if (dq.count > 1)
-               {
-                 if (!postponed)
-                   postponed = i;
-                 continue;
-               }
-           }
-
-         olevel = level;
-         level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
-         if (level < systemlevel)
-           break;              /* trouble */
-         /* something changed, so look at all rules again */
-         n = 0;
-       }
-
-      if (n < solv->nrules)    /* ran into trouble? */
-        continue;              /* start over */
-
-      /* decide leftover cleandeps packages */
-      if (solv->cleandepsmap.size && solv->installed)
-       {
-         for (p = solv->installed->start; p < solv->installed->end; p++)
-           {
-             s = pool->solvables + p;
-             if (s->repo != solv->installed)
-               continue;
-             if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
-               {
-                 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
-                 olevel = level;
-                 level = setpropagatelearn(solv, level, -p, 0, 0);
-                 if (level < olevel)
-                   break;
-               }
-           }
-         if (p < solv->installed->end)
-           continue;
-       }
-
-      /* at this point we have a consistent system. now do the extras... */
-
-      if (!solv->decisioncnt_weak)
-        solv->decisioncnt_weak = solv->decisionq.count;
-      if (doweak)
-       {
-         int qcount;
-
-         POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
-         queue_empty(&dq);     /* recommended packages */
-         queue_empty(&dqs);    /* supplemented packages */
-         for (i = 1; i < pool->nsolvables; i++)
-           {
-             if (solv->decisionmap[i] < 0)
-               continue;
-             if (solv->decisionmap[i] > 0)
-               {
-                 /* installed, check for recommends */
-                 Id *recp, rec, pp, p;
-                 s = pool->solvables + i;
-                 if (!solv->addalreadyrecommended && s->repo == solv->installed)
-                   continue;
-                 /* XXX need to special case AND ? */
-                 if (s->recommends)
-                   {
-                     recp = s->repo->idarraydata + s->recommends;
-                     while ((rec = *recp++) != 0)
-                       {
-#ifdef ENABLE_COMPLEX_DEPS
-                         if (pool_is_complex_dep(pool, rec))
-                           {
-                             add_complex_recommends(solv, rec, &dq, 0);
-                             continue;
-                           }
-#endif
-                         qcount = dq.count;
-                         FOR_PROVIDES(p, pp, rec)
-                           {
-                             if (solv->decisionmap[p] > 0)
-                               {
-                                 dq.count = qcount;
-                                 break;
-                               }
-                             else if (solv->decisionmap[p] == 0)
-                               {
-                                 if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
-                                   continue;
-                                 queue_pushunique(&dq, p);
-                               }
-                           }
-                       }
-                   }
-               }
-             else
-               {
-                 s = pool->solvables + i;
-                 if (!s->supplements)
-                   continue;
-                 if (!pool_installable(pool, s))
-                   continue;
-                 if (!solver_is_supplementing(solv, s))
-                   continue;
-                 if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
-                   continue;
-                 queue_push(&dqs, i);
-               }
-           }
-
-         /* filter out all packages obsoleted by installed packages */
-         /* this is no longer needed if we have reverse obsoletes */
-          if ((dqs.count || dq.count) && solv->installed)
-           {
-             Map obsmap;
-             Id obs, *obsp, po, ppo;
-
-             map_init(&obsmap, pool->nsolvables);
-             for (p = solv->installed->start; p < solv->installed->end; p++)
-               {
-                 s = pool->solvables + p;
-                 if (s->repo != solv->installed || !s->obsoletes)
-                   continue;
-                 if (solv->decisionmap[p] <= 0)
-                   continue;
-                 if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p))
-                   continue;
-                 obsp = s->repo->idarraydata + s->obsoletes;
-                 /* foreach obsoletes */
-                 while ((obs = *obsp++) != 0)
-                   FOR_PROVIDES(po, ppo, obs)
-                     {
-                       Solvable *pos = pool->solvables + po;
-                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs))
-                         continue;
-                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos))
-                         continue;
-                       MAPSET(&obsmap, po);
-                     }
-               }
-             for (i = j = 0; i < dqs.count; i++)
-               if (!MAPTST(&obsmap, dqs.elements[i]))
-                 dqs.elements[j++] = dqs.elements[i];
-             dqs.count = j;
-             for (i = j = 0; i < dq.count; i++)
-               if (!MAPTST(&obsmap, dq.elements[i]))
-                 dq.elements[j++] = dq.elements[i];
-             dq.count = j;
-             map_free(&obsmap);
-           }
-
-          /* filter out all already supplemented packages if requested */
-          if (!solv->addalreadyrecommended && dqs.count)
-           {
-             /* filter out old supplements */
-             for (i = j = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 s = pool->solvables + p;
-                 if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s))
-                   dqs.elements[j++] = p;
-               }
-             dqs.count = j;
-           }
-
-         /* multiversion doesn't mix well with supplements.
-          * filter supplemented packages where we already decided
-          * to install a different version (see bnc#501088) */
-          if (dqs.count && solv->multiversion.size)
-           {
-             for (i = j = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 if (MAPTST(&solv->multiversion, p))
-                   {
-                     Id p2, pp2;
-                     s = pool->solvables + p;
-                     FOR_PROVIDES(p2, pp2, s->name)
-                       if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
-                         break;
-                     if (p2)
-                       continue;       /* ignore this package */
-                   }
-                 dqs.elements[j++] = p;
-               }
-             dqs.count = j;
-           }
-
-          /* make dq contain both recommended and supplemented pkgs */
-         if (dqs.count)
-           {
-             for (i = 0; i < dqs.count; i++)
-               queue_pushunique(&dq, dqs.elements[i]);
-           }
-
-         if (dq.count)
-           {
-             Map dqmap;
-             int decisioncount = solv->decisionq.count;
-
-             if (dq.count == 1)
-               {
-                 /* simple case, just one package. no need to choose to best version */
-                 p = dq.elements[0];
-                 if (dqs.count)
-                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
-                 else
-                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
-                 level = setpropagatelearn(solv, level, p, 0, 0);
-                 continue;     /* back to main loop */
-               }
-
-             /* filter packages, this gives us the best versions */
-             policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
-
-             /* create map of result */
-             map_init(&dqmap, pool->nsolvables);
-             for (i = 0; i < dq.count; i++)
-               MAPSET(&dqmap, dq.elements[i]);
-
-             /* install all supplemented packages */
-             for (i = 0; i < dqs.count; i++)
-               {
-                 p = dqs.elements[i];
-                 if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
-                   continue;
-                 POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
-                 olevel = level;
-                 level = setpropagatelearn(solv, level, p, 0, 0);
-                 if (level <= olevel)
-                   break;
-               }
-             if (i < dqs.count || solv->decisionq.count < decisioncount)
-               {
-                 map_free(&dqmap);
-                 continue;
-               }
-
-             /* install all recommended packages */
-             /* more work as we want to created branches if multiple
-               * choices are valid */
-             for (i = 0; i < decisioncount; i++)
-               {
-                 Id rec, *recp, pp;
-                 p = solv->decisionq.elements[i];
-                 if (p < 0)
-                   continue;
-                 s = pool->solvables + p;
-                 if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
-                   continue;
-                 if (!s->recommends)
-                   continue;
-                 recp = s->repo->idarraydata + s->recommends;
-                 while ((rec = *recp++) != 0)
-                   {
-                     queue_empty(&dq);
-#ifdef ENABLE_COMPLEX_DEPS
-                     if (pool_is_complex_dep(pool, rec))
-                         add_complex_recommends(solv, rec, &dq, &dqmap);
-                     else
-#endif
-                     FOR_PROVIDES(p, pp, rec)
-                       {
-                         if (solv->decisionmap[p] > 0)
-                           {
-                             dq.count = 0;
-                             break;
-                           }
-                         else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
-                           queue_push(&dq, p);
-                       }
-                     if (!dq.count)
-                       continue;
-                     if (dq.count > 1)
-                       policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
-                     /* if we have multiple candidates we open a branch */
-                     if (dq.count > 1)
-                         createbranch(solv, level, &dq, s - pool->solvables, rec);
-                     p = dq.elements[0];
-                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
-                     olevel = level;
-                     level = setpropagatelearn(solv, level, p, 0, 0);
-                     if (level <= olevel || solv->decisionq.count < decisioncount)
-                       break;  /* we had to revert some decisions */
-                   }
-                 if (rec)
-                   break;      /* had a problem above, quit loop */
-               }
-             map_free(&dqmap);
-             continue;         /* back to main loop so that all deps are checked */
-           }
-       }
-
-      if (!solv->decisioncnt_orphan)
-        solv->decisioncnt_orphan = solv->decisionq.count;
-      if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules))
-       {
-         int installedone = 0;
-
-         /* let's see if we can install some unsupported package */
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
-         for (i = 0; i < solv->orphaned.count; i++)
-           {
-             p = solv->orphaned.elements[i];
-             if (solv->decisionmap[p])
-               continue;       /* already decided */
-             if (solv->droporphanedmap_all)
-               continue;
-             if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
-               continue;
-             POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
-             olevel = level;
-             level = setpropagatelearn(solv, level, p, 0, 0);
-             installedone = 1;
-             if (level < olevel)
-               break;
-           }
-         if (installedone || i < solv->orphaned.count)
-           continue;           /* back to main loop */
-         for (i = 0; i < solv->orphaned.count; i++)
-           {
-             p = solv->orphaned.elements[i];
-             if (solv->decisionmap[p])
-               continue;       /* already decided */
-             POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
-             olevel = level;
-             level = setpropagatelearn(solv, level, -p, 0, 0);
-             if (level < olevel)
-               break;
-           }
-         if (i < solv->orphaned.count)
-           continue;           /* back to main loop */
-          if (solv->brokenorphanrules)
-           {
-             solver_check_brokenorphanrules(solv, &dq);
-             if (dq.count)
-               {
-                 policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
-                 for (i = 0; i < dq.count; i++)
-                   {
-                     p = dq.elements[i];
-                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p));
-                     olevel = level;
-                     level = setpropagatelearn(solv, level, p, 0, 0);
-                     if (level < olevel)
-                       break;
-                   }
-                 continue;
-               }
-           }
-       }
-
-     /* one final pass to make sure we decided all installed packages */
-      if (solv->installed)
-       {
-         for (p = solv->installed->start; p < solv->installed->end; p++)
-           {
-             if (solv->decisionmap[p])
-               continue;       /* already decided */
-             s = pool->solvables + p;
-             if (s->repo != solv->installed)
-               continue;
-             POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p));
-             olevel = level;
-             level = setpropagatelearn(solv, level, -p, 0, 0);
-             if (level < olevel)
-               break;
-           }
-         if (p < solv->installed->end)
-           continue;           /* back to main loop */
-       }
-
-      if (solv->installed && solv->cleandepsmap.size && cleandeps_check_mistakes(solv))
-       {
-         solver_reset(solv);
-         level = 0;    /* restart from scratch */
-         continue;
-       }
-
-      if (solv->solution_callback)
-       {
-         solv->solution_callback(solv, solv->solution_callback_data);
-         if (solv->branches.count)
-           {
-             int l, endi = 0;
-             p = l = 0;
-             for (i = solv->branches.count - 1; i >= 0; i--)
-               {
-                 p = solv->branches.elements[i];
-                 if (p > 0 && !l)
-                   {
-                     endi = i + 1;
-                     l = p;
-                     i -= 3;   /* skip: p data count */
-                   }
-                 else if (p > 0)
-                   break;
-                 else if (p < 0)
-                   l = 0;
-               }
-             if (i >= 0)
-               {
-                 while (i > 0 && solv->branches.elements[i - 1] > 0)
-                   i--;
-                 level = takebranch(solv, i, endi, "branching", disablerules);
-                 continue;
-               }
-           }
-         /* all branches done, we're finally finished */
-         break;
-       }
-
-      /* auto-minimization step */
-      if (solv->branches.count)
-       {
-         int endi, lasti = -1, lastiend = -1;
-         if (solv->recommends_index < solv->decisionq.count)
-           policy_update_recommendsmap(solv);
-         for (endi = solv->branches.count; endi > 0;)
-           {
-             int l, lastsi = -1, starti = endi - solv->branches.elements[endi - 2];
-             l = solv->branches.elements[endi - 1];
-             for (i = starti; i < endi - 4; i++)
-               {
-                 p = solv->branches.elements[i];
-                 if (p <= 0)
-                   continue;
-                 if (solv->decisionmap[p] > l)
-                   {
-                     lasti = i;
-                     lastiend = endi;
-                     lastsi = -1;
-                     break;
-                   }
-                 if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
-                   lastsi = i;
-               }
-             if (lastsi >= 0)
-               {
-                 /* we have a recommended package that could not be installed */
-                 /* take it if our current selection is not recommended */
-                 for (i = starti; i < endi - 4; i++)
-                   {
-                     p = -solv->branches.elements[i];
-                     if (p <= 0 || solv->decisionmap[p] != l + 1)
-                       continue;
-                     if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
-                       {
-                         lasti = lastsi;
-                         lastiend = endi;
-                         break;
-                       }
-                   }
-               }
-             endi = starti;
-           }
-         if (lasti >= 0)
-           {
-             minimizationsteps++;
-             level = takebranch(solv, lasti, lastiend, "minimizing", disablerules);
-             continue;         /* back to main loop */
-           }
-       }
-      /* no minimization found, we're finally finished! */
-      break;
-    }
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
-  queue_free(&dq);
-  queue_free(&dqs);
-  if (level < 0)
-    {
-      /* unsolvable */
-      solv->decisioncnt_jobs = solv->decisionq.count;
-      solv->decisioncnt_update = solv->decisionq.count;
-      solv->decisioncnt_keep = solv->decisionq.count;
-      solv->decisioncnt_resolve = solv->decisionq.count;
-      solv->decisioncnt_weak = solv->decisionq.count;
-      solv->decisioncnt_orphan = solv->decisionq.count;
-    }
-#if 0
-  solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
-#endif
-}
-
-
-/*-------------------------------------------------------------------
- *
- * remove disabled conflicts
- *
- * purpose: update the decisionmap after some rules were disabled.
- * this is used to calculate the suggested/recommended package list.
- * Also returns a "removed" list to undo the discisionmap changes.
- */
-
-static void
-removedisabledconflicts(Solver *solv, Queue *removed)
-{
-  Pool *pool = solv->pool;
-  int i, n;
-  Id p, why, *dp;
-  Id new;
-  Rule *r;
-  Id *decisionmap = solv->decisionmap;
-
-  queue_empty(removed);
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p > 0)
-       continue;       /* conflicts only, please */
-      why = solv->decisionq_why.elements[i];
-      if (why == 0)
-       {
-         /* no rule involved, must be a orphan package drop */
-         continue;
-       }
-      /* we never do conflicts on free decisions, so there
-       * must have been an unit rule */
-      assert(why > 0);
-      r = solv->rules + why;
-      if (r->d < 0 && decisionmap[-p])
-       {
-         /* rule is now disabled, remove from decisionmap */
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
-         queue_push(removed, -p);
-         queue_push(removed, decisionmap[-p]);
-         decisionmap[-p] = 0;
-       }
-    }
-  if (!removed->count)
-    return;
-  /* we removed some confliced packages. some of them might still
-   * be in conflict, so search for unit rules and re-conflict */
-  new = 0;
-  for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
-    {
-      if (i == solv->nrules)
-       {
-         i = 1;
-         r = solv->rules + i;
-       }
-      if (r->d < 0)
-       continue;
-      if (!r->w2)
-       {
-         if (r->p < 0 && !decisionmap[-r->p])
-           new = r->p;
-       }
-      else if (!r->d)
-       {
-         /* binary rule */
-         if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
-           new = r->p;
-         else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
-           new = r->w2;
-       }
-      else
-       {
-         if (r->p < 0 && decisionmap[-r->p] == 0)
-           new = r->p;
-         if (new || DECISIONMAP_FALSE(r->p))
-           {
-             dp = pool->whatprovidesdata + r->d;
-             while ((p = *dp++) != 0)
-               {
-                 if (new && p == new)
-                   continue;
-                 if (p < 0 && decisionmap[-p] == 0)
-                   {
-                     if (new)
-                       {
-                         new = 0;
-                         break;
-                       }
-                     new = p;
-                   }
-                 else if (!DECISIONMAP_FALSE(p))
-                   {
-                     new = 0;
-                     break;
-                   }
-               }
-           }
-       }
-      if (new)
-       {
-         POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
-         decisionmap[-new] = -1;
-         new = 0;
-         n = 0;        /* redo all rules */
-       }
-    }
-}
-
-static inline void
-undo_removedisabledconflicts(Solver *solv, Queue *removed)
-{
-  int i;
-  for (i = 0; i < removed->count; i += 2)
-    solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
-}
-
-
-/*-------------------------------------------------------------------
- *
- * weaken solvable dependencies
- */
-
-static void
-weaken_solvable_deps(Solver *solv, Id p)
-{
-  int i;
-  Rule *r;
-
-  for (i = 1, r = solv->rules + i; i < solv->pkgrules_end; i++, r++)
-    {
-      if (r->p != -p)
-       continue;
-      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
-       continue;       /* conflict */
-      queue_push(&solv->weakruleq, i);
-    }
-}
-
-
-/********************************************************************/
-/* main() */
-
-
-void
-solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap)
-{
-  int i;
-  Id how, what, select;
-  Id p, pp;
-  for (i = 0; i < job->count; i += 2)
-    {
-      how = job->elements[i];
-      if ((how & SOLVER_JOBMASK) != SOLVER_MULTIVERSION)
-       continue;
-      what = job->elements[i + 1];
-      select = how & SOLVER_SELECTMASK;
-      if (!multiversionmap->size)
-       map_grow(multiversionmap, pool->nsolvables);
-      if (select == SOLVER_SOLVABLE_ALL)
-       {
-         FOR_POOL_SOLVABLES(p)
-           MAPSET(multiversionmap, p);
-       }
-      else if (select == SOLVER_SOLVABLE_REPO)
-       {
-         Solvable *s;
-         Repo *repo = pool_id2repo(pool, what);
-         if (repo)
-           FOR_REPO_SOLVABLES(repo, p, s)
-             MAPSET(multiversionmap, p);
-       }
-      FOR_JOB_SELECT(p, pp, select, what)
-        MAPSET(multiversionmap, p);
-    }
-}
-
-void
-solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap)
-{
-  solver_calculate_multiversionmap(pool, job, multiversionmap);
-}
-
-/*
- * add a rule created by a job, record job number and weak flag
- */
-static inline void
-solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak)
-{
-  solver_addrule(solv, p, p2, d);
-  queue_push(&solv->ruletojob, job);
-  if (weak)
-    queue_push(&solv->weakruleq, solv->nrules - 1);
-}
-
-static inline void
-add_cleandeps_package(Solver *solv, Id p)
-{
-  if (!solv->cleandeps_updatepkgs)
-    {
-      solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
-      queue_init(solv->cleandeps_updatepkgs);
-    }
-  queue_pushunique(solv->cleandeps_updatepkgs, p);
-}
-
-static void
-add_update_target(Solver *solv, Id p, Id how)
-{
-  Pool *pool = solv->pool;
-  Solvable *s = pool->solvables + p;
-  Repo *installed = solv->installed;
-  Id pi, pip;
-  if (!solv->update_targets)
-    {
-      solv->update_targets = solv_calloc(1, sizeof(Queue));
-      queue_init(solv->update_targets);
-    }
-  if (s->repo == installed)
-    {
-      queue_push2(solv->update_targets, p, p);
-      return;
-    }
-  FOR_PROVIDES(pi, pip, s->name)
-    {
-      Solvable *si = pool->solvables + pi;
-      if (si->repo != installed || si->name != s->name)
-       continue;
-      if (how & SOLVER_FORCEBEST)
-       {
-         if (!solv->bestupdatemap.size)
-           map_grow(&solv->bestupdatemap, installed->end - installed->start);
-         MAPSET(&solv->bestupdatemap, pi - installed->start);
-       }
-      if (how & SOLVER_CLEANDEPS)
-       add_cleandeps_package(solv, pi);
-      queue_push2(solv->update_targets, pi, p);
-      /* check if it's ok to keep the installed package */
-      if (s->evr == si->evr && solvable_identical(s, si))
-        queue_push2(solv->update_targets, pi, pi);
-    }
-  if (s->obsoletes)
-    {
-      Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-      while ((obs = *obsp++) != 0)
-       {
-         FOR_PROVIDES(pi, pip, obs)
-           {
-             Solvable *si = pool->solvables + pi;
-             if (si->repo != installed)
-               continue;
-             if (si->name == s->name)
-               continue;       /* already handled above */
-             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
-               continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
-               continue;
-             if (how & SOLVER_FORCEBEST)
-               {
-                 if (!solv->bestupdatemap.size)
-                   map_grow(&solv->bestupdatemap, installed->end - installed->start);
-                 MAPSET(&solv->bestupdatemap, pi - installed->start);
-               }
-             if (how & SOLVER_CLEANDEPS)
-               add_cleandeps_package(solv, pi);
-             queue_push2(solv->update_targets, pi, p);
-           }
-       }
-    }
-}
-
-static int
-transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap;
-  const Id *b = bp;
-  if (a[0] - b[0])
-    return a[0] - b[0];
-  return a[1] - b[1];
-}
-
-static void
-transform_update_targets(Solver *solv)
-{
-  Repo *installed = solv->installed;
-  Queue *update_targets = solv->update_targets;
-  int i, j;
-  Id p, q, lastp, lastq;
-
-  if (!update_targets->count)
-    {
-      queue_free(update_targets);
-      solv->update_targets = solv_free(update_targets);
-      return;
-    }
-  if (update_targets->count > 2)
-    solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
-  queue_insertn(update_targets, 0, installed->end - installed->start, 0);
-  lastp = lastq = 0;
-  for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
-    {
-      if ((p = update_targets->elements[i]) != lastp)
-       {
-         if (!solv->updatemap.size)
-           map_grow(&solv->updatemap, installed->end - installed->start);
-         MAPSET(&solv->updatemap, p - installed->start);
-         update_targets->elements[j++] = 0;                    /* finish old set */
-         update_targets->elements[p - installed->start] = j;   /* start new set */
-         lastp = p;
-         lastq = 0;
-       }
-      if ((q = update_targets->elements[i + 1]) != lastq)
-       {
-          update_targets->elements[j++] = q;
-         lastq = q;
-       }
-    }
-  queue_truncate(update_targets, j);
-  queue_push(update_targets, 0);       /* finish last set */
-}
-
-
-static void
-addedmap2deduceq(Solver *solv, Map *addedmap)
-{
-  Pool *pool = solv->pool;
-  int i, j;
-  Id p;
-  Rule *r;
-
-  queue_empty(&solv->addedmap_deduceq);
-  for (i = 2, j = solv->pkgrules_end - 1; i < pool->nsolvables && j > 0; j--)
-    {
-      r = solv->rules + j;
-      if (r->p >= 0)
-       continue;
-      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
-       continue;
-      p = -r->p;
-      if (!MAPTST(addedmap, p))
-       {
-         /* should never happen, but... */
-         if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
-            queue_push(&solv->addedmap_deduceq, -p);
-         continue;
-       }
-      for (; i < p; i++)
-        if (MAPTST(addedmap, i))
-          queue_push(&solv->addedmap_deduceq, i);
-      if (i == p)
-        i++;
-    }
-  for (; i < pool->nsolvables; i++)
-    if (MAPTST(addedmap, i))
-      queue_push(&solv->addedmap_deduceq, i);
-  j = 0;
-  for (i = 2; i < pool->nsolvables; i++)
-    if (MAPTST(addedmap, i))
-      j++;
-}
-
-static void
-deduceq2addedmap(Solver *solv, Map *addedmap)
-{
-  int j;
-  Id p;
-  Rule *r;
-  for (j = solv->pkgrules_end - 1; j > 0; j--)
-    {
-      r = solv->rules + j;
-      if (r->d < 0 && r->p)
-       solver_enablerule(solv, r);
-      if (r->p >= 0)
-       continue;
-      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
-       continue;
-      p = -r->p;
-      MAPSET(addedmap, p);
-    }
-  for (j = 0; j < solv->addedmap_deduceq.count; j++)
-    {
-      p = solv->addedmap_deduceq.elements[j];
-      if (p > 0)
-       MAPSET(addedmap, p);
-      else
-       MAPCLR(addedmap, p);
-    }
-}
-
-#ifdef ENABLE_COMPLEX_DEPS
-static int
-add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak)
-{
-  Pool *pool = solv->pool;
-  Queue bq;
-  int i, j;
-
-  queue_init(&bq);
-  i = pool_normalize_complex_dep(pool, dep, &bq, flags | CPLXDEPS_EXPAND);
-  if (i == 0 || i == 1)
-    {
-      queue_free(&bq);
-      if (i == 0)
-        solver_addjobrule(solv, -SYSTEMSOLVABLE, 0, 0, jobidx, weak);
-      return 0;
-    }
-  for (i = 0; i < bq.count; i++)
-    {
-      if (!bq.elements[i])
-       continue;
-      for (j = 0; bq.elements[i + j + 1]; j++)
-        ;
-      if (j > 1)
-        solver_addjobrule(solv, bq.elements[i], 0, pool_ids2whatprovides(pool, bq.elements + i + 1, j), jobidx, weak);
-      else
-        solver_addjobrule(solv, bq.elements[i], bq.elements[i + 1], 0, jobidx, weak);
-      i += j + 1;
-    }
-  queue_free(&bq);
-  return 1;
-}
-#endif
-
-/*
- *
- * solve job queue
- *
- */
-
-int
-solver_solve(Solver *solv, Queue *job)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  int i;
-  int oldnrules, initialnrules;
-  Map addedmap;                       /* '1' == have pkg-rules for solvable */
-  Map installcandidatemap;
-  Id how, what, select, name, weak, p, pp, d;
-  Queue q;
-  Solvable *s;
-  Rule *r;
-  int now, solve_start;
-  int needduprules = 0;
-  int hasbestinstalljob = 0;
-
-  solve_start = solv_timems(0);
-
-  /* log solver options */
-  POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
-  POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
-
-  /* create whatprovides if not already there */
-  if (!pool->whatprovides)
-    pool_createwhatprovides(pool);
-
-  /* create obsolete index */
-  policy_create_obsolete_index(solv);
-
-  /* remember job */
-  queue_free(&solv->job);
-  queue_init_clone(&solv->job, job);
-  solv->pooljobcnt = pool->pooljobs.count;
-  if (pool->pooljobs.count)
-    queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
-  job = &solv->job;
-
-  /* free old stuff in jase we re-run a solver */
-  queuep_free(&solv->update_targets);
-  queuep_free(&solv->cleandeps_updatepkgs);
-  queue_empty(&solv->ruleassertions);
-  solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
-  solv->yumobsrules_info = solv_free(solv->yumobsrules_info);
-  solv->choicerules_ref = solv_free(solv->choicerules_ref);
-  if (solv->noupdate.size)
-    map_empty(&solv->noupdate);
-  map_zerosize(&solv->multiversion);
-  solv->updatemap_all = 0;
-  map_zerosize(&solv->updatemap);
-  solv->bestupdatemap_all = 0;
-  map_zerosize(&solv->bestupdatemap);
-  solv->fixmap_all = 0;
-  map_zerosize(&solv->fixmap);
-  solv->dupmap_all = 0;
-  map_zerosize(&solv->dupmap);
-  map_zerosize(&solv->dupinvolvedmap);
-  solv->droporphanedmap_all = 0;
-  map_zerosize(&solv->droporphanedmap);
-  solv->allowuninstall_all = 0;
-  map_zerosize(&solv->allowuninstallmap);
-  map_zerosize(&solv->cleandepsmap);
-  map_zerosize(&solv->weakrulemap);
-  queue_empty(&solv->weakruleq);
-  solv->watches = solv_free(solv->watches);
-  queue_empty(&solv->ruletojob);
-  if (solv->decisionq.count)
-    memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
-  queue_empty(&solv->decisionq);
-  queue_empty(&solv->decisionq_why);
-  solv->decisioncnt_jobs = solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
-  queue_empty(&solv->learnt_why);
-  queue_empty(&solv->learnt_pool);
-  queue_empty(&solv->branches);
-  solv->propagate_index = 0;
-  queue_empty(&solv->problems);
-  queue_empty(&solv->solutions);
-  queue_empty(&solv->orphaned);
-  solv->stats_learned = solv->stats_unsolvable = 0;
-  if (solv->recommends_index)
-    {
-      map_empty(&solv->recommendsmap);
-      map_empty(&solv->suggestsmap);
-      queuep_free(&solv->recommendscplxq);
-      queuep_free(&solv->suggestscplxq);
-      solv->recommends_index = 0;
-    }
-  queuep_free(&solv->brokenorphanrules);
-  solv->specialupdaters = solv_free(solv->specialupdaters);
-
-
-  /*
-   * create basic rule set of all involved packages
-   * use addedmap bitmap to make sure we don't create rules twice
-   */
-
-  /* create multiversion map if needed */
-  solver_calculate_multiversionmap(pool, job, &solv->multiversion);
-
-  map_init(&addedmap, pool->nsolvables);
-  MAPSET(&addedmap, SYSTEMSOLVABLE);
-
-  map_init(&installcandidatemap, pool->nsolvables);
-  queue_init(&q);
-
-  now = solv_timems(0);
-  /*
-   * create rules for all package that could be involved with the solving
-   * so called: pkg rules
-   *
-   */
-  initialnrules = solv->pkgrules_end ? solv->pkgrules_end : 1;
-  if (initialnrules > 1)
-    deduceq2addedmap(solv, &addedmap);
-  if (solv->nrules != initialnrules)
-    solver_shrinkrules(solv, initialnrules);
-  solv->nrules = initialnrules;
-  solv->pkgrules_end = 0;
-
-  if (installed)
-    {
-      /* check for update/verify jobs as they need to be known early */
-      /* also setup the droporphaned map, we need it when creating update rules */
-      for (i = 0; i < job->count; i += 2)
-       {
-         how = job->elements[i];
-         what = job->elements[i + 1];
-         select = how & SOLVER_SELECTMASK;
-         switch (how & SOLVER_JOBMASK)
-           {
-           case SOLVER_VERIFY:
-             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
-               solv->fixmap_all = 1;
-             FOR_JOB_SELECT(p, pp, select, what)
-               {
-                 s = pool->solvables + p;
-                 if (s->repo != installed)
-                   continue;
-                 if (!solv->fixmap.size)
-                   map_grow(&solv->fixmap, installed->end - installed->start);
-                 MAPSET(&solv->fixmap, p - installed->start);
-               }
-             break;
-           case SOLVER_UPDATE:
-             if (select == SOLVER_SOLVABLE_ALL)
-               {
-                 solv->updatemap_all = 1;
-                 if (how & SOLVER_FORCEBEST)
-                   solv->bestupdatemap_all = 1;
-                 if (how & SOLVER_CLEANDEPS)
-                   {
-                     FOR_REPO_SOLVABLES(installed, p, s)
-                       add_cleandeps_package(solv, p);
-                   }
-               }
-             else if (select == SOLVER_SOLVABLE_REPO)
-               {
-                 Repo *repo = pool_id2repo(pool, what);
-                 if (!repo)
-                   break;
-                 if (repo == installed && !(how & SOLVER_TARGETED))
-                   {
-                     solv->updatemap_all = 1;
-                     if (how & SOLVER_FORCEBEST)
-                       solv->bestupdatemap_all = 1;
-                     if (how & SOLVER_CLEANDEPS)
-                       {
-                         FOR_REPO_SOLVABLES(installed, p, s)
-                           add_cleandeps_package(solv, p);
-                       }
-                     break;
-                   }
-                 if (solv->noautotarget && !(how & SOLVER_TARGETED))
-                   break;
-                 /* targeted update */
-                 FOR_REPO_SOLVABLES(repo, p, s)
-                   add_update_target(solv, p, how);
-               }
-             else
-               {
-                 if (!(how & SOLVER_TARGETED))
-                   {
-                     int targeted = 1;
-                     FOR_JOB_SELECT(p, pp, select, what)
-                       {
-                         s = pool->solvables + p;
-                         if (s->repo != installed)
-                           continue;
-                         if (!solv->updatemap.size)
-                           map_grow(&solv->updatemap, installed->end - installed->start);
-                         MAPSET(&solv->updatemap, p - installed->start);
-                         if (how & SOLVER_FORCEBEST)
-                           {
-                             if (!solv->bestupdatemap.size)
-                               map_grow(&solv->bestupdatemap, installed->end - installed->start);
-                             MAPSET(&solv->bestupdatemap, p - installed->start);
-                           }
-                         if (how & SOLVER_CLEANDEPS)
-                           add_cleandeps_package(solv, p);
-                         targeted = 0;
-                       }
-                     if (!targeted || solv->noautotarget)
-                       break;
-                   }
-                 FOR_JOB_SELECT(p, pp, select, what)
-                   add_update_target(solv, p, how);
-               }
-             break;
-           case SOLVER_DROP_ORPHANED:
-             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-               solv->droporphanedmap_all = 1;
-             FOR_JOB_SELECT(p, pp, select, what)
-               {
-                 s = pool->solvables + p;
-                 if (s->repo != installed)
-                   continue;
-                 if (!solv->droporphanedmap.size)
-                   map_grow(&solv->droporphanedmap, installed->end - installed->start);
-                 MAPSET(&solv->droporphanedmap, p - installed->start);
-               }
-             break;
-           case SOLVER_ALLOWUNINSTALL:
-             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
-               solv->allowuninstall_all = 1;
-             FOR_JOB_SELECT(p, pp, select, what)
-               {
-                 s = pool->solvables + p;
-                 if (s->repo != installed)
-                   continue;
-                 if (!solv->allowuninstallmap.size)
-                   map_grow(&solv->allowuninstallmap, installed->end - installed->start);
-                 MAPSET(&solv->allowuninstallmap, p - installed->start);
-               }
-             break;
-           default:
-             break;
-           }
-       }
-
-      if (solv->update_targets)
-       transform_update_targets(solv);
-
-      oldnrules = solv->nrules;
-      FOR_REPO_SOLVABLES(installed, p, s)
-       solver_addpkgrulesforsolvable(solv, s, &addedmap);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for installed solvables\n", solv->nrules - oldnrules);
-      oldnrules = solv->nrules;
-      FOR_REPO_SOLVABLES(installed, p, s)
-       solver_addpkgrulesforupdaters(solv, s, &addedmap, 1);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for updaters of installed solvables\n", solv->nrules - oldnrules);
-    }
-
-  /*
-   * create rules for all packages involved in the job
-   * (to be installed or removed)
-   */
-
-  oldnrules = solv->nrules;
-  for (i = 0; i < job->count; i += 2)
-    {
-      how = job->elements[i];
-      what = job->elements[i + 1];
-      select = how & SOLVER_SELECTMASK;
-
-      switch (how & SOLVER_JOBMASK)
-       {
-       case SOLVER_INSTALL:
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             MAPSET(&installcandidatemap, p);
-             solver_addpkgrulesforsolvable(solv, pool->solvables + p, &addedmap);
-           }
-         break;
-       case SOLVER_DISTUPGRADE:
-         if (select == SOLVER_SOLVABLE_ALL)
-           {
-             solv->dupmap_all = 1;
-             solv->updatemap_all = 1;
-             if (how & SOLVER_FORCEBEST)
-               solv->bestupdatemap_all = 1;
-           }
-         if ((how & SOLVER_TARGETED) != 0)
-           needduprules = 1;
-         if (!solv->dupmap_all || solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size || solv->keep_orphans)
-           needduprules = 1;
-         break;
-       default:
-         break;
-       }
-    }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for packages involved in a job\n", solv->nrules - oldnrules);
-
-
-  /*
-   * add rules for suggests, enhances
-   */
-  oldnrules = solv->nrules;
-  solver_addpkgrulesforweak(solv, &addedmap);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of weak dependencies\n", solv->nrules - oldnrules);
-
-#ifdef ENABLE_LINKED_PKGS
-  oldnrules = solv->nrules;
-  solver_addpkgrulesforlinked(solv, &addedmap);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of linked packages\n", solv->nrules - oldnrules);
-#endif
-
-  /*
-   * first pass done, we now have all the pkg rules we need.
-   * unify existing rules before going over all job rules and
-   * policy rules.
-   * at this point the system is always solvable,
-   * as an empty system (remove all packages) is a valid solution
-   */
-
-  IF_POOLDEBUG (SOLV_DEBUG_STATS)
-    {
-      int possible = 0, installable = 0;
-      for (i = 1; i < pool->nsolvables; i++)
-       {
-         if (pool_installable(pool, pool->solvables + i))
-           installable++;
-         if (MAPTST(&addedmap, i))
-           possible++;
-       }
-      POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
-    }
-
-  if (solv->nrules > initialnrules)
-    solver_unifyrules(solv);                   /* remove duplicate pkg rules */
-  solv->pkgrules_end = solv->nrules;           /* mark end of pkg rules */
-
-  if (solv->nrules > initialnrules)
-    addedmap2deduceq(solv, &addedmap);         /* so that we can recreate the addedmap */
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "pkg rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "pkg rule creation took %d ms\n", solv_timems(now));
-
-  /* create dup maps if needed. We need the maps early to create our
-   * update rules */
-  if (needduprules)
-    solver_createdupmaps(solv);
-
-  /*
-   * create feature rules
-   *
-   * foreach installed:
-   *   create assertion (keep installed, if no update available)
-   *   or
-   *   create update rule (A|update1(A)|update2(A)|...)
-   *
-   * those are used later on to keep a version of the installed packages in
-   * best effort mode
-   */
-
-  solv->featurerules = solv->nrules;              /* mark start of feature rules */
-  if (installed)
-    {
-      /* foreach possibly installed solvable */
-      for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
-       {
-         if (s->repo != installed)
-           {
-             solver_addrule(solv, 0, 0, 0);    /* create dummy rule */
-             continue;
-           }
-         solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
-       }
-      /* make sure we accounted for all rules */
-      assert(solv->nrules - solv->featurerules == installed->end - installed->start);
-    }
-  solv->featurerules_end = solv->nrules;
-
-    /*
-     * Add update rules for installed solvables
-     *
-     * almost identical to feature rules
-     * except that downgrades/archchanges/vendorchanges are not allowed
-     */
-
-  solv->updaterules = solv->nrules;
-
-  if (installed)
-    { /* foreach installed solvables */
-      /* we create all update rules, but disable some later on depending on the job */
-      for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
-       {
-         Rule *sr;
-
-         if (s->repo != installed)
-           {
-             solver_addrule(solv, 0, 0, 0);    /* create dummy rule */
-             continue;
-           }
-         solver_addupdaterule(solv, s, 0);     /* allowall = 0: downgrades not allowed */
-         /*
-          * check for and remove duplicate
-          */
-         r = solv->rules + solv->nrules - 1;           /* r: update rule */
-         sr = r - (installed->end - installed->start); /* sr: feature rule */
-          if (!r->p)
-           {
-             if (sr->p)
-               memset(sr, 0, sizeof(*sr));             /* no feature rules without update rules */
-             continue;
-           }
-         /* it's also orphaned if the feature rule consists just of the installed package */
-         if (!solv->dupmap_all && sr->p == i && !sr->d && !sr->w2)
-           queue_push(&solv->orphaned, i);
-         if (!solver_rulecmp(solv, r, sr))
-           memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
-         else
-           solver_disablerule(solv, sr);       /* disable feature rule for now */
-       }
-      /* consistency check: we added a rule for _every_ installed solvable */
-      assert(solv->nrules - solv->updaterules == installed->end - installed->start);
-    }
-  solv->updaterules_end = solv->nrules;
-
-
-  /*
-   * now add all job rules
-   */
-
-  solv->jobrules = solv->nrules;
-  for (i = 0; i < job->count; i += 2)
-    {
-      oldnrules = solv->nrules;
-
-      if (i && i == solv->pooljobcnt)
-        POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
-      how = job->elements[i];
-      what = job->elements[i + 1];
-      weak = how & SOLVER_WEAK;
-      select = how & SOLVER_SELECTMASK;
-      switch (how & SOLVER_JOBMASK)
-       {
-       case SOLVER_INSTALL:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
-         if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
-           map_grow(&solv->cleandepsmap, installed->end - installed->start);
-         if (select == SOLVER_SOLVABLE)
-           {
-             p = what;
-             d = 0;
-           }
-#ifdef ENABLE_COMPLEX_DEPS
-         else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what))
-           {
-             if (add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? CPLXDEPS_NAME : 0, i, weak))
-               if (how & SOLVER_FORCEBEST)
-                 hasbestinstalljob = 1;
-             break;
-           }
-#endif
-         else
-           {
-             queue_empty(&q);
-             FOR_JOB_SELECT(p, pp, select, what)
-               queue_push(&q, p);
-             if (!q.count)
-               {
-                 if (select == SOLVER_SOLVABLE_ONE_OF)
-                   break;      /* ignore empty installs */
-                 /* no candidate found or unsupported, make this an impossible rule */
-                 queue_push(&q, -SYSTEMSOLVABLE);
-               }
-             p = queue_shift(&q);      /* get first candidate */
-             d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
-           }
-         /* force install of namespace supplements hack */
-         if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
-           {
-             Reldep *rd = GETRELDEP(pool, what);
-             if (rd->flags == REL_NAMESPACE)
-               {
-                 p = SYSTEMSOLVABLE;
-                 if (!solv->installsuppdepq)
-                   {
-                     solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
-                     queue_init(solv->installsuppdepq);
-                   }
-                 queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
-               }
-           }
-         solver_addjobrule(solv, p, 0, d, i, weak);
-          if (how & SOLVER_FORCEBEST)
-           hasbestinstalljob = 1;
-         break;
-       case SOLVER_ERASE:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
-         if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
-           map_grow(&solv->cleandepsmap, installed->end - installed->start);
-         /* specific solvable: by id or by nevra */
-         name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
-         if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
-           {
-             FOR_POOL_SOLVABLES(p)
-               solver_addjobrule(solv, -p, 0, 0, i, weak);
-           }
-         else if (select == SOLVER_SOLVABLE_REPO)
-           {
-             Repo *repo = pool_id2repo(pool, what);
-             if (repo)
-               FOR_REPO_SOLVABLES(repo, p, s)
-                 solver_addjobrule(solv, -p, 0, 0, i, weak);
-           }
-#ifdef ENABLE_COMPLEX_DEPS
-         else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what))
-           {
-             /* no special "erase a specific solvable" handling? */
-             add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? (CPLXDEPS_NAME | CPLXDEPS_TODNF | CPLXDEPS_INVERT) : (CPLXDEPS_TODNF | CPLXDEPS_INVERT), i, weak);
-             break;
-           }
-#endif
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             s = pool->solvables + p;
-             if (installed && s->repo == installed)
-               name = !name ? s->name : -1;
-             solver_addjobrule(solv, -p, 0, 0, i, weak);
-           }
-         /* special case for "erase a specific solvable": we also
-          * erase all other solvables with that name, so that they
-          * don't get picked up as replacement.
-          * name is > 0 if exactly one installed solvable matched.
-          */
-         /* XXX: look also at packages that obsolete this package? */
-         if (name > 0)
-           {
-             int j, k;
-             k = solv->nrules;
-             FOR_PROVIDES(p, pp, name)
-               {
-                 s = pool->solvables + p;
-                 if (s->name != name)
-                   continue;
-                 /* keep other versions installed */
-                 if (s->repo == installed)
-                   continue;
-                 /* keep installcandidates of other jobs */
-                 if (MAPTST(&installcandidatemap, p))
-                   continue;
-                 /* don't add the same rule twice */
-                 for (j = oldnrules; j < k; j++)
-                   if (solv->rules[j].p == -p)
-                     break;
-                 if (j == k)
-                   solver_addjobrule(solv, -p, 0, 0, i, weak); /* remove by id */
-               }
-           }
-         break;
-
-       case SOLVER_UPDATE:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
-         break;
-       case SOLVER_VERIFY:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
-         break;
-       case SOLVER_WEAKENDEPS:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
-         if (select != SOLVER_SOLVABLE)
-           break;
-         s = pool->solvables + what;
-         weaken_solvable_deps(solv, what);
-         break;
-       case SOLVER_MULTIVERSION:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %smultiversion %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
-         break;
-       case SOLVER_LOCK:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
-         if (select == SOLVER_SOLVABLE_ALL)
-           {
-             FOR_POOL_SOLVABLES(p)
-               solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
-           }
-          else if (select == SOLVER_SOLVABLE_REPO)
-           {
-             Repo *repo = pool_id2repo(pool, what);
-             if (repo)
-               FOR_REPO_SOLVABLES(repo, p, s)
-                 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
-           }
-         FOR_JOB_SELECT(p, pp, select, what)
-           solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
-         break;
-       case SOLVER_DISTUPGRADE:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
-         break;
-       case SOLVER_DROP_ORPHANED:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
-         break;
-       case SOLVER_USERINSTALLED:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
-         break;
-       case SOLVER_ALLOWUNINSTALL:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: allowuninstall %s\n", solver_select2str(pool, select, what));
-         break;
-       default:
-         POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
-         break;
-       }
-       
-      IF_POOLDEBUG (SOLV_DEBUG_JOB)
-       {
-         int j;
-         if (solv->nrules == oldnrules)
-           POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
-         for (j = oldnrules; j < solv->nrules; j++)
-           {
-             POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
-             solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
-           }
-       }
-    }
-  assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
-  solv->jobrules_end = solv->nrules;
-
-  /* now create infarch and dup rules */
-  if (!solv->noinfarchcheck)
-    {
-      solver_addinfarchrules(solv, &addedmap);
-#if 0
-      if (pool->implicitobsoleteusescolors)
-       {
-         /* currently doesn't work well with infarch rules, so make
-           * them weak */
-         for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
-           queue_push(&solv->weakruleq, i);
-       }
-#endif
-    }
-  else
-    solv->infarchrules = solv->infarchrules_end = solv->nrules;
-
-  if (needduprules)
-    solver_addduprules(solv, &addedmap);
-  else
-    solv->duprules = solv->duprules_end = solv->nrules;
-
-  if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
-    solver_addbestrules(solv, hasbestinstalljob);
-  else
-    solv->bestrules = solv->bestrules_end = solv->nrules;
-
-  if (needduprules)
-    solver_freedupmaps(solv);  /* no longer needed */
-
-  if (solv->do_yum_obsoletes)
-    solver_addyumobsrules(solv);
-  else
-    solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
-
-  if (1)
-    solver_addchoicerules(solv);
-  else
-    solv->choicerules = solv->choicerules_end = solv->nrules;
-
-  if (0)
-    {
-      for (i = solv->featurerules; i < solv->nrules; i++)
-        solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
-    }
-  /* all rules created
-   * --------------------------------------------------------------
-   * prepare for solving
-   */
-
-  /* free unneeded memory */
-  map_free(&addedmap);
-  map_free(&installcandidatemap);
-  queue_free(&q);
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
-
-  /* create weak map */
-  if (solv->weakruleq.count)
-    {
-      map_grow(&solv->weakrulemap, solv->nrules);
-      for (i = 0; i < solv->weakruleq.count; i++)
-       {
-         p = solv->weakruleq.elements[i];
-         MAPSET(&solv->weakrulemap, p);
-       }
-    }
-
-  /* enable cleandepsmap creation if we have updatepkgs */
-  if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
-    map_grow(&solv->cleandepsmap, installed->end - installed->start);
-  /* no mistakes */
-  if (solv->cleandeps_mistakes)
-    {
-      queue_free(solv->cleandeps_mistakes);
-      solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
-    }
-
-  /* all new rules are learnt after this point */
-  solv->learntrules = solv->nrules;
-
-  /* create watches chains */
-  makewatches(solv);
-
-  /* create assertion index. it is only used to speed up
-   * makeruledecsions() a bit */
-  for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
-    if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
-      queue_push(&solv->ruleassertions, i);
-
-  /* disable update rules that conflict with our job */
-  solver_disablepolicyrules(solv);
-
-  /* break orphans if requested */
-  if (solv->dupmap_all && solv->orphaned.count && solv->break_orphans)
-    solver_breakorphans(solv);
-
-  /*
-   * ********************************************
-   * solve!
-   * ********************************************
-   */
-
-  now = solv_timems(0);
-  solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
-
-  /*
-   * prepare solution queue if there were problems
-   */
-  solver_prepare_solutions(solv);
-
-  POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
-
-  /* return number of problems */
-  return solv->problems.count ? solv->problems.count / 2 : 0;
-}
-
-Transaction *
-solver_create_transaction(Solver *solv)
-{
-  return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->multiversion);
-}
-
-void solver_get_orphaned(Solver *solv, Queue *orphanedq)
-{
-  queue_free(orphanedq);
-  queue_init_clone(orphanedq, &solv->orphaned);
-}
-
-void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
-{
-  Pool *pool = solv->pool;
-  Queue redoq, disabledq;
-  int goterase, i;
-  Solvable *s;
-  Rule *r;
-  Map obsmap;
-
-  if (!recommendationsq && !suggestionsq)
-    return;
-
-  map_init(&obsmap, pool->nsolvables);
-  if (solv->installed)
-    {
-      Id obs, *obsp, p, po, ppo;
-      for (p = solv->installed->start; p < solv->installed->end; p++)
-       {
-         s = pool->solvables + p;
-         if (s->repo != solv->installed || !s->obsoletes)
-           continue;
-         if (solv->decisionmap[p] <= 0)
-           continue;
-         if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
-           continue;
-         obsp = s->repo->idarraydata + s->obsoletes;
-         /* foreach obsoletes */
-         while ((obs = *obsp++) != 0)
-           FOR_PROVIDES(po, ppo, obs)
-             MAPSET(&obsmap, po);
-       }
-    }
-
-  queue_init(&redoq);
-  queue_init(&disabledq);
-  goterase = 0;
-  /* disable all erase jobs (including weak "keep uninstalled" rules) */
-  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
-    {
-      if (r->d < 0)    /* disabled ? */
-       continue;
-      if (r->p >= 0)   /* install job? */
-       continue;
-      queue_push(&disabledq, i);
-      solver_disablerule(solv, r);
-      goterase++;
-    }
-
-  if (goterase)
-    {
-      enabledisablelearntrules(solv);
-      removedisabledconflicts(solv, &redoq);
-    }
-
-  /*
-   * find recommended packages
-   */
-  if (recommendationsq)
-    {
-      Id rec, *recp, p, pp;
-
-      queue_empty(recommendationsq);
-      /* create map of all recommened packages */
-      solv->recommends_index = -1;
-      MAPZERO(&solv->recommendsmap);
-
-      /* put all packages the solver already chose in the map */
-      if (solv->decisioncnt_weak)
-       {
-         for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
-           {
-             Id why;
-             why = solv->decisionq_why.elements[i];
-             if (why)
-               continue;       /* forced by unit rule or dep resolving */
-             p = solv->decisionq.elements[i];
-             if (p < 0)
-               continue;
-             MAPSET(&solv->recommendsmap, p);
-           }
-       }
-
-      for (i = 0; i < solv->decisionq.count; i++)
-       {
-         p = solv->decisionq.elements[i];
-         if (p < 0)
-           continue;
-         s = pool->solvables + p;
-         if (s->recommends)
-           {
-             recp = s->repo->idarraydata + s->recommends;
-             while ((rec = *recp++) != 0)
-               {
-#ifdef ENABLE_COMPLEX_DEPS
-                 if (pool_is_complex_dep(pool, rec))
-                   {
-                     do_complex_recommendations(solv, rec, &solv->recommendsmap, noselected);
-                     continue;
-                   }
-#endif
-                 FOR_PROVIDES(p, pp, rec)
-                   if (solv->decisionmap[p] > 0)
-                     break;
-                 if (p)
-                   {
-                     if (!noselected)
-                       {
-                         FOR_PROVIDES(p, pp, rec)
-                           if (solv->decisionmap[p] > 0)
-                             MAPSET(&solv->recommendsmap, p);
-                       }
-                     continue; /* p != 0: already fulfilled */
-                   }
-                 FOR_PROVIDES(p, pp, rec)
-                   MAPSET(&solv->recommendsmap, p);
-               }
-           }
-       }
-      for (i = 1; i < pool->nsolvables; i++)
-       {
-         if (solv->decisionmap[i] < 0)
-           continue;
-         if (solv->decisionmap[i] > 0 && noselected)
-           continue;
-          if (MAPTST(&obsmap, i))
-           continue;
-         s = pool->solvables + i;
-         if (!MAPTST(&solv->recommendsmap, i))
-           {
-             if (!s->supplements)
-               continue;
-             if (!pool_installable(pool, s))
-               continue;
-             if (!solver_is_supplementing(solv, s))
-               continue;
-           }
-         queue_push(recommendationsq, i);
-       }
-      /* we use MODE_SUGGEST here so that repo prio is ignored */
-      policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
-    }
-
-  /*
-   * find suggested packages
-   */
-
-  if (suggestionsq)
-    {
-      Id sug, *sugp, p, pp;
-
-      queue_empty(suggestionsq);
-      /* create map of all suggests that are still open */
-      solv->recommends_index = -1;
-      MAPZERO(&solv->suggestsmap);
-      for (i = 0; i < solv->decisionq.count; i++)
-       {
-         p = solv->decisionq.elements[i];
-         if (p < 0)
-           continue;
-         s = pool->solvables + p;
-         if (s->suggests)
-           {
-             sugp = s->repo->idarraydata + s->suggests;
-             while ((sug = *sugp++) != 0)
-               {
-#ifdef ENABLE_COMPLEX_DEPS
-                 if (pool_is_complex_dep(pool, sug))
-                   {
-                     do_complex_recommendations(solv, sug, &solv->suggestsmap, noselected);
-                     continue;
-                   }
-#endif
-                 FOR_PROVIDES(p, pp, sug)
-                   if (solv->decisionmap[p] > 0)
-                     break;
-                 if (p)
-                   {
-                     if (!noselected)
-                       {
-                         FOR_PROVIDES(p, pp, sug)
-                           if (solv->decisionmap[p] > 0)
-                             MAPSET(&solv->suggestsmap, p);
-                       }
-                     continue; /* already fulfilled */
-                   }
-                 FOR_PROVIDES(p, pp, sug)
-                   MAPSET(&solv->suggestsmap, p);
-               }
-           }
-       }
-      for (i = 1; i < pool->nsolvables; i++)
-       {
-         if (solv->decisionmap[i] < 0)
-           continue;
-         if (solv->decisionmap[i] > 0 && noselected)
-           continue;
-          if (MAPTST(&obsmap, i))
-           continue;
-         s = pool->solvables + i;
-         if (!MAPTST(&solv->suggestsmap, i))
-           {
-             if (!s->enhances)
-               continue;
-             if (!pool_installable(pool, s))
-               continue;
-             if (!solver_is_enhancing(solv, s))
-               continue;
-           }
-         queue_push(suggestionsq, i);
-       }
-      policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
-    }
-
-  /* undo removedisabledconflicts */
-  if (redoq.count)
-    undo_removedisabledconflicts(solv, &redoq);
-  queue_free(&redoq);
-
-  /* undo job rule disabling */
-  for (i = 0; i < disabledq.count; i++)
-    solver_enablerule(solv, solv->rules + disabledq.elements[i]);
-  queue_free(&disabledq);
-  map_free(&obsmap);
-}
-
-
-/***********************************************************************/
-/* disk usage computations */
-
-/*-------------------------------------------------------------------
- *
- * calculate DU changes
- */
-
-void
-solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
-{
-  Map installedmap;
-
-  solver_create_state_maps(solv, &installedmap, 0);
-  pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
-  map_free(&installedmap);
-}
-
-
-/*-------------------------------------------------------------------
- *
- * calculate changes in install size
- */
-
-int
-solver_calc_installsizechange(Solver *solv)
-{
-  Map installedmap;
-  int change;
-
-  solver_create_state_maps(solv, &installedmap, 0);
-  change = pool_calc_installsizechange(solv->pool, &installedmap);
-  map_free(&installedmap);
-  return change;
-}
-
-void
-solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
-{
-  pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
-}
-
-void
-solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
-{
-  Pool *pool = solv->pool;
-  Map installedmap;
-  int i;
-  pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
-  pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0);
-  for (i = 0; i < res->count; i++)
-    if (res->elements[i] != -1)
-      {
-       Solvable *s = pool->solvables + pkgs->elements[i];
-       if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap))
-         res->elements[i] = -1;
-      }
-  map_free(&installedmap);
-}
-
-/*-------------------------------------------------------------------
- *
- * decision introspection
- */
-
-int
-solver_get_decisionlevel(Solver *solv, Id p)
-{
-  return solv->decisionmap[p];
-}
-
-void
-solver_get_decisionqueue(Solver *solv, Queue *decisionq)
-{
-  queue_free(decisionq);
-  queue_init_clone(decisionq, &solv->decisionq);
-}
-
-int
-solver_get_lastdecisionblocklevel(Solver *solv)
-{
-  Id p;
-  if (solv->decisionq.count == 0)
-    return 0;
-  p = solv->decisionq.elements[solv->decisionq.count - 1];
-  if (p < 0)
-    p = -p;
-  return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
-}
-
-void
-solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
-{
-  Id p;
-  int i;
-
-  queue_empty(decisionq);
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p < 0)
-       p = -p;
-      if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
-        break;
-    }
-  if (i == solv->decisionq.count)
-    return;
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p < 0)
-       p = -p;
-      if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
-        queue_push(decisionq, p);
-      else
-        break;
-    }
-}
-
-int
-solver_describe_decision(Solver *solv, Id p, Id *infop)
-{
-  int i;
-  Id pp, why;
-
-  if (infop)
-    *infop = 0;
-  if (!solv->decisionmap[p])
-    return SOLVER_REASON_UNRELATED;
-  pp = solv->decisionmap[p] < 0 ? -p : p;
-  for (i = 0; i < solv->decisionq.count; i++)
-    if (solv->decisionq.elements[i] == pp)
-      break;
-  if (i == solv->decisionq.count)      /* just in case... */
-    return SOLVER_REASON_UNRELATED;
-  why = solv->decisionq_why.elements[i];
-  if (infop)
-    *infop = why > 0 ? why : -why;
-  if (why > 0)
-    return SOLVER_REASON_UNIT_RULE;
-  why = -why;
-  if (i == 0)
-    return SOLVER_REASON_KEEP_INSTALLED;       /* the systemsolvable */
-  if (i < solv->decisioncnt_update)
-    return SOLVER_REASON_RESOLVE_JOB;
-  if (i < solv->decisioncnt_keep)
-    {
-      if (why == 0 && pp < 0)
-       return SOLVER_REASON_CLEANDEPS_ERASE;
-      return SOLVER_REASON_UPDATE_INSTALLED;
-    }
-  if (i < solv->decisioncnt_resolve)
-    {
-      if (solv->focus_installed && i >= solv->decisioncnt_jobs)
-       return SOLVER_REASON_RESOLVE_JOB;
-      if (why == 0 && pp < 0)
-       return SOLVER_REASON_CLEANDEPS_ERASE;
-      return SOLVER_REASON_KEEP_INSTALLED;
-    }
-  if (why > 0)
-    return SOLVER_REASON_RESOLVE;
-  /* weak or orphaned */
-  if (i < solv->decisioncnt_orphan)
-    return SOLVER_REASON_WEAKDEP;
-  return SOLVER_REASON_RESOLVE_ORPHAN;
-}
-
-
-void
-solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
-{
-  Pool *pool = solv->pool;
-  int i;
-  int level = solv->decisionmap[p];
-  int decisionno;
-  Solvable *s;
-
-  queue_empty(whyq);
-  if (level < 0)
-    return;    /* huh? */
-  for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
-    if (solv->decisionq.elements[decisionno] == p)
-      break;
-  if (decisionno == solv->decisionq.count)
-    return;    /* huh? */
-  if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
-    return;    /* huh? */
-
-  /* 1) list all packages that recommend us */
-  for (i = 1; i < pool->nsolvables; i++)
-    {
-      Id *recp, rec, pp2, p2;
-      if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
-       continue;
-      s = pool->solvables + i;
-      if (!s->recommends)
-       continue;
-      if (!solv->addalreadyrecommended && s->repo == solv->installed)
-       continue;
-      recp = s->repo->idarraydata + s->recommends;
-      while ((rec = *recp++) != 0)
-       {
-         int found = 0;
-         FOR_PROVIDES(p2, pp2, rec)
-           {
-             if (p2 == p)
-               found = 1;
-             else
-               {
-                 /* if p2 is already installed, this recommends is ignored */
-                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
-                   break;
-               }
-           }
-         if (!p2 && found)
-           {
-             queue_push(whyq, SOLVER_REASON_RECOMMENDED);
-             queue_push2(whyq, i, rec);
-           }
-       }
-    }
-  /* 2) list all supplements */
-  s = pool->solvables + p;
-  if (s->supplements && level > 0)
-    {
-      Id *supp, sup, pp2, p2;
-      /* this is a hack. to use solver_dep_fulfilled we temporarily clear
-       * everything above our level in the decisionmap */
-      for (i = decisionno; i < solv->decisionq.count; i++ )
-       {
-         p2 = solv->decisionq.elements[i];
-         if (p2 > 0)
-           solv->decisionmap[p2] = -solv->decisionmap[p2];
-       }
-      supp = s->repo->idarraydata + s->supplements;
-      while ((sup = *supp++) != 0)
-       if (solver_dep_fulfilled(solv, sup))
-         {
-           int found = 0;
-           /* let's see if this is an easy supp */
-           FOR_PROVIDES(p2, pp2, sup)
-             {
-               if (!solv->addalreadyrecommended && solv->installed)
-                 {
-                   if (pool->solvables[p2].repo == solv->installed)
-                     continue;
-                 }
-               if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
-                 {
-                   queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
-                   queue_push2(whyq, p2, sup);
-                   found = 1;
-                 }
-             }
-           if (!found)
-             {
-               /* hard case, just note dependency with no package */
-               queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
-               queue_push2(whyq, 0, sup);
-             }
-         }
-      for (i = decisionno; i < solv->decisionq.count; i++)
-       {
-         p2 = solv->decisionq.elements[i];
-         if (p2 > 0)
-           solv->decisionmap[p2] = -solv->decisionmap[p2];
-       }
-    }
-}
-
-void
-pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
-{
-  Id p, pp;
-  how &= SOLVER_SELECTMASK;
-  queue_empty(pkgs);
-  if (how == SOLVER_SOLVABLE_ALL)
-    {
-      FOR_POOL_SOLVABLES(p)
-        queue_push(pkgs, p);
-    }
-  else if (how == SOLVER_SOLVABLE_REPO)
-    {
-      Repo *repo = pool_id2repo(pool, what);
-      Solvable *s;
-      if (repo)
-       FOR_REPO_SOLVABLES(repo, p, s)
-         queue_push(pkgs, p);
-    }
-  else
-    {
-      FOR_JOB_SELECT(p, pp, how, what)
-       queue_push(pkgs, p);
-    }
-}
-
-int
-pool_isemptyupdatejob(Pool *pool, Id how, Id what)
-{
-  Id p, pp, pi, pip;
-  Id select = how & SOLVER_SELECTMASK;
-  if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
-    return 0;
-  if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
-    return 0;
-  if (!pool->installed)
-    return 1;
-  FOR_JOB_SELECT(p, pp, select, what)
-    if (pool->solvables[p].repo == pool->installed)
-      return 0;
-  /* hard work */
-  FOR_JOB_SELECT(p, pp, select, what)
-    {
-      Solvable *s = pool->solvables + p;
-      FOR_PROVIDES(pi, pip, s->name)
-       {
-         Solvable *si = pool->solvables + pi;
-         if (si->repo != pool->installed || si->name != s->name)
-           continue;
-         return 0;
-       }
-      if (s->obsoletes)
-       {
-         Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-         while ((obs = *obsp++) != 0)
-           {
-             FOR_PROVIDES(pi, pip, obs)
-               {
-                 Solvable *si = pool->solvables + pi;
-                 if (si->repo != pool->installed)
-                   continue;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
-                   continue;
-                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
-                   continue;
-                 return 0;
-               }
-           }
-       }
-    }
-  return 1;
-}
-
-static int
-get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
-{
-  return *(Id *)ap - *(Id *)bp;
-}
-
-static int
-get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
-}
-
-static int
-get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  int r;
-  r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
-  if (r)
-    return r;
-  return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
-}
-
-static void
-get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
-{
-  Id lastp = -1, lasta = -1;
-  int i, j;
-  if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
-    return;
-  if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-    solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
-  else if ((flags & GET_USERINSTALLED_NAMES) != 0)
-    solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
-  else
-    solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
-  if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-    {
-      for (i = j = 0; i < q->count; i += 2)
-       if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
-         {
-           q->elements[j++] = lastp = q->elements[i];
-           q->elements[j++] = lasta = q->elements[i + 1];
-         }
-    }
-  else
-    {
-      for (i = j = 0; i < q->count; i++)
-       if (q->elements[i] != lastp)
-         q->elements[j++] = lastp = q->elements[i];
-    }
-  queue_truncate(q, j);
-}
-
-static void
-namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
-{
-  int i;
-  if (!pool->installed)
-    return;
-  for (i = 0; i < q->count; i += 2)
-    {
-      Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
-      FOR_PROVIDES(p, pp, name)
-       {
-         Solvable *s = pool->solvables + p;
-         if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
-           continue;
-         if (job)
-           queue_push(qout, job);
-         queue_push(qout, p);
-       }
-    }
-}
-
-void
-solver_get_userinstalled(Solver *solv, Queue *q, int flags)
-{
-  Pool *pool = solv->pool;
-  Id p, p2, pp;
-  Solvable *s;
-  Repo *installed = solv->installed;
-  int i, j;
-  Map userinstalled;
-  
-  map_init(&userinstalled, 0);
-  queue_empty(q);
-  /* first process jobs */
-  for (i = 0; i < solv->job.count; i += 2)
-    {
-      Id how = solv->job.elements[i];
-      Id what, select;
-      if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
-       {
-         if (!userinstalled.size)
-           map_grow(&userinstalled, installed->end - installed->start);
-         what = solv->job.elements[i + 1];
-         select = how & SOLVER_SELECTMASK;
-         if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
-           FOR_REPO_SOLVABLES(installed, p, s)
-             MAPSET(&userinstalled, p - installed->start);
-         FOR_JOB_SELECT(p, pp, select, what)
-           if (pool->solvables[p].repo == installed)
-             MAPSET(&userinstalled, p - installed->start);
-         continue;
-       }
-      if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
-       continue;
-      if ((how & SOLVER_NOTBYUSER) != 0)
-       continue;
-      what = solv->job.elements[i + 1];
-      select = how & SOLVER_SELECTMASK;
-      FOR_JOB_SELECT(p, pp, select, what)
-        if (solv->decisionmap[p] > 0)
-         {
-           queue_push(q, p);
-#ifdef ENABLE_LINKED_PKGS
-           if (has_package_link(pool, pool->solvables + p))
-             {
-               int j;
-               Queue lq;
-               queue_init(&lq);
-               find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
-               for (j = 0; j < lq.count; j++)
-                 if (solv->decisionmap[lq.elements[j]] > 0)
-                   queue_push(q, lq.elements[j]);
-             }
-#endif
-         }
-    }
-  /* now process updates of userinstalled packages */
-  if (installed && userinstalled.size)
-    {
-      for (i = 1; i < solv->decisionq.count; i++)
-       {
-         p = solv->decisionq.elements[i];
-         if (p <= 0)
-           continue;
-         s = pool->solvables + p;
-         if (!s->repo)
-           continue;
-         if (s->repo == installed)
-           {
-             if (MAPTST(&userinstalled, p - installed->start))
-               queue_push(q, p);
-             continue;
-           }
-         /* new package, check if we replace a userinstalled one */
-         FOR_PROVIDES(p2, pp, s->name)
-           {
-             Solvable *ps = pool->solvables + p2;
-             if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
-               continue;
-             if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
-               continue;
-             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
-               continue;
-             queue_push(q, p);
-             break;
-           }
-         if (!p2 && s->repo != installed && s->obsoletes)
-           {
-             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-             while ((obs = *obsp++) != 0)
-               {
-                 FOR_PROVIDES(p2, pp, obs)
-                   {
-                     Solvable *ps = pool->solvables + p2;
-                     if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
-                       continue;
-                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-                       continue;
-                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) 
-                       continue;
-                     queue_push(q, p); 
-                     break;
-                   }
-                 if (p2)
-                   break;
-               }
-           }
-       }
-    }
-  map_free(&userinstalled);
-
-  /* convert to desired output format */
-  if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-    {
-      int qcount = q->count;
-      queue_insertn(q, 0, qcount, 0);
-      for (i = j = 0; i < qcount; i++)
-       {
-         s = pool->solvables + q->elements[i + qcount];
-         q->elements[j++] = s->name;
-         q->elements[j++] = s->arch;
-       }
-    }
-  else if ((flags & GET_USERINSTALLED_NAMES) != 0)
-    {
-      for (i = 0; i < q->count; i++)
-       {
-         s = pool->solvables + q->elements[i];
-         q->elements[i] = s->name;
-       }
-    }
-  /* sort and unify */
-  get_userinstalled_sort_uniq(pool, q, flags);
-
-  /* invert if asked for */
-  if ((flags & GET_USERINSTALLED_INVERTED) != 0)
-    {
-      /* first generate queue with all installed packages */
-      Queue invq;
-      queue_init(&invq);
-      for (i = 1; i < solv->decisionq.count; i++)
-       {
-         p = solv->decisionq.elements[i];
-         if (p <= 0)
-           continue;
-         s = pool->solvables + p;
-         if (!s->repo)
-           continue;
-         if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-           queue_push2(&invq, s->name, s->arch);
-         else if ((flags & GET_USERINSTALLED_NAMES) != 0)
-           queue_push(&invq, s->name);
-         else
-           queue_push(&invq, p);
-       }
-      /* push q on invq, just in case... */
-      queue_insertn(&invq, invq.count, q->count, q->elements);
-      get_userinstalled_sort_uniq(pool, &invq, flags);
-      /* subtract queues (easy as they are sorted and invq is a superset of q) */
-      if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-       {
-         if (q->count)
-           {
-             for (i = j = 0; i < invq.count; i += 2)
-               if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
-                 {
-                   invq.elements[i] = invq.elements[i + 1] = 0;
-                   j += 2;
-                   if (j >= q->count)
-                     break;
-                 }
-             queue_empty(q);
-           }
-         for (i = 0; i < invq.count; i += 2)
-           if (invq.elements[i])
-             queue_push2(q, invq.elements[i], invq.elements[i + 1]);
-       }
-      else
-       {
-         if (q->count)
-           {
-             for (i = j = 0; i < invq.count; i++)
-               if (invq.elements[i] == q->elements[j])
-                 {
-                   invq.elements[i] = 0;
-                   if (++j >= q->count)
-                     break;
-                 }
-             queue_empty(q);
-           }
-         for (i = 0; i < invq.count; i++)
-           if (invq.elements[i])
-             queue_push(q, invq.elements[i]);
-       }
-      queue_free(&invq);
-    }
-}
-
-void
-pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
-{
-  int i;
-
-  if ((flags & GET_USERINSTALLED_INVERTED) != 0)
-    {
-      Queue invq;
-      Id p, lastid;
-      Solvable *s;
-      int bad;
-      if (!pool->installed)
-       return;
-      queue_init(&invq);
-      if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-       flags &= ~GET_USERINSTALLED_NAMES;      /* just in case */
-      FOR_REPO_SOLVABLES(pool->installed, p, s)
-       queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
-      if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
-       {
-         /* for namearch we convert to packages */
-         namearch2solvables(pool, q, &invq, 0);
-         get_userinstalled_sort_uniq(pool, &invq, flags);
-         namearch2solvables(pool, q, &invq, 0);
-         flags = 0;
-       }
-      else
-       {
-         queue_insertn(&invq, invq.count, q->count, q->elements);
-         get_userinstalled_sort_uniq(pool, &invq, flags);
-         /* now the fun part, add q again, sort, and remove all dups */
-         queue_insertn(&invq, invq.count, q->count, q->elements);
-       }
-      if (invq.count > 1)
-       {
-         if ((flags & GET_USERINSTALLED_NAMES) != 0)
-           solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
-         else
-           solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
-       }
-      lastid = -1;
-      bad = 1;
-      for (i = 0; i < invq.count; i++)
-       {
-         if (invq.elements[i] == lastid)
-           {
-             bad = 1;
-             continue;
-           }
-         if (!bad)
-           queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
-         bad = 0;
-         lastid = invq.elements[i];
-       }
-      if (!bad)
-       queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
-      queue_free(&invq);
-    }
-  else
-    {
-      if (flags & GET_USERINSTALLED_NAMEARCH)
-       namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
-      else
-       {
-         for (i = 0; i < q->count; i++)
-           queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
-       }
-    }
-}
-
-int
-solver_alternatives_count(Solver *solv)
-{
-  Id *elements = solv->branches.elements;
-  int res, count;
-  for (res = 0, count = solv->branches.count; count; res++)
-    count -= elements[count - 2];
-  return res;
-}
-
-int
-solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
-{
-  int cnt = solver_alternatives_count(solv);
-  int count = solv->branches.count;
-  Id *elements = solv->branches.elements;
-  if (choices)
-    queue_empty(choices);
-  if (alternative <= 0 || alternative > cnt)
-    return 0;
-  elements += count;
-  for (; cnt > alternative; cnt--)
-    elements -= elements[-2];
-  if (levelp)
-    *levelp = elements[-1];
-  if (fromp)
-    *fromp = elements[-4];
-  if (idp)
-    *idp = elements[-3];
-  if (chosenp)
-    {
-      int i;
-      *chosenp = 0;
-      for (i = elements[-2]; i > 4; i--)
-       {
-         Id p = -elements[-i];
-         if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
-           {
-             *chosenp = p;
-             break;
-           }
-       }
-    }
-  if (choices)
-    queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
-  return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
-}
-
-const char *
-solver_select2str(Pool *pool, Id select, Id what)
-{
-  const char *s;
-  char *b;
-  select &= SOLVER_SELECTMASK;
-  if (select == SOLVER_SOLVABLE)
-    return pool_solvid2str(pool, what);
-  if (select == SOLVER_SOLVABLE_NAME)
-    return pool_dep2str(pool, what);
-  if (select == SOLVER_SOLVABLE_PROVIDES)
-    {
-      s = pool_dep2str(pool, what);
-      b = pool_alloctmpspace(pool, 11 + strlen(s));
-      sprintf(b, "providing %s", s);
-      return b;
-    }
-  if (select == SOLVER_SOLVABLE_ONE_OF)
-    {
-      Id p;
-      b = 0;
-      while ((p = pool->whatprovidesdata[what++]) != 0)
-       {
-         s = pool_solvid2str(pool, p);
-         if (b)
-           b = pool_tmpappend(pool, b, ", ", s);
-         else
-           b = pool_tmpjoin(pool, s, 0, 0);
-         pool_freetmpspace(pool, s);
-       }
-      return b ? b : "nothing";
-    }
-  if (select == SOLVER_SOLVABLE_REPO)
-    {
-      b = pool_alloctmpspace(pool, 20);
-      sprintf(b, "repo #%d", what);
-      return b;
-    }
-  if (select == SOLVER_SOLVABLE_ALL)
-    return "all packages";
-  return "unknown job select";
-}
-
-const char *
-pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
-{
-  Id select = how & SOLVER_SELECTMASK;
-  const char *strstart = 0, *strend = 0;
-  char *s;
-  int o;
-
-  switch (how & SOLVER_JOBMASK)
-    {
-    case SOLVER_NOOP:
-      return "do nothing";
-    case SOLVER_INSTALL:
-      if (select == SOLVER_SOLVABLE && pool->installed && pool->solvables[what].repo == pool->installed)
-       strstart = "keep ", strend = " installed";
-      else if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_NAME)
-       strstart = "install ";
-      else if (select == SOLVER_SOLVABLE_PROVIDES)
-       strstart = "install a package ";
-      else
-       strstart = "install one of ";
-      break;
-    case SOLVER_ERASE:
-      if (select == SOLVER_SOLVABLE && !(pool->installed && pool->solvables[what].repo == pool->installed))
-       strstart = "keep ", strend = " uninstalled";
-      else if (select == SOLVER_SOLVABLE_PROVIDES)
-       strstart = "deinstall all packages ";
-      else
-       strstart = "deinstall ";
-      break;
-    case SOLVER_UPDATE:
-      strstart = "update ";
-      break;
-    case SOLVER_WEAKENDEPS:
-      strstart = "weaken deps of ";
-      break;
-    case SOLVER_MULTIVERSION:
-      strstart = "multi version ";
-      break;
-    case SOLVER_LOCK:
-      strstart = "lock ";
-      break;
-    case SOLVER_DISTUPGRADE:
-      strstart = "dist upgrade ";
-      break;
-    case SOLVER_VERIFY:
-      strstart = "verify ";
-      break;
-    case SOLVER_DROP_ORPHANED:
-      strstart = "deinstall ", strend = " if orphaned";
-      break;
-    case SOLVER_USERINSTALLED:
-      strstart = "regard ", strend = " as userinstalled";
-      break;
-    case SOLVER_ALLOWUNINSTALL:
-      strstart = "allow deinstallation of ";
-      break;
-    default:
-      strstart = "unknown job ";
-      break;
-    }
-  s = pool_tmpjoin(pool, strstart, solver_select2str(pool, select, what), strend);
-  how &= flagmask;
-  if ((how & ~(SOLVER_SELECTMASK|SOLVER_JOBMASK)) == 0)
-    return s;
-  o = strlen(s);
-  s = pool_tmpappend(pool, s, " ", 0);
-  if (how & SOLVER_WEAK)
-    s = pool_tmpappend(pool, s, ",weak", 0);
-  if (how & SOLVER_ESSENTIAL)
-    s = pool_tmpappend(pool, s, ",essential", 0);
-  if (how & SOLVER_CLEANDEPS)
-    s = pool_tmpappend(pool, s, ",cleandeps", 0);
-  if (how & SOLVER_ORUPDATE)
-    s = pool_tmpappend(pool, s, ",orupdate", 0);
-  if (how & SOLVER_FORCEBEST)
-    s = pool_tmpappend(pool, s, ",forcebest", 0);
-  if (how & SOLVER_TARGETED)
-    s = pool_tmpappend(pool, s, ",targeted", 0);
-  if (how & SOLVER_SETEV)
-    s = pool_tmpappend(pool, s, ",setev", 0);
-  if (how & SOLVER_SETEVR)
-    s = pool_tmpappend(pool, s, ",setevr", 0);
-  if (how & SOLVER_SETARCH)
-    s = pool_tmpappend(pool, s, ",setarch", 0);
-  if (how & SOLVER_SETVENDOR)
-    s = pool_tmpappend(pool, s, ",setvendor", 0);
-  if (how & SOLVER_SETREPO)
-    s = pool_tmpappend(pool, s, ",setrepo", 0);
-  if (how & SOLVER_SETNAME)
-    s = pool_tmpappend(pool, s, ",setname", 0);
-  if (how & SOLVER_NOAUTOSET)
-    s = pool_tmpappend(pool, s, ",noautoset", 0);
-  if (s[o + 1] != ',')
-    s = pool_tmpappend(pool, s, ",?", 0);
-  s[o + 1] = '[';
-  return pool_tmpappend(pool, s, "]", 0);
-}
-
-const char *
-solver_alternative2str(Solver *solv, int type, Id id, Id from)
-{
-  Pool *pool = solv->pool;
-  if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
-    {
-      const char *s = pool_dep2str(pool, id);
-      return pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
-    }
-  if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
-    {
-      int rtype;
-      Id depfrom, depto, dep;
-      char buf[64];
-      if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
-       id = solver_rule2pkgrule(solv, id);
-      rtype = solver_ruleinfo(solv, id, &depfrom, &depto, &dep);
-      if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
-       {
-         if ((depto & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
-           return pool_dep2str(pool, dep);
-         return solver_select2str(pool, depto & SOLVER_SELECTMASK, dep);
-       }
-      if (rtype == SOLVER_RULE_PKG_REQUIRES)
-       {
-         const char *s = pool_dep2str(pool, dep);
-         return pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, depfrom));
-       }
-      sprintf(buf, "Rule #%d", id);
-      return pool_tmpjoin(pool, buf, 0, 0);
-    }
-  return "unknown alternative type";
-}
-
diff --git a/libsolv-0.6.15/src/solver.h b/libsolv-0.6.15/src/solver.h
deleted file mode 100644 (file)
index 2ae9c8d..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solver.h
- *
- */
-
-#ifndef LIBSOLV_SOLVER_H
-#define LIBSOLV_SOLVER_H
-
-#include "pooltypes.h"
-#include "pool.h"
-#include "repo.h"
-#include "queue.h"
-#include "bitmap.h"
-#include "transaction.h"
-#include "rules.h"
-#include "problems.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _Solver {
-  Pool *pool;                          /* back pointer to pool */
-  Queue job;                           /* copy of the job we're solving */
-
-  int (*solution_callback)(struct _Solver *solv, void *data);
-  void *solution_callback_data;
-
-  int pooljobcnt;                      /* number of pooljob entries in job queue */
-
-#ifdef LIBSOLV_INTERNAL
-  Repo *installed;                     /* copy of pool->installed */
-
-  /* list of rules, ordered
-   * pkg rules first, then features, updates, jobs, learnt
-   * see start/end offsets below
-   */
-  Rule *rules;                         /* all rules */
-  Id nrules;                           /* [Offset] index of the last rule */
-
-  Queue ruleassertions;                        /* Queue of all assertion rules */
-
-  /* start/end offset for rule 'areas' */
-
-  Id pkgrules_end;                      /* [Offset] dep rules end */
-
-  Id featurerules;                     /* feature rules start/end */
-  Id featurerules_end;
-
-  Id updaterules;                      /* policy rules, e.g. keep packages installed or update. All literals > 0 */
-  Id updaterules_end;
-
-  Id jobrules;                         /* user rules */
-  Id jobrules_end;
-
-  Id infarchrules;                     /* inferior arch rules */
-  Id infarchrules_end;
-
-  Id duprules;                         /* dist upgrade rules */
-  Id duprules_end;
-
-  Id bestrules;                                /* rules from SOLVER_FORCEBEST */
-  Id bestrules_end;
-  Id *bestrules_pkg;
-
-  Id yumobsrules;                      /* rules from yum obsoletes handling */
-  Id yumobsrules_end;
-  Id *yumobsrules_info;                        /* the dependency for each rule */
-
-  Id choicerules;                      /* choice rules (always weak) */
-  Id choicerules_end;
-  Id *choicerules_ref;
-
-  Id learntrules;                      /* learnt rules, (end == nrules) */
-
-  Map noupdate;                                /* don't try to update these
-                                           installed solvables */
-  Map multiversion;                    /* ignore obsoletes for these (multiinstall) */
-
-  Map updatemap;                       /* bring these installed packages to the newest version */
-  int updatemap_all;                   /* bring all packages to the newest version */
-
-  Map bestupdatemap;                   /* create best rule for those packages */
-  int bestupdatemap_all;               /* bring all packages to the newest version */
-
-  Map fixmap;                          /* fix these packages */
-  int fixmap_all;                      /* fix all packages */
-
-  Queue weakruleq;                     /* index into 'rules' for weak ones */
-  Map weakrulemap;                     /* map rule# to '1' for weak rules, 1..learntrules */
-
-  Id *watches;                         /* Array of rule offsets
-                                        * watches has nsolvables*2 entries and is addressed from the middle
-                                        * middle-solvable : decision to conflict, offset point to linked-list of rules
-                                        * middle+solvable : decision to install: offset point to linked-list of rules
-                                        */
-
-  Queue ruletojob;                      /* index into job queue: jobs for which a rule exits */
-
-  /* our decisions: */
-  Queue decisionq;                      /* >0:install, <0:remove/conflict */
-  Queue decisionq_why;                 /* index of rule, Offset into rules */
-
-  Id *decisionmap;                     /* map for all available solvables,
-                                        * = 0: undecided
-                                        * > 0: level of decision when installed,
-                                        * < 0: level of decision when conflict */
-
-  int decisioncnt_jobs;
-  int decisioncnt_update;
-  int decisioncnt_keep;
-  int decisioncnt_resolve;
-  int decisioncnt_weak;
-  int decisioncnt_orphan;
-
-  /* learnt rule history */
-  Queue learnt_why;
-  Queue learnt_pool;
-
-  Queue branches;
-  int propagate_index;                  /* index into decisionq for non-propagated decisions */
-
-  Queue problems;                       /* list of lists of conflicting rules, < 0 for job rules */
-  Queue solutions;                     /* refined problem storage space */
-
-  Queue orphaned;                      /* orphaned packages (to be removed?) */
-
-  int stats_learned;                   /* statistic */
-  int stats_unsolvable;                        /* statistic */
-
-  Map recommendsmap;                   /* recommended packages from decisionmap */
-  Map suggestsmap;                     /* suggested packages from decisionmap */
-  int recommends_index;                        /* recommendsmap/suggestsmap is created up to this level */
-  Queue *recommendscplxq;
-  Queue *suggestscplxq;
-
-  Id *obsoletes;                       /* obsoletes for each installed solvable */
-  Id *obsoletes_data;                  /* data area for obsoletes */
-  Id *specialupdaters;                 /* updaters for packages with a limited update rule */
-
-  /*-------------------------------------------------------------------------------------------------------------
-   * Solver configuration
-   *-------------------------------------------------------------------------------------------------------------*/
-
-  int allowdowngrade;                  /* allow to downgrade installed solvable */
-  int allownamechange;                 /* allow to change name of installed solvables */
-  int allowarchchange;                 /* allow to change architecture of installed solvables */
-  int allowvendorchange;               /* allow to change vendor of installed solvables */
-  int allowuninstall;                  /* allow removal of installed solvables */
-  int noupdateprovide;                 /* true: update packages needs not to provide old package */
-  int needupdateprovide;               /* true: update packages must provide old package */
-  int dosplitprovides;                 /* true: consider legacy split provides */
-  int dontinstallrecommended;          /* true: do not install recommended packages */
-  int addalreadyrecommended;           /* true: also install recommended packages that were already recommended by the installed packages */
-  int dontshowinstalledrecommended;    /* true: do not show recommended packages that are already installed */
-
-  int noinfarchcheck;                  /* true: do not forbid inferior architectures */
-  int keepexplicitobsoletes;           /* true: honor obsoletes during multiinstall */
-  int bestobeypolicy;                  /* true: stay in policy with the best rules */
-  int noautotarget;                    /* true: do not assume targeted for up/dup jobs that contain no installed solvable */
-  int focus_installed;                 /* true: resolve update rules first */
-  int do_yum_obsoletes;                        /* true: add special yumobs rules */
-
-  Map dupmap;                          /* dup these packages*/
-  int dupmap_all;                      /* dup all packages */
-  Map dupinvolvedmap;                  /* packages involved in dup process */
-  int dup_allowdowngrade;              /* dup mode: allow to downgrade installed solvable */
-  int dup_allownamechange;             /* dup mode: allow to change name of installed solvable */
-  int dup_allowarchchange;             /* dup mode: allow to change architecture of installed solvables */
-  int dup_allowvendorchange;           /* dup mode: allow to change vendor of installed solvables */
-
-  Map droporphanedmap;                 /* packages to drop in dup mode */
-  int droporphanedmap_all;
-
-  Map cleandepsmap;                    /* try to drop these packages as of cleandeps erases */
-
-  Queue *ruleinfoq;                    /* tmp space for solver_ruleinfo() */
-
-  Queue *cleandeps_updatepkgs;         /* packages we update in cleandeps mode */
-  Queue *cleandeps_mistakes;           /* mistakes we made */
-
-  Queue *update_targets;               /* update to specific packages */
-
-  Queue *installsuppdepq;              /* deps from the install namespace provides hack */
-
-  Queue addedmap_deduceq;              /* deduce addedmap from pkg rules */
-  Id *instbuddy;                       /* buddies of installed packages */
-  int keep_orphans;                    /* how to treat orphans */
-  int break_orphans;                   /* how to treat orphans */
-  Queue *brokenorphanrules;            /* broken rules of orphaned packages */
-
-  Map allowuninstallmap;               /* ok to uninstall those */
-  int allowuninstall_all;
-
-#endif /* LIBSOLV_INTERNAL */
-};
-
-typedef struct _Solver Solver;
-
-/*
- * queue commands
- */
-
-#define SOLVER_SOLVABLE                        0x01
-#define SOLVER_SOLVABLE_NAME           0x02
-#define SOLVER_SOLVABLE_PROVIDES       0x03
-#define SOLVER_SOLVABLE_ONE_OF         0x04
-#define SOLVER_SOLVABLE_REPO           0x05
-#define SOLVER_SOLVABLE_ALL            0x06
-
-#define SOLVER_SELECTMASK              0xff
-
-#define SOLVER_NOOP                    0x0000
-#define SOLVER_INSTALL                 0x0100
-#define SOLVER_ERASE                   0x0200
-#define SOLVER_UPDATE                  0x0300
-#define SOLVER_WEAKENDEPS                      0x0400
-#define SOLVER_MULTIVERSION            0x0500
-#define SOLVER_LOCK                    0x0600
-#define SOLVER_DISTUPGRADE             0x0700
-#define SOLVER_VERIFY                  0x0800
-#define SOLVER_DROP_ORPHANED           0x0900
-#define SOLVER_USERINSTALLED           0x0a00
-#define SOLVER_ALLOWUNINSTALL          0x0b00
-
-#define SOLVER_JOBMASK                 0xff00
-
-#define SOLVER_WEAK                    0x010000
-#define SOLVER_ESSENTIAL               0x020000
-#define SOLVER_CLEANDEPS                0x040000
-/* ORUPDATE makes SOLVER_INSTALL not prune to installed
- * packages, thus updating installed packages */
-#define SOLVER_ORUPDATE                        0x080000
-/* FORCEBEST makes the solver insist on best packages, so
- * you will get problem reported if the best package is
- * not installable. This can be used with INSTALL, UPDATE
- * and DISTUPGRADE */
-#define SOLVER_FORCEBEST               0x100000
-/* TARGETED is used in up/dup jobs to make the solver
- * treat the specified selection as target packages.
- * It is automatically assumed if the selection does not
- * contain an "installed" package unless the
- * NO_AUTOTARGET solver flag is set */
-#define SOLVER_TARGETED                        0x200000
-/* This (SOLVER_INSTALL) job was automatically added
- * and thus does not the add to the userinstalled packages */
-#define SOLVER_NOTBYUSER               0x400000
-
-#define SOLVER_SETEV                   0x01000000
-#define SOLVER_SETEVR                  0x02000000
-#define SOLVER_SETARCH                 0x04000000
-#define SOLVER_SETVENDOR               0x08000000
-#define SOLVER_SETREPO                 0x10000000
-#define SOLVER_NOAUTOSET               0x20000000
-#define SOLVER_SETNAME                 0x40000000
-
-#define SOLVER_SETMASK                 0x7f000000
-
-/* legacy */
-#define SOLVER_NOOBSOLETES             SOLVER_MULTIVERSION
-
-#define SOLVER_REASON_UNRELATED                0
-#define SOLVER_REASON_UNIT_RULE                1
-#define SOLVER_REASON_KEEP_INSTALLED   2
-#define SOLVER_REASON_RESOLVE_JOB      3
-#define SOLVER_REASON_UPDATE_INSTALLED 4
-#define SOLVER_REASON_CLEANDEPS_ERASE  5
-#define SOLVER_REASON_RESOLVE          6
-#define SOLVER_REASON_WEAKDEP          7
-#define SOLVER_REASON_RESOLVE_ORPHAN   8
-
-#define SOLVER_REASON_RECOMMENDED      16
-#define SOLVER_REASON_SUPPLEMENTED     17
-
-
-#define SOLVER_FLAG_ALLOW_DOWNGRADE            1
-#define SOLVER_FLAG_ALLOW_ARCHCHANGE           2
-#define SOLVER_FLAG_ALLOW_VENDORCHANGE         3
-#define SOLVER_FLAG_ALLOW_UNINSTALL            4
-#define SOLVER_FLAG_NO_UPDATEPROVIDE           5
-#define SOLVER_FLAG_SPLITPROVIDES              6
-#define SOLVER_FLAG_IGNORE_RECOMMENDED         7
-#define SOLVER_FLAG_ADD_ALREADY_RECOMMENDED    8
-#define SOLVER_FLAG_NO_INFARCHCHECK            9
-#define SOLVER_FLAG_ALLOW_NAMECHANGE           10
-#define SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES    11
-#define SOLVER_FLAG_BEST_OBEY_POLICY           12
-#define SOLVER_FLAG_NO_AUTOTARGET              13
-#define SOLVER_FLAG_DUP_ALLOW_DOWNGRADE                14
-#define SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE       15
-#define SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE     16
-#define SOLVER_FLAG_DUP_ALLOW_NAMECHANGE       17
-#define SOLVER_FLAG_KEEP_ORPHANS               18
-#define SOLVER_FLAG_BREAK_ORPHANS              19
-#define SOLVER_FLAG_FOCUS_INSTALLED            20
-#define SOLVER_FLAG_YUM_OBSOLETES              21
-#define SOLVER_FLAG_NEED_UPDATEPROVIDE         22
-
-#define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead of ids */
-#define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
-#define GET_USERINSTALLED_NAMEARCH             (1 << 2)        /* package/arch tuples instead of ids */
-
-#define SOLVER_ALTERNATIVE_TYPE_RULE           1
-#define SOLVER_ALTERNATIVE_TYPE_RECOMMENDS     2
-#define SOLVER_ALTERNATIVE_TYPE_SUGGESTS       3
-
-extern Solver *solver_create(Pool *pool);
-extern void solver_free(Solver *solv);
-extern int  solver_solve(Solver *solv, Queue *job);
-extern Transaction *solver_create_transaction(Solver *solv);
-extern int solver_set_flag(Solver *solv, int flag, int value);
-extern int solver_get_flag(Solver *solv, int flag);
-
-extern int  solver_get_decisionlevel(Solver *solv, Id p);
-extern void solver_get_decisionqueue(Solver *solv, Queue *decisionq);
-extern int  solver_get_lastdecisionblocklevel(Solver *solv);
-extern void solver_get_decisionblock(Solver *solv, int level, Queue *decisionq);
-
-extern void solver_get_orphaned(Solver *solv, Queue *orphanedq);
-extern void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected);
-extern void solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered);
-extern void solver_get_userinstalled(Solver *solv, Queue *q, int flags);
-extern void pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags);
-
-extern int  solver_describe_decision(Solver *solv, Id p, Id *infop);
-extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq);
-
-extern int solver_alternatives_count(Solver *solv);
-extern int solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp);
-
-extern void solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap);
-extern void solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap);   /* obsolete */
-extern void solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap);
-
-extern void solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps);
-extern int solver_calc_installsizechange(Solver *solv);
-extern void solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res);
-
-extern void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
-extern int  pool_isemptyupdatejob(Pool *pool, Id how, Id what);
-
-extern const char *solver_select2str(Pool *pool, Id select, Id what);
-extern const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
-extern const char *solver_alternative2str(Solver *solv, int type, Id id, Id from);
-
-
-/* iterate over all literals of a rule */
-#define FOR_RULELITERALS(l, pp, r)                             \
-    for (pp = r->d < 0 ? -r->d - 1 : r->d,                     \
-         l = r->p; l; l = (pp <= 0 ? (pp-- ? 0 : r->w2) :      \
-         pool->whatprovidesdata[pp++]))
-
-
-
-
-/* XXX: this currently doesn't work correctly for SOLVER_SOLVABLE_REPO and
-   SOLVER_SOLVABLE_ALL */
-
-/* iterate over all packages selected by a job */
-#define FOR_JOB_SELECT(p, pp, select, what)                                    \
-    if (select == SOLVER_SOLVABLE_REPO || select == SOLVER_SOLVABLE_ALL)       \
-       p = pp = 0;                                                             \
-    else for (pp = (select == SOLVER_SOLVABLE ? 0 :                            \
-               select == SOLVER_SOLVABLE_ONE_OF ? what :                       \
-               pool_whatprovides(pool, what)),                                 \
-         p = (select == SOLVER_SOLVABLE ? what : pool->whatprovidesdata[pp++]); \
-                                        p ; p = pool->whatprovidesdata[pp++])  \
-      if (select == SOLVER_SOLVABLE_NAME &&                                    \
-                       pool_match_nevr(pool, pool->solvables + p, what) == 0)  \
-       continue;                                                               \
-      else
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_SOLVER_H */
diff --git a/libsolv-0.6.15/src/solver_private.h b/libsolv-0.6.15/src/solver_private.h
deleted file mode 100644 (file)
index fe80881..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2011, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solver_private.h - private functions
- *
- */
-
-#ifndef LIBSOLV_SOLVER_PRIVATE_H
-#define LIBSOLV_SOLVER_PRIVATE_H
-
-extern void solver_run_sat(Solver *solv, int disablerules, int doweak);
-extern void solver_reset(Solver *solv);
-
-extern int solver_splitprovides(Solver *solv, Id dep, Map *m);
-
-static inline int
-solver_dep_fulfilled(Solver *solv, Id dep)
-{
-  Pool *pool = solv->pool;
-  Id p, pp;
-
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
-       {
-         if (ISRELDEP(rd->evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
-               {
-                 if (solver_dep_fulfilled(solv, rd2->name))
-                   return solver_dep_fulfilled(solv, rd->name);
-                 return solver_dep_fulfilled(solv, rd2->evr);
-               }
-           }
-          if (solver_dep_fulfilled(solv, rd->name))
-           return 1;
-         return !solver_dep_fulfilled(solv, rd->evr);
-       }
-      if (rd->flags == REL_AND)
-        {
-          if (!solver_dep_fulfilled(solv, rd->name))
-            return 0;
-          return solver_dep_fulfilled(solv, rd->evr);
-        }
-      if (rd->flags == REL_OR)
-       {
-          if (solver_dep_fulfilled(solv, rd->name))
-           return 1;
-          return solver_dep_fulfilled(solv, rd->evr);
-       }
-      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
-        return solver_splitprovides(solv, rd->evr, 0);
-    }
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (solv->decisionmap[p] > 0)
-        return 1;
-    }
-  return 0;
-}
-
-static inline int
-solver_is_supplementing(Solver *solv, Solvable *s)
-{
-  Id sup, *supp;
-  if (!s->supplements)
-    return 0;
-  supp = s->repo->idarraydata + s->supplements;
-  while ((sup = *supp++) != 0)
-    if (solver_dep_fulfilled(solv, sup))
-      return 1;
-  return 0;
-}
-
-static inline int
-solver_is_enhancing(Solver *solv, Solvable *s)
-{
-  Id enh, *enhp;
-  if (!s->enhances)
-    return 0;
-  enhp = s->repo->idarraydata + s->enhances;
-  while ((enh = *enhp++) != 0)
-    if (solver_dep_fulfilled(solv, enh))
-      return 1;
-  return 0;
-}
-
-#endif /* LIBSOLV_SOLVER_PRIVATE_H */
diff --git a/libsolv-0.6.15/src/solverdebug.c b/libsolv-0.6.15/src/solverdebug.c
deleted file mode 100644 (file)
index 39f5d78..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solverdebug.c
- *
- * debug functions for the SAT solver
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "solver.h"
-#include "solver_private.h"
-#include "solverdebug.h"
-#include "bitmap.h"
-#include "pool.h"
-#include "poolarch.h"
-#include "util.h"
-#include "evr.h"
-#include "policy.h"
-
-
-void
-solver_printruleelement(Solver *solv, int type, Rule *r, Id v)
-{
-  Pool *pool = solv->pool;
-  Solvable *s;
-  if (v < 0)
-    {
-      s = pool->solvables + -v;
-      POOL_DEBUG(type, "    !%s [%d]", pool_solvable2str(pool, s), -v);
-    }
-  else
-    {
-      s = pool->solvables + v;
-      POOL_DEBUG(type, "    %s [%d]", pool_solvable2str(pool, s), v);
-    }
-  if (pool->installed && s->repo == pool->installed)
-    POOL_DEBUG(type, "I");
-  if (r)
-    {
-      if (r->w1 == v)
-       POOL_DEBUG(type, " (w1)");
-      if (r->w2 == v)
-       POOL_DEBUG(type, " (w2)");
-    }
-  if (solv->decisionmap[s - pool->solvables] > 0)
-    POOL_DEBUG(type, " Install.level%d", solv->decisionmap[s - pool->solvables]);
-  if (solv->decisionmap[s - pool->solvables] < 0)
-    POOL_DEBUG(type, " Conflict.level%d", -solv->decisionmap[s - pool->solvables]);
-  POOL_DEBUG(type, "\n");
-}
-
-
-/*
- * print rule
- */
-
-void
-solver_printrule(Solver *solv, int type, Rule *r)
-{
-  Pool *pool = solv->pool;
-  int i;
-  Id d, v;
-
-  if (r >= solv->rules && r < solv->rules + solv->nrules)   /* r is a solver rule */
-    POOL_DEBUG(type, "Rule #%d:", (int)(r - solv->rules));
-  else
-    POOL_DEBUG(type, "Rule:");                /* r is any rule */
-  if (r->d < 0)
-    POOL_DEBUG(type, " (disabled)");
-  POOL_DEBUG(type, "\n");
-  d = r->d < 0 ? -r->d - 1 : r->d;
-  for (i = 0; ; i++)
-    {
-      if (i == 0)
-         /* print direct literal */
-       v = r->p;
-      else if (!d)
-       {
-         if (i == 2)
-           break;
-         /* binary rule --> print w2 as second literal */
-         v = r->w2;
-       }
-      else
-         /* every other which is in d */
-       v = solv->pool->whatprovidesdata[d + i - 1];
-      if (v == ID_NULL)
-       break;
-      solver_printruleelement(solv, type, r, v);
-    }
-  POOL_DEBUG(type, "    next rules: %d %d\n", r->n1, r->n2);
-}
-
-void
-solver_printruleclass(Solver *solv, int type, Rule *r)
-{
-  Pool *pool = solv->pool;
-  Id p = r - solv->rules;
-  assert(p >= 0);
-  if (p < solv->learntrules)
-    if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, p))
-      POOL_DEBUG(type, "WEAK ");
-  if (solv->learntrules && p >= solv->learntrules)
-    POOL_DEBUG(type, "LEARNT ");
-  else if (p >= solv->bestrules && p < solv->bestrules_end)
-    POOL_DEBUG(type, "BEST ");
-  else if (p >= solv->choicerules && p < solv->choicerules_end)
-    POOL_DEBUG(type, "CHOICE ");
-  else if (p >= solv->infarchrules && p < solv->infarchrules_end)
-    POOL_DEBUG(type, "INFARCH ");
-  else if (p >= solv->duprules && p < solv->duprules_end)
-    POOL_DEBUG(type, "DUP ");
-  else if (p >= solv->jobrules && p < solv->jobrules_end)
-    POOL_DEBUG(type, "JOB ");
-  else if (p >= solv->updaterules && p < solv->updaterules_end)
-    POOL_DEBUG(type, "UPDATE ");
-  else if (p >= solv->featurerules && p < solv->featurerules_end)
-    POOL_DEBUG(type, "FEATURE ");
-  else if (p >= solv->yumobsrules && p < solv->yumobsrules_end)
-    POOL_DEBUG(type, "YUMOBS ");
-  solver_printrule(solv, type, r);
-}
-
-void
-solver_printproblem(Solver *solv, Id v)
-{
-  Pool *pool = solv->pool;
-  int i;
-  Rule *r;
-  Id *jp;
-
-  if (v > 0)
-    solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, solv->rules + v);
-  else
-    {
-      v = -(v + 1);
-      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "JOB %d\n", v);
-      jp = solv->ruletojob.elements;
-      for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
-       if (*jp == v)
-         {
-           POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "- ");
-           solver_printrule(solv, SOLV_DEBUG_SOLUTIONS, r);
-         }
-      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "ENDJOB\n");
-    }
-}
-
-void
-solver_printwatches(Solver *solv, int type)
-{
-  Pool *pool = solv->pool;
-  int counter;
-
-  POOL_DEBUG(type, "Watches: \n");
-  for (counter = -(pool->nsolvables - 1); counter < pool->nsolvables; counter++)
-    POOL_DEBUG(type, "    solvable [%d] -- rule [%d]\n", counter, solv->watches[counter + pool->nsolvables]);
-}
-
-void
-solver_printdecisionq(Solver *solv, int type)
-{
-  Pool *pool = solv->pool;
-  int i;
-  Id p, why;
-
-  POOL_DEBUG(type, "Decisions:\n");
-  for (i = 0; i < solv->decisionq.count; i++)
-    {
-      p = solv->decisionq.elements[i];
-      if (p > 0)
-        POOL_DEBUG(type, "%d %d install  %s, ", i, solv->decisionmap[p], pool_solvid2str(pool, p));
-      else
-        POOL_DEBUG(type, "%d %d conflict %s, ", i, -solv->decisionmap[-p], pool_solvid2str(pool, -p));
-      why = solv->decisionq_why.elements[i];
-      if (why > 0)
-       {
-         POOL_DEBUG(type, "forced by ");
-         solver_printruleclass(solv, type, solv->rules + why);
-       }
-      else if (why < 0)
-       {
-         POOL_DEBUG(type, "chosen from ");
-         solver_printruleclass(solv, type, solv->rules - why);
-       }
-      else
-        POOL_DEBUG(type, "picked for some unknown reason.\n");
-    }
-}
-
-/*
- * printdecisions
- */
-
-void
-solver_printdecisions(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Repo *installed = solv->installed;
-  Transaction *trans = solver_create_transaction(solv);
-  Id p, type;
-  int i, j;
-  Solvable *s;
-  Queue iq;
-  Queue recommendations;
-  Queue suggestions;
-  Queue orphaned;
-
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "transaction:\n");
-
-  queue_init(&iq);
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      p = trans->steps.elements[i];
-      s = pool->solvables + p;
-      type = transaction_type(trans, p, SOLVER_TRANSACTION_SHOW_ACTIVE|SOLVER_TRANSACTION_SHOW_ALL|SOLVER_TRANSACTION_SHOW_OBSOLETES|SOLVER_TRANSACTION_SHOW_MULTIINSTALL);
-      switch(type)
-        {
-       case SOLVER_TRANSACTION_MULTIINSTALL:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  multi install %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_MULTIREINSTALL:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  multi reinstall %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_INSTALL:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  install   %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_REINSTALL:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  reinstall %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_DOWNGRADE:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  downgrade %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_CHANGE:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  change    %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_UPGRADE:
-       case SOLVER_TRANSACTION_OBSOLETES:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  upgrade   %s", pool_solvable2str(pool, s));
-         break;
-       case SOLVER_TRANSACTION_ERASE:
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "  erase     %s", pool_solvable2str(pool, s));
-         break;
-       default:
-         break;
-        }
-      switch(type)
-        {
-       case SOLVER_TRANSACTION_INSTALL:
-       case SOLVER_TRANSACTION_ERASE:
-       case SOLVER_TRANSACTION_MULTIINSTALL:
-       case SOLVER_TRANSACTION_MULTIREINSTALL:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-         break;
-       case SOLVER_TRANSACTION_REINSTALL:
-       case SOLVER_TRANSACTION_DOWNGRADE:
-       case SOLVER_TRANSACTION_CHANGE:
-       case SOLVER_TRANSACTION_UPGRADE:
-       case SOLVER_TRANSACTION_OBSOLETES:
-         transaction_all_obs_pkgs(trans, p, &iq);
-         if (iq.count)
-           {
-             POOL_DEBUG(SOLV_DEBUG_RESULT, "  (obsoletes");
-             for (j = 0; j < iq.count; j++)
-               POOL_DEBUG(SOLV_DEBUG_RESULT, " %s", pool_solvid2str(pool, iq.elements[j]));
-             POOL_DEBUG(SOLV_DEBUG_RESULT, ")");
-           }
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-         break;
-       default:
-         break;
-       }
-    }
-  queue_free(&iq);
-
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-
-  queue_init(&recommendations);
-  queue_init(&suggestions);
-  queue_init(&orphaned);
-  solver_get_recommendations(solv, &recommendations, &suggestions, 0);
-  solver_get_orphaned(solv, &orphaned);
-  if (recommendations.count)
-    {
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "recommended packages:\n");
-      for (i = 0; i < recommendations.count; i++)
-       {
-         s = pool->solvables + recommendations.elements[i];
-          if (solv->decisionmap[recommendations.elements[i]] > 0)
-           {
-             if (installed && s->repo == installed)
-               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (installed)\n", pool_solvable2str(pool, s));
-             else
-               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (selected)\n", pool_solvable2str(pool, s));
-           }
-          else
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s\n", pool_solvable2str(pool, s));
-       }
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-    }
-
-  if (suggestions.count)
-    {
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "suggested packages:\n");
-      for (i = 0; i < suggestions.count; i++)
-       {
-         s = pool->solvables + suggestions.elements[i];
-          if (solv->decisionmap[suggestions.elements[i]] > 0)
-           {
-             if (installed && s->repo == installed)
-               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (installed)\n", pool_solvable2str(pool, s));
-             else
-               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (selected)\n", pool_solvable2str(pool, s));
-           }
-         else
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s\n", pool_solvable2str(pool, s));
-       }
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-    }
-  if (orphaned.count)
-    {
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "orphaned packages:\n");
-      for (i = 0; i < orphaned.count; i++)
-       {
-         s = pool->solvables + orphaned.elements[i];
-          if (solv->decisionmap[solv->orphaned.elements[i]] > 0)
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (kept)\n", pool_solvable2str(pool, s));
-         else
-           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (erased)\n", pool_solvable2str(pool, s));
-       }
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-    }
-  queue_free(&recommendations);
-  queue_free(&suggestions);
-  queue_free(&orphaned);
-  transaction_free(trans);
-}
-
-static inline
-const char *id2strnone(Pool *pool, Id id)
-{
-  return !id || id == 1 ? "(none)" : pool_id2str(pool, id);
-}
-
-void
-transaction_print(Transaction *trans)
-{
-  Pool *pool = trans->pool;
-  Queue classes, pkgs;
-  int i, j, mode, l, linel;
-  char line[76];
-  const char *n;
-
-  queue_init(&classes);
-  queue_init(&pkgs);
-  mode = SOLVER_TRANSACTION_SHOW_OBSOLETES | SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
-  transaction_classify(trans, mode, &classes);
-  for (i = 0; i < classes.count; i += 4)
-    {
-      Id class = classes.elements[i];
-      Id cnt = classes.elements[i + 1];
-      switch(class)
-       {
-       case SOLVER_TRANSACTION_ERASE:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d erased packages:\n", cnt);
-         break;
-       case SOLVER_TRANSACTION_INSTALL:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d installed packages:\n", cnt);
-         break;
-       case SOLVER_TRANSACTION_REINSTALLED:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d reinstalled packages:\n", cnt);
-         break;
-       case SOLVER_TRANSACTION_DOWNGRADED:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d downgraded packages:\n", cnt);
-         break;
-       case SOLVER_TRANSACTION_CHANGED:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d changed packages:\n", cnt);
-         break;
-       case SOLVER_TRANSACTION_UPGRADED:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d upgraded packages:\n", cnt);
-         break;
-       case SOLVER_TRANSACTION_VENDORCHANGE:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d vendor changes from '%s' to '%s':\n", cnt, id2strnone(pool, classes.elements[i + 2]), id2strnone(pool, classes.elements[i + 3]));
-         break;
-       case SOLVER_TRANSACTION_ARCHCHANGE:
-         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d arch changes from %s to %s:\n", cnt, pool_id2str(pool, classes.elements[i + 2]), pool_id2str(pool, classes.elements[i + 3]));
-         break;
-       default:
-         class = SOLVER_TRANSACTION_IGNORE;
-         break;
-       }
-      if (class == SOLVER_TRANSACTION_IGNORE)
-       continue;
-      transaction_classify_pkgs(trans, mode, class, classes.elements[i + 2], classes.elements[i + 3], &pkgs);
-      *line = 0;
-      linel = 0;
-      for (j = 0; j < pkgs.count; j++)
-       {
-         Id p = pkgs.elements[j];
-         Solvable *s = pool->solvables + p;
-         Solvable *s2;
-
-         switch(class)
-           {
-           case SOLVER_TRANSACTION_DOWNGRADED:
-           case SOLVER_TRANSACTION_UPGRADED:
-             s2 = pool->solvables + transaction_obs_pkg(trans, p);
-             POOL_DEBUG(SOLV_DEBUG_RESULT, "  - %s -> %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2));
-             break;
-           case SOLVER_TRANSACTION_VENDORCHANGE:
-           case SOLVER_TRANSACTION_ARCHCHANGE:
-             n = pool_id2str(pool, s->name);
-             l = strlen(n);
-             if (l + linel > sizeof(line) - 3)
-               {
-                 if (*line)
-                   POOL_DEBUG(SOLV_DEBUG_RESULT, "    %s\n", line);
-                 *line = 0;
-                 linel = 0;
-               }
-             if (l + linel > sizeof(line) - 3)
-               POOL_DEBUG(SOLV_DEBUG_RESULT, "    %s\n", n);
-             else
-               {
-                 if (*line)
-                   {
-                     strcpy(line + linel, ", ");
-                     linel += 2;
-                   }
-                 strcpy(line + linel, n);
-                 linel += l;
-               }
-             break;
-           default:
-             POOL_DEBUG(SOLV_DEBUG_RESULT, "  - %s\n", pool_solvable2str(pool, s));
-             break;
-           }
-       }
-      if (*line)
-       POOL_DEBUG(SOLV_DEBUG_RESULT, "    %s\n", line);
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-    }
-  queue_free(&classes);
-  queue_free(&pkgs);
-}
-
-void
-solver_printproblemruleinfo(Solver *solv, Id probr)
-{
-  Pool *pool = solv->pool;
-  Id dep, source, target;
-  SolverRuleinfo type = solver_ruleinfo(solv, probr, &source, &target, &dep);
-
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "%s\n", solver_problemruleinfo2str(solv, type, source, target, dep));
-}
-
-void
-solver_printprobleminfo(Solver *solv, Id problem)
-{
-  solver_printproblemruleinfo(solv, solver_findproblemrule(solv, problem));
-}
-
-void
-solver_printcompleteprobleminfo(Solver *solv, Id problem)
-{
-  Queue q;
-  Id probr;
-  int i, nobad = 0;
-
-  queue_init(&q);
-  solver_findallproblemrules(solv, problem, &q);
-  for (i = 0; i < q.count; i++)
-    {
-      probr = q.elements[i];
-      if (!(probr >= solv->updaterules && probr < solv->updaterules_end) && !(probr >= solv->jobrules && probr < solv->jobrules_end))
-       {
-         nobad = 1;
-         break;
-       }
-    }
-  for (i = 0; i < q.count; i++)
-    {
-      probr = q.elements[i];
-      if (nobad && ((probr >= solv->updaterules && probr < solv->updaterules_end) || (probr >= solv->jobrules && probr < solv->jobrules_end)))
-       continue;
-      solver_printproblemruleinfo(solv, probr);
-    }
-  queue_free(&q);
-}
-
-static int illegals[] = {
-  POLICY_ILLEGAL_DOWNGRADE,
-  POLICY_ILLEGAL_NAMECHANGE,
-  POLICY_ILLEGAL_ARCHCHANGE,
-  POLICY_ILLEGAL_VENDORCHANGE,
-  0
-};
-
-void
-solver_printsolution(Solver *solv, Id problem, Id solution)
-{
-  Pool *pool = solv->pool;
-  Id p, rp, element;
-
-  element = 0;
-  while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
-    {
-      if (p > 0 && rp > 0)
-       {
-         /* for replacements we want to know why it was illegal */
-         Solvable *s = pool->solvables + p, *rs = pool->solvables + rp;
-         int illegal = policy_is_illegal(solv, s, rs, 0);
-         if (illegal)
-           {
-             int i;
-             for (i = 0; illegals[i]; i++)
-               if ((illegal & illegals[i]) != 0)
-                 {
-                   POOL_DEBUG(SOLV_DEBUG_RESULT, "  - allow %s\n", policy_illegal2str(solv, illegals[i], s, rs));
-                   illegal ^= illegals[i];
-                 }
-             if (!illegal)
-               continue;
-           }
-       }
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "  - %s\n", solver_solutionelement2str(solv, p, rp));
-    }
-}
-
-void
-solver_printallsolutions(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  int pcnt;
-  Id problem, solution;
-
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "Encountered problems! Here are the solutions:\n\n");
-  pcnt = 0;
-  problem = 0;
-  while ((problem = solver_next_problem(solv, problem)) != 0)
-    {
-      pcnt++;
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "Problem %d:\n", pcnt);
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "====================================\n");
-#if 1
-      solver_printprobleminfo(solv, problem);
-#else
-      solver_printcompleteprobleminfo(solv, problem);
-#endif
-      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-      solution = 0;
-      while ((solution = solver_next_solution(solv, problem, solution)) != 0)
-        {
-         solver_printsolution(solv, problem, solution);
-          POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-        }
-    }
-}
-
-void
-solver_printtrivial(Solver *solv)
-{
-  Pool *pool = solv->pool;
-  Queue in, out;
-  Id p;
-  const char *n;
-  Solvable *s;
-  int i;
-
-  queue_init(&in);
-  for (p = 1, s = pool->solvables + p; p < solv->pool->nsolvables; p++, s++)
-    {
-      n = pool_id2str(pool, s->name);
-      if (strncmp(n, "patch:", 6) != 0 && strncmp(n, "pattern:", 8) != 0)
-        continue;
-      queue_push(&in, p);
-    }
-  if (!in.count)
-    {
-      queue_free(&in);
-      return;
-    }
-  queue_init(&out);
-  solver_trivial_installable(solv, &in, &out);
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "trivial installable status:\n");
-  for (i = 0; i < in.count; i++)
-    POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s: %d\n", pool_solvid2str(pool, in.elements[i]), out.elements[i]);
-  POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
-  queue_free(&in);
-  queue_free(&out);
-}
-
diff --git a/libsolv-0.6.15/src/solverdebug.h b/libsolv-0.6.15/src/solverdebug.h
deleted file mode 100644 (file)
index 32e427e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2008, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solverdebug.h
- *
- */
-
-#ifndef LIBSOLV_SOLVERDEBUG_H
-#define LIBSOLV_SOLVERDEBUG_H
-
-#include "pooltypes.h"
-#include "pool.h"
-#include "solver.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void solver_printruleelement(Solver *solv, int type, Rule *r, Id v);
-extern void solver_printrule(Solver *solv, int type, Rule *r);
-extern void solver_printruleclass(Solver *solv, int type, Rule *r);
-extern void solver_printproblem(Solver *solv, Id v);
-extern void solver_printwatches(Solver *solv, int type);
-extern void solver_printdecisionq(Solver *solv, int type);
-extern void solver_printdecisions(Solver *solv);
-extern void solver_printproblemruleinfo(Solver *solv, Id rule);
-extern void solver_printprobleminfo(Solver *solv, Id problem);
-extern void solver_printcompleteprobleminfo(Solver *solv, Id problem);
-extern void solver_printsolution(Solver *solv, Id problem, Id solution);
-extern void solver_printallsolutions(Solver *solv);
-extern void solver_printtrivial(Solver *solv);
-
-extern void transaction_print(Transaction *trans);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_SOLVERDEBUG_H */
-
diff --git a/libsolv-0.6.15/src/solvversion.c b/libsolv-0.6.15/src/solvversion.c
deleted file mode 100644 (file)
index d66e195..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (c) 2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include "solvversion.h"
-
-const char solv_version[] = LIBSOLV_VERSION_STRING;
-int solv_version_major = LIBSOLV_VERSION_MAJOR;
-int solv_version_minor = LIBSOLV_VERSION_MINOR;
-int solv_version_patch = LIBSOLV_VERSION_PATCH;
diff --git a/libsolv-0.6.15/src/solvversion.h.in b/libsolv-0.6.15/src/solvversion.h.in
deleted file mode 100644 (file)
index 268219c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * solvversion.h
- * 
- */
-
-#ifndef LIBSOLV_SOLVVERSION_H
-#define LIBSOLV_SOLVVERSION_H
-
-#define LIBSOLV_VERSION_STRING "@VERSION@"
-#define LIBSOLV_VERSION_MAJOR @LIBSOLV_MAJOR@
-#define LIBSOLV_VERSION_MINOR @LIBSOLV_MINOR@
-#define LIBSOLV_VERSION_PATCH @LIBSOLV_PATCH@
-#define LIBSOLV_VERSION (LIBSOLV_VERSION_MAJOR * 10000 + LIBSOLV_VERSION_MINOR * 100 + LIBSOLV_VERSION_PATCH)
-
-extern const char solv_version[];
-extern int solv_version_major;
-extern int solv_version_minor;
-extern int solv_version_patch;
-
-#endif
diff --git a/libsolv-0.6.15/src/strpool.c b/libsolv-0.6.15/src/strpool.c
deleted file mode 100644 (file)
index af43e01..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <string.h>
-#include "util.h"
-#include "strpool.h"
-
-#define STRING_BLOCK      2047
-#define STRINGSPACE_BLOCK 65535
-
-void
-stringpool_init(Stringpool *ss, const char *strs[])
-{
-  unsigned totalsize = 0;
-  unsigned count;
-
-  memset(ss, 0, sizeof(*ss));
-  /* count number and total size of predefined strings */
-  for (count = 0; strs[count]; count++)
-    totalsize += strlen(strs[count]) + 1;
-
-  /* alloc appropriate space */
-  ss->stringspace = solv_extend_resize(0, totalsize, 1, STRINGSPACE_BLOCK);
-  ss->strings = solv_extend_resize(0, count, sizeof(Offset), STRING_BLOCK);
-
-  /* now copy predefined strings into allocated space */
-  ss->sstrings = 0;
-  for (count = 0; strs[count]; count++)
-    {
-      strcpy(ss->stringspace + ss->sstrings, strs[count]);
-      ss->strings[count] = ss->sstrings;
-      ss->sstrings += strlen(strs[count]) + 1;
-    }
-  ss->nstrings = count;
-}
-
-void
-stringpool_free(Stringpool *ss)
-{
-  solv_free(ss->strings);
-  solv_free(ss->stringspace);
-  solv_free(ss->stringhashtbl);
-}
-
-void
-stringpool_freehash(Stringpool *ss)
-{
-  ss->stringhashtbl = solv_free(ss->stringhashtbl);
-  ss->stringhashmask = 0;
-}
-
-void
-stringpool_init_empty(Stringpool *ss)
-{
-  const char *emptystrs[] = {
-    "<NULL>",
-    "",
-    0,
-  };
-  stringpool_init(ss, emptystrs);
-}
-
-void
-stringpool_clone(Stringpool *ss, Stringpool *from)
-{
-  memset(ss, 0, sizeof(*ss));
-  ss->strings = solv_extend_resize(0, from->nstrings, sizeof(Offset), STRING_BLOCK);
-  memcpy(ss->strings, from->strings, from->nstrings * sizeof(Offset));
-  ss->stringspace = solv_extend_resize(0, from->sstrings, 1, STRINGSPACE_BLOCK);
-  memcpy(ss->stringspace, from->stringspace, from->sstrings);
-  ss->nstrings = from->nstrings;
-  ss->sstrings = from->sstrings;
-}
-
-Id
-stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create)
-{
-  Hashval h, hh, hashmask, oldhashmask;
-  int i;
-  Id id;
-  Hashtable hashtbl;
-
-  if (!str)
-    return STRID_NULL;
-  if (!len)
-    return STRID_EMPTY;
-
-  hashmask = oldhashmask = ss->stringhashmask;
-  hashtbl = ss->stringhashtbl;
-
-  /* expand hashtable if needed */
-  if ((Hashval)ss->nstrings * 2 > hashmask)
-    {
-      solv_free(hashtbl);
-
-      /* realloc hash table */
-      ss->stringhashmask = hashmask = mkmask(ss->nstrings + STRING_BLOCK);
-      ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id));
-
-      /* rehash all strings into new hashtable */
-      for (i = 1; i < ss->nstrings; i++)
-       {
-         h = strhash(ss->stringspace + ss->strings[i]) & hashmask;
-         hh = HASHCHAIN_START;
-         while (hashtbl[h] != 0)
-           h = HASHCHAIN_NEXT(h, hh, hashmask);
-         hashtbl[h] = i;
-       }
-    }
-
-  /* compute hash and check for match */
-  h = strnhash(str, len) & hashmask;
-  hh = HASHCHAIN_START;
-  while ((id = hashtbl[h]) != 0)
-    {
-      if(!memcmp(ss->stringspace + ss->strings[id], str, len)
-         && ss->stringspace[ss->strings[id] + len] == 0)
-       break;
-      h = HASHCHAIN_NEXT(h, hh, hashmask);
-    }
-  if (id || !create)    /* exit here if string found */
-    return id;
-
-  /* this should be a test for a flag that tells us if the
-   * correct blocking is used, but adding a flag would break
-   * the ABI. So we use the existance of the hash area as
-   * indication instead */
-  if (!oldhashmask)
-    {
-      ss->stringspace = solv_extend_resize(ss->stringspace, ss->sstrings + len + 1, 1, STRINGSPACE_BLOCK);
-      ss->strings = solv_extend_resize(ss->strings, ss->nstrings + 1, sizeof(Offset), STRING_BLOCK);
-    }
-
-  /* generate next id and save in table */
-  id = ss->nstrings++;
-  hashtbl[h] = id;
-
-  ss->strings = solv_extend(ss->strings, id, 1, sizeof(Offset), STRING_BLOCK);
-  ss->strings[id] = ss->sstrings;      /* we will append to the end */
-
-  /* append string to stringspace */
-  ss->stringspace = solv_extend(ss->stringspace, ss->sstrings, len + 1, 1, STRINGSPACE_BLOCK);
-  memcpy(ss->stringspace + ss->sstrings, str, len);
-  ss->stringspace[ss->sstrings + len] = 0;
-  ss->sstrings += len + 1;
-  return id;
-}
-
-Id
-stringpool_str2id(Stringpool *ss, const char *str, int create)
-{
-  if (!str)
-    return STRID_NULL;
-  if (!*str)
-    return STRID_EMPTY;
-  return stringpool_strn2id(ss, str, (unsigned int)strlen(str), create);
-}
-
-void
-stringpool_shrink(Stringpool *ss)
-{
-  ss->stringspace = solv_extend_resize(ss->stringspace, ss->sstrings, 1, STRINGSPACE_BLOCK);
-  ss->strings = solv_extend_resize(ss->strings, ss->nstrings, sizeof(Offset), STRING_BLOCK);
-}
diff --git a/libsolv-0.6.15/src/strpool.h b/libsolv-0.6.15/src/strpool.h
deleted file mode 100644 (file)
index c97b873..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-#ifndef LIBSOLV_STRINGPOOL_H
-#define LIBSOLV_STRINGPOOL_H
-
-#include "pooltypes.h"
-#include "hash.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define STRID_NULL  0
-#define STRID_EMPTY 1
-
-struct _Stringpool
-{
-  Offset *strings;            /* table of offsets into stringspace, indexed by Id: Id -> Offset */
-  int nstrings;               /* number of ids in strings table */
-  char *stringspace;          /* space for all unique strings: stringspace + Offset = string */
-  Offset sstrings;            /* size of used stringspace */
-
-  Hashtable stringhashtbl;    /* hash table: (string ->) Hash -> Id */
-  Hashval stringhashmask;     /* modulo value for hash table (size of table - 1) */
-};
-
-void stringpool_init(Stringpool *ss, const char *strs[]);
-void stringpool_init_empty(Stringpool *ss);
-void stringpool_clone(Stringpool *ss, Stringpool *from);
-void stringpool_free(Stringpool *ss);
-void stringpool_freehash(Stringpool *ss);
-
-Id stringpool_str2id(Stringpool *ss, const char *str, int create);
-Id stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create);
-
-void stringpool_shrink(Stringpool *ss);
-
-
-static inline const char *
-stringpool_id2str(Stringpool *ss, Id id)
-{
-  return ss->stringspace + ss->strings[id];
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libsolv-0.6.15/src/transaction.c b/libsolv-0.6.15/src/transaction.c
deleted file mode 100644 (file)
index ffe1ec2..0000000
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- * Copyright (c) 2007-2015, SUSE LLC
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * transaction.c
- *
- * Transaction handling
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <assert.h>
-
-#include "transaction.h"
-#include "solver.h"
-#include "bitmap.h"
-#include "pool.h"
-#include "poolarch.h"
-#include "evr.h"
-#include "util.h"
-
-static int
-obsq_sortcmp(const void *ap, const void *bp, void *dp)
-{
-  Id a, b, oa, ob;
-  Pool *pool = dp;
-  Solvable *s, *oas, *obs;
-  int r;
-
-  a = ((Id *)ap)[0];
-  oa = ((Id *)ap)[1];
-  b = ((Id *)bp)[0];
-  ob = ((Id *)bp)[1];
-  if (a != b)
-    return a - b;
-  if (oa == ob)
-    return 0;
-  s = pool->solvables + a;
-  oas = pool->solvables + oa;
-  obs = pool->solvables + ob;
-  if (oas->name != obs->name)
-    {
-      /* bring "same name" obsoleters (i.e. upgraders) to front */
-      if (oas->name == s->name)
-        return -1;
-      if (obs->name == s->name)
-        return 1;
-      return strcmp(pool_id2str(pool, oas->name), pool_id2str(pool, obs->name));
-    }
-  r = pool_evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE);
-  if (r)
-    return -r; /* highest version first */
-  return oa - ob;
-}
-
-void
-transaction_all_obs_pkgs(Transaction *trans, Id p, Queue *pkgs)
-{
-  Pool *pool = trans->pool;
-  Solvable *s = pool->solvables + p;
-  Queue *ti = &trans->transaction_info;
-  Id q;
-  int i;
-
-  queue_empty(pkgs);
-  if (p <= 0 || !s->repo)
-    return;
-  if (s->repo == pool->installed)
-    {
-      q = trans->transaction_installed[p - pool->installed->start];
-      if (!q)
-       return;
-      if (q > 0)
-       {
-         /* only a single obsoleting package */
-         queue_push(pkgs, q);
-         return;
-       }
-      /* find which packages obsolete us */
-      for (i = 0; i < ti->count; i += 2)
-       if (ti->elements[i + 1] == p)
-         queue_push2(pkgs, p, ti->elements[i]);
-      /* sort obsoleters */
-      if (pkgs->count > 2)
-       solv_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
-      for (i = 0; i < pkgs->count; i += 2)
-       pkgs->elements[i / 2] = pkgs->elements[i + 1];
-      queue_truncate(pkgs, pkgs->count / 2);
-    }
-  else
-    {
-      /* find the packages we obsolete */
-      for (i = 0; i < ti->count; i += 2)
-       {
-         if (ti->elements[i] == p)
-           queue_push(pkgs, ti->elements[i + 1]);
-         else if (pkgs->count)
-           break;
-       }
-    }
-}
-
-Id
-transaction_obs_pkg(Transaction *trans, Id p)
-{
-  Pool *pool = trans->pool;
-  Solvable *s = pool->solvables + p;
-  Queue *ti;
-  int i;
-
-  if (p <= 0 || !s->repo)
-    return 0;
-  if (s->repo == pool->installed)
-    {
-      p = trans->transaction_installed[p - pool->installed->start];
-      return p < 0 ? -p : p;
-    }
-  ti = &trans->transaction_info;
-  for (i = 0; i < ti->count; i += 2)
-    if (ti->elements[i] == p)
-      return ti->elements[i + 1];
-  return 0;
-}
-
-
-/*
- * calculate base type of transaction element
- */
-
-static Id
-transaction_base_type(Transaction *trans, Id p)
-{
-  Pool *pool = trans->pool;
-  Solvable *s, *s2;
-  int r;
-  Id p2;
-
-  if (!MAPTST(&trans->transactsmap, p))
-    return SOLVER_TRANSACTION_IGNORE;
-  p2 = transaction_obs_pkg(trans, p);
-  if (pool->installed && pool->solvables[p].repo == pool->installed)
-    {
-      /* erase */
-      if (!p2)
-       return SOLVER_TRANSACTION_ERASE;
-      s = pool->solvables + p;
-      s2 = pool->solvables + p2;
-      if (s->name == s2->name)
-       {
-         if (s->evr == s2->evr && solvable_identical(s, s2))
-           return SOLVER_TRANSACTION_REINSTALLED;
-         r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
-         if (r < 0)
-           return SOLVER_TRANSACTION_UPGRADED;
-         else if (r > 0)
-           return SOLVER_TRANSACTION_DOWNGRADED;
-         return SOLVER_TRANSACTION_CHANGED;
-       }
-      return SOLVER_TRANSACTION_OBSOLETED;
-    }
-  else
-    {
-      /* install or multiinstall */
-      int multi = trans->multiversionmap.size && MAPTST(&trans->multiversionmap, p);
-      if (multi)
-       {
-         if (p2)
-           {
-             s = pool->solvables + p;
-             s2 = pool->solvables + p2;
-             if (s->name == s2->name && s->arch == s2->arch && s->evr == s2->evr)
-               return SOLVER_TRANSACTION_MULTIREINSTALL;
-           }
-         return SOLVER_TRANSACTION_MULTIINSTALL;
-       }
-      if (!p2)
-       return SOLVER_TRANSACTION_INSTALL;
-      s = pool->solvables + p;
-      s2 = pool->solvables + p2;
-      if (s->name == s2->name)
-       {
-         if (s->evr == s2->evr && solvable_identical(s, s2))
-           return SOLVER_TRANSACTION_REINSTALL;
-         r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
-         if (r > 0)
-           return SOLVER_TRANSACTION_UPGRADE;
-         else if (r < 0)
-           return SOLVER_TRANSACTION_DOWNGRADE;
-         else
-           return SOLVER_TRANSACTION_CHANGE;
-       }
-      return SOLVER_TRANSACTION_OBSOLETES;
-    }
-}
-
-/* these packages do not get installed by the package manager */
-static inline int
-is_pseudo_package(Pool *pool, Solvable *s)
-{
-  const char *n = pool_id2str(pool, s->name);
-  if (*n == 'p' && !strncmp(n, "patch:", 6))
-    return 1;
-  if (*n == 'p' && !strncmp(n, "pattern:", 8))
-    return 1;
-  if (*n == 'p' && !strncmp(n, "product:", 8))
-    return 1;
-  if (*n == 'a' && !strncmp(n, "application:", 12))
-    return 1;
-  return 0;
-}
-
-/* these packages will never show up installed */
-static inline int
-is_noinst_pseudo_package(Pool *pool, Solvable *s)
-{
-  const char *n = pool_id2str(pool, s->name);
-  if (!strncmp(n, "patch:", 6))
-    return 1;
-  if (!strncmp(n, "pattern:", 8))
-    {
-#if defined(SUSE) && defined(ENABLE_LINKED_PKGS)
-      /* unlike normal patterns, autopatterns *can* be installed (via the package link),
-         so do not filter them */
-      if (s->provides)
-       {
-         Id prv, *prvp = s->repo->idarraydata + s->provides;
-         while ((prv = *prvp++) != 0)
-           if (ISRELDEP(prv) && !strcmp(pool_id2str(pool, prv), "autopattern()"))
-             return 0;
-       }
-#endif
-      return 1;
-    }
-  return 0;
-}
-
-static int
-obsoleted_by_pseudos_only(Transaction *trans, Id p)
-{
-  Pool *pool = trans->pool;
-  Queue q;
-  Id op;
-  int i;
-
-  op = transaction_obs_pkg(trans, p);
-  if (op && !is_pseudo_package(pool, pool->solvables + op))
-    return 0;
-  queue_init(&q);
-  transaction_all_obs_pkgs(trans, p, &q);
-  for (i = 0; i < q.count; i++)
-    if (!is_pseudo_package(pool, pool->solvables + q.elements[i]))
-      break;
-  i = !q.count || i < q.count ? 0 : 1;
-  queue_free(&q);
-  return i;
-}
-
-/*
- * return type of transaction element
- *
- * filtering is needed if either not all packages are shown
- * or replaces are not shown, as otherwise parts of the
- * transaction might not be shown to the user */
-
-Id
-transaction_type(Transaction *trans, Id p, int mode)
-{
-  Pool *pool = trans->pool;
-  Solvable *s = pool->solvables + p;
-  Queue oq, rq;
-  Id type, q;
-  int i, j, ref = 0;
-
-  if (!s->repo)
-    return SOLVER_TRANSACTION_IGNORE;
-
-  /* XXX: SUSE only? */
-  if (!(mode & SOLVER_TRANSACTION_KEEP_PSEUDO) && is_noinst_pseudo_package(pool, s))
-    return SOLVER_TRANSACTION_IGNORE;
-
-  type = transaction_base_type(trans, p);
-
-  if (type == SOLVER_TRANSACTION_IGNORE)
-    return SOLVER_TRANSACTION_IGNORE;  /* not part of the transaction */
-
-  if ((mode & SOLVER_TRANSACTION_RPM_ONLY) != 0)
-    {
-      /* application wants to know what to feed to the package manager */
-      if (!(mode & SOLVER_TRANSACTION_KEEP_PSEUDO) && is_pseudo_package(pool, s))
-       return SOLVER_TRANSACTION_IGNORE;
-      if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL)
-       return type;
-      if (s->repo == pool->installed)
-       {
-         /* check if we're a real package that is obsoleted by pseudos */
-         if (!is_pseudo_package(pool, s) && obsoleted_by_pseudos_only(trans, s - pool->solvables))
-           return SOLVER_TRANSACTION_ERASE;
-         return SOLVER_TRANSACTION_IGNORE;     /* ignore as we're being obsoleted */
-       }
-      if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
-       return SOLVER_TRANSACTION_MULTIINSTALL;
-      return SOLVER_TRANSACTION_INSTALL;
-    }
-
-  if ((mode & SOLVER_TRANSACTION_SHOW_MULTIINSTALL) == 0)
-    {
-      /* application wants to make no difference between install
-       * and multiinstall */
-      if (type == SOLVER_TRANSACTION_MULTIINSTALL)
-        type = SOLVER_TRANSACTION_INSTALL;
-      if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
-        type = SOLVER_TRANSACTION_REINSTALL;
-    }
-
-  if ((mode & SOLVER_TRANSACTION_CHANGE_IS_REINSTALL) != 0)
-    {
-      /* application wants to make no difference between change
-       * and reinstall */
-      if (type == SOLVER_TRANSACTION_CHANGED)
-       type = SOLVER_TRANSACTION_REINSTALLED;
-      else if (type == SOLVER_TRANSACTION_CHANGE)
-       type = SOLVER_TRANSACTION_REINSTALL;
-    }
-
-  if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL)
-    return type;
-
-  if (s->repo == pool->installed && (mode & SOLVER_TRANSACTION_SHOW_ACTIVE) == 0)
-    {
-      /* erase element and we're showing the passive side */
-      if (type == SOLVER_TRANSACTION_OBSOLETED && (mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
-       type = SOLVER_TRANSACTION_ERASE;
-      if (type == SOLVER_TRANSACTION_OBSOLETED && (mode & SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE) != 0)
-       type = SOLVER_TRANSACTION_UPGRADED;
-      return type;
-    }
-  if (s->repo != pool->installed && (mode & SOLVER_TRANSACTION_SHOW_ACTIVE) != 0)
-    {
-      /* install element and we're showing the active side */
-      if (type == SOLVER_TRANSACTION_OBSOLETES && (mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
-       type = SOLVER_TRANSACTION_INSTALL;
-      if (type == SOLVER_TRANSACTION_OBSOLETES && (mode & SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE) != 0)
-       type = SOLVER_TRANSACTION_UPGRADE;
-      return type;
-    }
-
-  /* the element doesn't match the show mode */
-
-  /* if we're showing all references, we can ignore this package */
-  if ((mode & (SOLVER_TRANSACTION_SHOW_ALL|SOLVER_TRANSACTION_SHOW_OBSOLETES)) == (SOLVER_TRANSACTION_SHOW_ALL|SOLVER_TRANSACTION_SHOW_OBSOLETES))
-    return SOLVER_TRANSACTION_IGNORE;
-
-  /* we're not showing all refs. check if some other package
-   * references us. If yes, it's safe to ignore this package,
-   * otherwise we need to map the type */
-
-  /* most of the time there's only one reference, so check it first */
-  q = transaction_obs_pkg(trans, p);
-
-  if ((mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
-    {
-      Solvable *sq = pool->solvables + q;
-      if (sq->name != s->name)
-       {
-         /* it's a replace but we're not showing replaces. map type. */
-         if (s->repo == pool->installed)
-           return SOLVER_TRANSACTION_ERASE;
-         else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
-           return SOLVER_TRANSACTION_MULTIINSTALL;
-         else
-           return SOLVER_TRANSACTION_INSTALL;
-       }
-    }
-
-  /* if there's a match, p will be shown when q
-   * is processed */
-  if (transaction_obs_pkg(trans, q) == p)
-    return SOLVER_TRANSACTION_IGNORE;
-
-  /* too bad, a miss. check em all */
-  queue_init(&oq);
-  queue_init(&rq);
-  transaction_all_obs_pkgs(trans, p, &oq);
-  for (i = 0; i < oq.count; i++)
-    {
-      q = oq.elements[i];
-      if ((mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
-       {
-         Solvable *sq = pool->solvables + q;
-         if (sq->name != s->name)
-           continue;
-       }
-      /* check if we are referenced? */
-      if ((mode & SOLVER_TRANSACTION_SHOW_ALL) != 0)
-       {
-         transaction_all_obs_pkgs(trans, q, &rq);
-         for (j = 0; j < rq.count; j++)
-           if (rq.elements[j] == p)
-             {
-               ref = 1;
-               break;
-             }
-         if (ref)
-           break;
-       }
-      else if (transaction_obs_pkg(trans, q) == p)
-        {
-         ref = 1;
-         break;
-        }
-    }
-  queue_free(&oq);
-  queue_free(&rq);
-
-  if (!ref)
-    {
-      /* we're not referenced. map type */
-      if (s->repo == pool->installed)
-       return SOLVER_TRANSACTION_ERASE;
-      else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
-       return SOLVER_TRANSACTION_MULTIINSTALL;
-      else
-       return SOLVER_TRANSACTION_INSTALL;
-    }
-  /* there was a ref, so p is shown with some other package */
-  return SOLVER_TRANSACTION_IGNORE;
-}
-
-
-
-static int
-classify_cmp(const void *ap, const void *bp, void *dp)
-{
-  Transaction *trans = dp;
-  Pool *pool = trans->pool;
-  const Id *a = ap;
-  const Id *b = bp;
-  int r;
-
-  r = a[0] - b[0];
-  if (r)
-    return r;
-  r = a[2] - b[2];
-  if (r)
-    return a[2] && b[2] ? strcmp(pool_id2str(pool, a[2]), pool_id2str(pool, b[2])) : r;
-  r = a[3] - b[3];
-  if (r)
-    return a[3] && b[3] ? strcmp(pool_id2str(pool, a[3]), pool_id2str(pool, b[3])) : r;
-  return 0;
-}
-
-static int
-classify_cmp_pkgs(const void *ap, const void *bp, void *dp)
-{
-  Transaction *trans = dp;
-  Pool *pool = trans->pool;
-  Id a = *(Id *)ap;
-  Id b = *(Id *)bp;
-  Solvable *sa, *sb;
-
-  sa = pool->solvables + a;
-  sb = pool->solvables + b;
-  if (sa->name != sb->name)
-    return strcmp(pool_id2str(pool, sa->name), pool_id2str(pool, sb->name));
-  if (sa->evr != sb->evr)
-    {
-      int r = pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE);
-      if (r)
-       return r;
-    }
-  return a - b;
-}
-
-static inline void
-queue_push4(Queue *q, Id id1, Id id2, Id id3, Id id4)
-{
-  queue_push(q, id1);
-  queue_push(q, id2);
-  queue_push(q, id3);
-  queue_push(q, id4);
-}
-
-static inline void
-queue_unshift4(Queue *q, Id id1, Id id2, Id id3, Id id4)
-{
-  queue_unshift(q, id4);
-  queue_unshift(q, id3);
-  queue_unshift(q, id2);
-  queue_unshift(q, id1);
-}
-
-void
-transaction_classify(Transaction *trans, int mode, Queue *classes)
-{
-  Pool *pool = trans->pool;
-  int ntypes[SOLVER_TRANSACTION_MAXTYPE + 1];
-  Solvable *s, *sq;
-  Id v, vq, type, p, q;
-  int i, j;
-
-  queue_empty(classes);
-  memset(ntypes, 0, sizeof(ntypes));
-  /* go through transaction and classify each step */
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      p = trans->steps.elements[i];
-      s = pool->solvables + p;
-      type = transaction_type(trans, p, mode);
-      ntypes[type]++;
-      if (!pool->installed || s->repo != pool->installed)
-       continue;
-      /* don't report vendor/arch changes if we were mapped to erase. */
-      if (type == SOLVER_TRANSACTION_ERASE)
-       continue;
-      /* look at arch/vendor changes */
-      q = transaction_obs_pkg(trans, p);
-      if (!q)
-       continue;
-      sq = pool->solvables + q;
-
-      v = s->arch;
-      vq = sq->arch;
-      if (v != vq)
-       {
-         if ((mode & SOLVER_TRANSACTION_MERGE_ARCHCHANGES) != 0)
-           v = vq = 0;
-         for (j = 0; j < classes->count; j += 4)
-           if (classes->elements[j] == SOLVER_TRANSACTION_ARCHCHANGE && classes->elements[j + 2] == v && classes->elements[j + 3] == vq)
-             break;
-         if (j == classes->count)
-           queue_push4(classes, SOLVER_TRANSACTION_ARCHCHANGE, 1, v, vq);
-         else
-           classes->elements[j + 1]++;
-       }
-
-      v = s->vendor ? s->vendor : 1;
-      vq = sq->vendor ? sq->vendor : 1;
-      if (v != vq)
-       {
-         if ((mode & SOLVER_TRANSACTION_MERGE_VENDORCHANGES) != 0)
-           v = vq = 0;
-         for (j = 0; j < classes->count; j += 4)
-           if (classes->elements[j] == SOLVER_TRANSACTION_VENDORCHANGE && classes->elements[j + 2] == v && classes->elements[j + 3] == vq)
-             break;
-         if (j == classes->count)
-           queue_push4(classes, SOLVER_TRANSACTION_VENDORCHANGE, 1, v, vq);
-         else
-           classes->elements[j + 1]++;
-       }
-    }
-  /* now sort all vendor/arch changes */
-  if (classes->count > 4)
-    solv_sort(classes->elements, classes->count / 4, 4 * sizeof(Id), classify_cmp, trans);
-  /* finally add all classes. put erases last */
-  i = SOLVER_TRANSACTION_ERASE;
-  if (ntypes[i])
-    queue_unshift4(classes, i, ntypes[i], 0, 0);
-  for (i = SOLVER_TRANSACTION_MAXTYPE; i > 0; i--)
-    {
-      if (!ntypes[i])
-       continue;
-      if (i == SOLVER_TRANSACTION_ERASE)
-       continue;
-      queue_unshift4(classes, i, ntypes[i], 0, 0);
-    }
-}
-
-void
-transaction_classify_pkgs(Transaction *trans, int mode, Id class, Id from, Id to, Queue *pkgs)
-{
-  Pool *pool = trans->pool;
-  int i;
-  Id type, p, q;
-  Solvable *s, *sq;
-
-  queue_empty(pkgs);
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      p = trans->steps.elements[i];
-      s = pool->solvables + p;
-      if (class <= SOLVER_TRANSACTION_MAXTYPE)
-       {
-         type = transaction_type(trans, p, mode);
-         if (type == class)
-           queue_push(pkgs, p);
-         continue;
-       }
-      if (!pool->installed || s->repo != pool->installed)
-       continue;
-      q = transaction_obs_pkg(trans, p);
-      if (!q)
-       continue;
-      sq = pool->solvables + q;
-      if (class == SOLVER_TRANSACTION_ARCHCHANGE)
-       {
-         if ((!from && !to) || (s->arch == from && sq->arch == to))
-           queue_push(pkgs, p);
-         continue;
-       }
-      if (class == SOLVER_TRANSACTION_VENDORCHANGE)
-       {
-         Id v = s->vendor ? s->vendor : 1;
-         Id vq = sq->vendor ? sq->vendor : 1;
-         if ((!from && !to) || (v == from && vq == to))
-           queue_push(pkgs, p);
-         continue;
-       }
-    }
-  if (pkgs->count > 1)
-    solv_sort(pkgs->elements, pkgs->count, sizeof(Id), classify_cmp_pkgs, trans);
-}
-
-static void
-create_transaction_info(Transaction *trans, Queue *decisionq)
-{
-  Pool *pool = trans->pool;
-  Queue *ti = &trans->transaction_info;
-  Repo *installed = pool->installed;
-  int i, j, multi;
-  Id p, p2, pp2;
-  Solvable *s, *s2;
-
-  queue_empty(ti);
-  trans->transaction_installed = solv_free(trans->transaction_installed);
-  if (!installed)
-    return;    /* no info needed */
-  for (i = 0; i < decisionq->count; i++)
-    {
-      p = decisionq->elements[i];
-      if (p <= 0 || p == SYSTEMSOLVABLE)
-       continue;
-      s = pool->solvables + p;
-      if (!s->repo || s->repo == installed)
-       continue;
-      multi = trans->multiversionmap.size && MAPTST(&trans->multiversionmap, p);
-      FOR_PROVIDES(p2, pp2, s->name)
-       {
-         if (!MAPTST(&trans->transactsmap, p2))
-           continue;
-         s2 = pool->solvables + p2;
-         if (s2->repo != installed)
-           continue;
-         if (multi && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch))
-           continue;
-         if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
-           continue;
-         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
-           continue;
-         queue_push2(ti, p, p2);
-       }
-      if (s->obsoletes && !multi)
-       {
-         Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-         while ((obs = *obsp++) != 0)
-           {
-             FOR_PROVIDES(p2, pp2, obs)
-               {
-                 if (!MAPTST(&trans->transactsmap, p2))
-                   continue;
-                 s2 = pool->solvables + p2;
-                 if (s2->repo != installed)
-                   continue;
-                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
-                   continue;
-                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
-                   continue;
-                 queue_push2(ti, p, p2);
-               }
-           }
-       }
-    }
-  if (ti->count > 2)
-    {
-      /* sort and unify */
-      solv_sort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
-      for (i = j = 2; i < ti->count; i += 2)
-       {
-         if (ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1])
-           continue;
-         ti->elements[j++] = ti->elements[i];
-         ti->elements[j++] = ti->elements[i + 1];
-       }
-      queue_truncate(ti, j);
-    }
-
-  /* create transaction_installed helper */
-  /*   entry > 0: exactly one obsoleter, entry < 0: multiple obsoleters, -entry is "best" */
-  trans->transaction_installed = solv_calloc(installed->end - installed->start, sizeof(Id));
-  for (i = 0; i < ti->count; i += 2)
-    {
-      j = ti->elements[i + 1] - installed->start;
-      if (!trans->transaction_installed[j])
-       trans->transaction_installed[j] = ti->elements[i];
-      else
-       {
-         /* more than one package obsoletes us. compare to find "best" */
-         Id q[4];
-         if (trans->transaction_installed[j] > 0)
-           trans->transaction_installed[j] = -trans->transaction_installed[j];
-         q[0] = q[2] = ti->elements[i + 1];
-         q[1] = ti->elements[i];
-         q[3] = -trans->transaction_installed[j];
-         if (obsq_sortcmp(q, q + 2, pool) < 0)
-           trans->transaction_installed[j] = -ti->elements[i];
-       }
-    }
-}
-
-/* create a transaction from the decisionq */
-Transaction *
-transaction_create_decisionq(Pool *pool, Queue *decisionq, Map *multiversionmap)
-{
-  Repo *installed = pool->installed;
-  int i, needmulti;
-  Id p;
-  Solvable *s;
-  Transaction *trans;
-
-  trans = transaction_create(pool);
-  if (multiversionmap && !multiversionmap->size)
-    multiversionmap = 0;       /* ignore empty map */
-  queue_empty(&trans->steps);
-  map_init(&trans->transactsmap, pool->nsolvables);
-  needmulti = 0;
-  for (i = 0; i < decisionq->count; i++)
-    {
-      p = decisionq->elements[i];
-      s = pool->solvables + (p > 0 ? p : -p);
-      if (!s->repo)
-       continue;
-      if (installed && s->repo == installed && p < 0)
-       MAPSET(&trans->transactsmap, -p);
-      if (!(installed && s->repo == installed) && p > 0)
-       {
-         MAPSET(&trans->transactsmap, p);
-         if (multiversionmap && MAPTST(multiversionmap, p))
-           needmulti = 1;
-       }
-    }
-  MAPCLR(&trans->transactsmap, SYSTEMSOLVABLE);
-  if (needmulti)
-    map_init_clone(&trans->multiversionmap, multiversionmap);
-
-  create_transaction_info(trans, decisionq);
-
-  if (installed)
-    {
-      FOR_REPO_SOLVABLES(installed, p, s)
-       {
-         if (MAPTST(&trans->transactsmap, p))
-           queue_push(&trans->steps, p);
-       }
-    }
-  for (i = 0; i < decisionq->count; i++)
-    {
-      p = decisionq->elements[i];
-      if (p > 0 && MAPTST(&trans->transactsmap, p))
-        queue_push(&trans->steps, p);
-    }
-  return trans;
-}
-
-int
-transaction_installedresult(Transaction *trans, Queue *installedq)
-{
-  Pool *pool = trans->pool;
-  Repo *installed = pool->installed;
-  Solvable *s;
-  int i, cutoff;
-  Id p;
-
-  queue_empty(installedq);
-  /* first the new installs, than the kept packages */
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      p = trans->steps.elements[i];
-      s = pool->solvables + p;
-      if (installed && s->repo == installed)
-       continue;
-      queue_push(installedq, p);
-    }
-  cutoff = installedq->count;
-  if (installed)
-    {
-      FOR_REPO_SOLVABLES(installed, p, s)
-       if (!MAPTST(&trans->transactsmap, p))
-          queue_push(installedq, p);
-    }
-  return cutoff;
-}
-
-static void
-transaction_make_installedmap(Transaction *trans, Map *installedmap)
-{
-  Pool *pool = trans->pool;
-  Repo *installed = pool->installed;
-  Solvable *s;
-  Id p;
-  int i;
-
-  map_init(installedmap, pool->nsolvables);
-  for (i = 0; i < trans->steps.count; i++)
-    {
-      p = trans->steps.elements[i];
-      s = pool->solvables + p;
-      if (!installed || s->repo != installed)
-        MAPSET(installedmap, p);
-    }
-  if (installed)
-    {
-      FOR_REPO_SOLVABLES(installed, p, s)
-       if (!MAPTST(&trans->transactsmap, p))
-          MAPSET(installedmap, p);
-    }
-}
-
-int
-transaction_calc_installsizechange(Transaction *trans)
-{
-  Map installedmap;
-  int change;
-
-  transaction_make_installedmap(trans, &installedmap);
-  change = pool_calc_installsizechange(trans->pool, &installedmap);
-  map_free(&installedmap);
-  return change;
-}
-
-void
-transaction_calc_duchanges(Transaction *trans, DUChanges *mps, int nmps)
-{
-  Map installedmap;
-
-  transaction_make_installedmap(trans, &installedmap);
-  pool_calc_duchanges(trans->pool, &installedmap, mps, nmps);
-  map_free(&installedmap);
-}
-
-Transaction *
-transaction_create(Pool *pool)
-{
-  Transaction *trans = solv_calloc(1, sizeof(*trans));
-  trans->pool = pool;
-  return trans;
-}
-
-Transaction *
-transaction_create_clone(Transaction *srctrans)
-{
-  Transaction *trans = transaction_create(srctrans->pool);
-  queue_init_clone(&trans->steps, &srctrans->steps);
-  queue_init_clone(&trans->transaction_info, &srctrans->transaction_info);
-  if (srctrans->transaction_installed)
-    {
-      Repo *installed = srctrans->pool->installed;
-      trans->transaction_installed = solv_memdup2(srctrans->transaction_installed, installed->end - installed->start, sizeof(Id));
-    }
-  map_init_clone(&trans->transactsmap, &srctrans->transactsmap);
-  map_init_clone(&trans->multiversionmap, &srctrans->multiversionmap);
-  if (srctrans->orderdata)
-    transaction_clone_orderdata(trans, srctrans);
-  return trans;
-}
-
-void
-transaction_free(Transaction *trans)
-{
-  queue_free(&trans->steps);
-  queue_free(&trans->transaction_info);
-  trans->transaction_installed = solv_free(trans->transaction_installed);
-  map_free(&trans->transactsmap);
-  map_free(&trans->multiversionmap);
-  if (trans->orderdata)
-    transaction_free_orderdata(trans);
-  free(trans);
-}
-
diff --git a/libsolv-0.6.15/src/transaction.h b/libsolv-0.6.15/src/transaction.h
deleted file mode 100644 (file)
index c840838..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * transaction.h
- *
- */
-
-#ifndef LIBSOLV_TRANSACTION_H
-#define LIBSOLV_TRANSACTION_H
-
-#include "pooltypes.h"
-#include "queue.h"
-#include "bitmap.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct _Pool;
-struct _DUChanges;
-struct _TransactionOrderdata;
-
-typedef struct _Transaction {
-  struct _Pool *pool;          /* back pointer to pool */
-
-  Queue steps;                 /* the transaction steps */
-
-#ifdef LIBSOLV_INTERNAL
-  Queue transaction_info;
-  Id *transaction_installed;
-  Map transactsmap;
-  Map multiversionmap;
-
-  struct _TransactionOrderdata *orderdata;
-#endif
-
-} Transaction;
-
-
-/* step types */
-#define SOLVER_TRANSACTION_IGNORE              0x00
-
-#define SOLVER_TRANSACTION_ERASE               0x10
-#define SOLVER_TRANSACTION_REINSTALLED         0x11
-#define SOLVER_TRANSACTION_DOWNGRADED          0x12
-#define SOLVER_TRANSACTION_CHANGED             0x13
-#define SOLVER_TRANSACTION_UPGRADED            0x14
-#define SOLVER_TRANSACTION_OBSOLETED           0x15
-
-#define SOLVER_TRANSACTION_INSTALL             0x20
-#define SOLVER_TRANSACTION_REINSTALL           0x21
-#define SOLVER_TRANSACTION_DOWNGRADE           0x22
-#define SOLVER_TRANSACTION_CHANGE              0x23
-#define SOLVER_TRANSACTION_UPGRADE             0x24
-#define SOLVER_TRANSACTION_OBSOLETES           0x25
-
-#define SOLVER_TRANSACTION_MULTIINSTALL                0x30
-#define SOLVER_TRANSACTION_MULTIREINSTALL      0x31
-
-#define SOLVER_TRANSACTION_MAXTYPE             0x3f
-
-/* modes */
-#define SOLVER_TRANSACTION_SHOW_ACTIVE         (1 << 0)
-#define SOLVER_TRANSACTION_SHOW_ALL            (1 << 1)
-#define SOLVER_TRANSACTION_SHOW_OBSOLETES      (1 << 2)
-#define SOLVER_TRANSACTION_SHOW_MULTIINSTALL   (1 << 3)
-#define SOLVER_TRANSACTION_CHANGE_IS_REINSTALL (1 << 4)
-#define SOLVER_TRANSACTION_MERGE_VENDORCHANGES (1 << 5)
-#define SOLVER_TRANSACTION_MERGE_ARCHCHANGES   (1 << 6)
-
-#define SOLVER_TRANSACTION_RPM_ONLY            (1 << 7)
-
-#define SOLVER_TRANSACTION_KEEP_PSEUDO         (1 << 8)
-
-#define SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE  (1 << 9)
-
-/* extra classifications */
-#define SOLVER_TRANSACTION_ARCHCHANGE          0x100
-#define SOLVER_TRANSACTION_VENDORCHANGE                0x101
-
-/* order flags */
-#define SOLVER_TRANSACTION_KEEP_ORDERDATA      (1 << 0)
-#define SOLVER_TRANSACTION_KEEP_ORDERCYCLES    (1 << 1)
-
-/* cycle severities */
-#define SOLVER_ORDERCYCLE_HARMLESS             0
-#define SOLVER_ORDERCYCLE_NORMAL               1
-#define SOLVER_ORDERCYCLE_CRITICAL             2
-
-extern Transaction *transaction_create(struct _Pool *pool);
-extern Transaction *transaction_create_decisionq(struct _Pool *pool, Queue *decisionq, Map *multiversionmap);
-extern Transaction *transaction_create_clone(Transaction *srctrans);
-extern void transaction_free(Transaction *trans);
-
-/* if p is installed, returns with pkg(s) obsolete p */
-/* if p is not installed, returns with pkg(s) we obsolete */
-extern Id   transaction_obs_pkg(Transaction *trans, Id p);
-extern void transaction_all_obs_pkgs(Transaction *trans, Id p, Queue *pkgs);
-
-/* return step type of a transaction element */
-extern Id   transaction_type(Transaction *trans, Id p, int mode);
-
-/* return sorted collection of all step types */
-/* classify_pkgs can be used to return all packages of a type */
-extern void transaction_classify(Transaction *trans, int mode, Queue *classes);
-extern void transaction_classify_pkgs(Transaction *trans, int mode, Id type, Id from, Id to, Queue *pkgs);
-
-/* return all packages that will be installed after the transaction is run*/
-/* The new packages are put at the head of the queue, the number of new
-   packages is returned */
-extern int transaction_installedresult(Transaction *trans, Queue *installedq);
-
-int transaction_calc_installsizechange(Transaction *trans);
-void transaction_calc_duchanges(Transaction *trans, struct _DUChanges *mps, int nmps);
-
-
-
-/* order a transaction */
-extern void transaction_order(Transaction *trans, int flags);
-
-/* roll your own order funcion:
- * add pkgs free for installation to queue choices after chosen was
- * installed. start with chosen = 0
- * needs an ordered transaction created with SOLVER_TRANSACTION_KEEP_ORDERDATA */
-extern int  transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices);
-/* add obsoleted packages into transaction steps */
-extern void transaction_add_obsoleted(Transaction *trans);
-
-/* debug function, report problems found in the order */
-extern void transaction_check_order(Transaction *trans);
-
-/* order cycle introspection */
-extern void transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity);
-extern int transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q);
-
-extern void transaction_free_orderdata(Transaction *trans);
-extern void transaction_clone_orderdata(Transaction *trans, Transaction *srctrans);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libsolv-0.6.15/src/util.c b/libsolv-0.6.15/src/util.c
deleted file mode 100644 (file)
index d611297..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-
-#include "util.h"
-
-void
-solv_oom(size_t num, size_t len)
-{
-  if (num)
-    fprintf(stderr, "Out of memory allocating %zu*%zu bytes!\n", num, len);
-  else
-    fprintf(stderr, "Out of memory allocating %zu bytes!\n", len);
-  abort();
-  exit(1);
-}
-
-void *
-solv_malloc(size_t len)
-{
-  void *r = malloc(len ? len : 1);
-  if (!r)
-    solv_oom(0, len);
-  return r;
-}
-
-void *
-solv_malloc2(size_t num, size_t len)
-{
-  if (len && (num * len) / len != num)
-    solv_oom(num, len);
-  return solv_malloc(num * len);
-}
-
-void *
-solv_realloc(void *old, size_t len)
-{
-  if (old == 0)
-    old = malloc(len ? len : 1);
-  else
-    old = realloc(old, len ? len : 1);
-  if (!old)
-    solv_oom(0, len);
-  return old;
-}
-
-void *
-solv_realloc2(void *old, size_t num, size_t len)
-{
-  if (len && (num * len) / len != num)
-    solv_oom(num, len);
-  return solv_realloc(old, num * len);
-}
-
-void *
-solv_calloc(size_t num, size_t len)
-{
-  void *r;
-  if (num == 0 || len == 0)
-    r = malloc(1);
-  else
-    r = calloc(num, len);
-  if (!r)
-    solv_oom(num, len);
-  return r;
-}
-
-/* this was solv_realloc2(old, len, size), but we now overshoot
- * for huge len sizes */
-void *
-solv_extend_realloc(void *old, size_t len, size_t size, size_t block)
-{
-  size_t xblock = (block + 1) << 5;
-  len = (len + block) & ~block;
-  if (len >= xblock && xblock)
-    {
-      xblock <<= 1;
-      while (len >= xblock && xblock)
-       xblock <<= 1;
-      if (xblock)
-       {
-         size_t nlen;
-          xblock = (xblock >> 5) - 1;
-         nlen = (len + xblock) & ~xblock;
-         if (nlen > len)
-           len = nlen;
-       }
-    }
-  return solv_realloc2(old, len, size);
-}
-
-void *
-solv_free(void *mem)
-{
-  if (mem)
-    free(mem);
-  return 0;
-}
-
-char *
-solv_strdup(const char *s)
-{
-  char *r;
-  if (!s)
-    return 0;
-  r = strdup(s);
-  if (!r)
-    solv_oom(0, strlen(s));
-  return r;
-}
-
-unsigned int
-solv_timems(unsigned int subtract)
-{
-  struct timeval tv;
-  unsigned int r;
-
-  if (gettimeofday(&tv, 0))
-    return 0;
-  r = (((unsigned int)tv.tv_sec >> 16) * 1000) << 16;
-  r += ((unsigned int)tv.tv_sec & 0xffff) * 1000;
-  r += (unsigned int)tv.tv_usec / 1000;
-  return r - subtract;
-}
-
-/* bsd's qsort_r has different arguments, so we define our
-   own version in case we need to do some clever mapping
-
-   see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html
- */
-#if defined(__GLIBC__) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R))
-
-void
-solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
-{
-# if defined(HAVE_QSORT_R)
-  qsort_r(base, nmemb, size, compar, compard);
-# else
-  /* backported for SLE10-SP2 */
-  __qsort_r(base, nmemb, size, compar, compard);
-# endif
-
-}
-
-#elif defined(HAVE_QSORT_R) /* not glibc, but has qsort_r() */
-
-struct solv_sort_data {
-  int (*compar)(const void *, const void *, void *);
-  void *compard;
-};
-
-static int
-solv_sort_helper(void *compard, const void *a, const void *b)
-{
-  struct solv_sort_data *d = compard;
-  return (*d->compar)(a, b, d->compard);
-}
-
-void
-solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
-{
-  struct solv_sort_data d;
-  d.compar = compar;
-  d.compard = compard;
-  qsort_r(base, nmemb, size, &d, solv_sort_helper);
-}
-
-#else /* not glibc and no qsort_r() */
-/* use own version of qsort if none available */
-#include "qsort_r.c"
-#endif
-
-char *
-solv_dupjoin(const char *str1, const char *str2, const char *str3)
-{
-  int l1, l2, l3;
-  char *s, *str;
-  l1 = str1 ? strlen(str1) : 0;
-  l2 = str2 ? strlen(str2) : 0;
-  l3 = str3 ? strlen(str3) : 0;
-  s = str = solv_malloc(l1 + l2 + l3 + 1);
-  if (l1)
-    {
-      strcpy(s, str1);
-      s += l1;
-    }
-  if (l2)
-    {
-      strcpy(s, str2);
-      s += l2;
-    }
-  if (l3)
-    {
-      strcpy(s, str3);
-      s += l3;
-    }
-  *s = 0;
-  return str;
-}
-
-char *
-solv_dupappend(const char *str1, const char *str2, const char *str3)
-{
-  char *str = solv_dupjoin(str1, str2, str3);
-  solv_free((void *)str1);
-  return str;
-}
-
-int
-solv_hex2bin(const char **strp, unsigned char *buf, int bufl)
-{
-  const char *str = *strp;
-  int i;
-
-  for (i = 0; i < bufl; i++)
-    {
-      int c = *str;
-      int d;
-      if (c >= '0' && c <= '9')
-        d = c - '0';
-      else if (c >= 'a' && c <= 'f')
-        d = c - ('a' - 10);
-      else if (c >= 'A' && c <= 'F')
-        d = c - ('A' - 10);
-      else
-       break;
-      c = *++str;
-      d <<= 4;
-      if (c >= '0' && c <= '9')
-        d |= c - '0';
-      else if (c >= 'a' && c <= 'f')
-        d |= c - ('a' - 10);
-      else if (c >= 'A' && c <= 'F')
-        d |= c - ('A' - 10);
-      else
-       break;
-      buf[i] = d;
-      ++str;
-    }
-  *strp = str;
-  return i;
-}
-
-char *
-solv_bin2hex(const unsigned char *buf, int l, char *str)
-{
-  int i;
-  for (i = 0; i < l; i++, buf++)
-    {
-      int c = *buf >> 4;
-      *str++ = c < 10 ? c + '0' : c + ('a' - 10);
-      c = *buf & 15;
-      *str++ = c < 10 ? c + '0' : c + ('a' - 10);
-    }
-  *str = 0;
-  return str;
-}
-
-size_t
-solv_validutf8(const char *buf)
-{
-  const unsigned char *p;
-  int x;
-
-  for (p = (const unsigned char *)buf; (x = *p) != 0; p++)
-    {
-      if (x < 0x80)
-       continue;
-      if (x < 0xc0)
-       break;
-      if (x < 0xe0)
-       {
-         /* one byte to follow */
-         if ((p[1] & 0xc0) != 0x80)
-           break;
-         if ((x & 0x1e) == 0)
-           break;      /* not minimal */
-         p += 1;
-         continue;
-       }
-      if (x < 0xf0)
-       {
-         /* two bytes to follow */
-         if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)
-           break;
-         if ((x & 0x0f) == 0 && (p[1] & 0x20) == 0)
-           break;      /* not minimal */
-         if (x == 0xed && (p[1] & 0x20) != 0)
-           break;      /* d800-dfff surrogate */
-         if (x == 0xef && p[1] == 0xbf && (p[2] == 0xbe || p[2] == 0xbf))
-           break;      /* fffe or ffff */
-         p += 2;
-         continue;
-       }
-      if (x < 0xf8)
-       {
-         /* three bytes to follow */
-         if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)
-           break;
-         if ((x & 0x07) == 0 && (p[1] & 0x30) == 0)
-           break;      /* not minimal */
-         if ((x & 0x07) > 4 || ((x & 0x07) == 4 && (p[1] & 0x30) != 0))
-           break;      /* above 0x10ffff */
-         p += 3;
-         continue;
-       }
-      break;   /* maybe valid utf8, but above 0x10ffff */
-    }
-  return (const char *)p - buf;
-}
-
-char *
-solv_latin1toutf8(const char *buf)
-{
-  int l = 1;
-  const char *p;
-  char *r, *rp;
-
-  for (p = buf; *p; p++)
-    if ((*(const unsigned char *)p & 128) != 0)
-      l++;
-  r = rp = solv_malloc(p - buf + l);
-  for (p = buf; *p; p++)
-    {
-      if ((*(const unsigned char *)p & 128) != 0)
-       {
-         *rp++ = *(const unsigned char *)p & 64 ? 0xc3 : 0xc2;
-         *rp++ = *p & 0xbf;
-       }
-      else
-        *rp++ = *p;
-    }
-  *rp = 0;
-  return r;
-}
-
-char *
-solv_replacebadutf8(const char *buf, int replchar)
-{
-  size_t l, nl;
-  const char *p;
-  char *r = 0, *rp = 0;
-  int repllen, replin;
-
-  if (replchar < 0 || replchar > 0x10ffff)
-    replchar = 0xfffd;
-  if (!replchar)
-    repllen = replin = 0;
-  else if (replchar < 0x80)
-    {
-      repllen = 1;
-      replin = (replchar & 0x40) | 0x80;
-    }
-  else if (replchar < 0x800)
-    {
-      repllen = 2;
-      replin = 0x40;
-    }
-  else if (replchar < 0x10000)
-    {
-      repllen = 3;
-      replin = 0x60;
-    }
-  else
-    {
-      repllen = 4;
-      replin = 0x70;
-    }
-  for (;;)
-    {
-      for (p = buf, nl = 0; *p; )
-       {
-         l = solv_validutf8(p);
-         if (rp && l)
-           {
-             memcpy(rp, p, l);
-             rp += l;
-           }
-         nl += l;
-         p += l;
-         if (!*p)
-           break;
-         /* found a bad char, replace with replchar */
-         if (rp && replchar)
-           {
-             switch (repllen)
-               {
-               case 4:
-                 *rp++ = (replchar >> 18 & 0x3f) | 0x80;
-               case 3:
-                 *rp++ = (replchar >> 12 & 0x3f) | 0x80;
-               case 2:
-                 *rp++ = (replchar >> 6  & 0x3f) | 0x80;
-               default:
-                 *rp++ = (replchar       & 0x3f) | 0x80;
-               }
-             rp[-repllen] ^= replin;
-           }
-         nl += repllen;
-         p++;
-         while ((*(const unsigned char *)p & 0xc0) == 0x80)
-           p++;
-       }
-      if (rp)
-       break;
-      r = rp = solv_malloc(nl + 1);
-    }
-  *rp = 0;
-  return r;
-}
-
diff --git a/libsolv-0.6.15/src/util.h b/libsolv-0.6.15/src/util.h
deleted file mode 100644 (file)
index 5f7a93a..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * util.h
- *
- */
-
-#ifndef LIBSOLV_UTIL_H
-#define LIBSOLV_UTIL_H
-
-#include <stddef.h>
-#include <string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * malloc
- * exits with error message on error
- */
-extern void *solv_malloc(size_t);
-extern void *solv_malloc2(size_t, size_t);
-extern void *solv_calloc(size_t, size_t);
-extern void *solv_realloc(void *, size_t);
-extern void *solv_realloc2(void *, size_t, size_t);
-extern void *solv_extend_realloc(void *, size_t, size_t, size_t);
-extern void *solv_free(void *);
-extern char *solv_strdup(const char *);
-extern void solv_oom(size_t, size_t);
-extern unsigned int solv_timems(unsigned int subtract);
-extern void solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard);
-extern char *solv_dupjoin(const char *str1, const char *str2, const char *str3);
-extern char *solv_dupappend(const char *str1, const char *str2, const char *str3);
-extern int solv_hex2bin(const char **strp, unsigned char *buf, int bufl);
-extern char *solv_bin2hex(const unsigned char *buf, int l, char *str);
-extern size_t solv_validutf8(const char *buf);
-extern char *solv_latin1toutf8(const char *buf);
-extern char *solv_replacebadutf8(const char *buf, int replchar);
-
-
-static inline void *solv_extend(void *buf, size_t len, size_t nmemb, size_t size, size_t block)
-{
-  if (nmemb == 1)
-    {
-      if ((len & block) == 0)
-       buf = solv_extend_realloc(buf, len + 1, size, block);
-    }
-  else
-    {
-      if (((len - 1) | block) != ((len + nmemb - 1) | block))
-       buf = solv_extend_realloc(buf, len + nmemb, size, block);
-    }
-  return buf;
-}
-
-/**
- * extend an array by reallocation and zero's the new section
- * buf old pointer
- * len current size
- * nmbemb number of elements to add
- * size size of each element
- * block block size used to allocate the elements
- */
-static inline void *solv_zextend(void *buf, size_t len, size_t nmemb, size_t size, size_t block)
-{
-  buf = solv_extend(buf, len, nmemb, size, block);
-  memset((char *)buf + len * size, 0, nmemb * size);
-  return buf;
-}
-
-static inline void *solv_extend_resize(void *buf, size_t len, size_t size, size_t block)
-{
-  if (len)
-    buf = solv_extend_realloc(buf, len, size, block);
-  return buf;
-}
-
-static inline void *solv_calloc_block(size_t len, size_t size, size_t block)
-{
-  void *buf;
-  if (!len)
-    return 0;
-  buf = solv_extend_realloc((void *)0, len, size, block);
-  memset(buf, 0, ((len + block) & ~block) * size);
-  return buf;
-}
-
-static inline void *solv_memdup(void *buf, size_t len)
-{
-  void *newbuf;
-  if (!buf)
-    return 0;
-  newbuf = solv_malloc(len);
-  if (len)
-    memcpy(newbuf, buf, len);
-  return newbuf;
-}
-
-static inline void *solv_memdup2(void *buf, size_t num, size_t len)
-{
-  void *newbuf;
-  if (!buf)
-    return 0;
-  newbuf = solv_malloc2(num, len);
-  if (num)
-    memcpy(newbuf, buf, num * len);
-  return newbuf;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBSOLV_UTIL_H */
diff --git a/libsolv-0.6.15/test/CMakeLists.txt b/libsolv-0.6.15/test/CMakeLists.txt
deleted file mode 100644 (file)
index 92a5e7a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-FOREACH(tcdir testcases libsolv-zypptestcases)
-    IF(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}")
-        FILE(GLOB dirs "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}/[_a-zA-Z0-9]*")
-        FOREACH(dir ${dirs})
-           IF(IS_DIRECTORY ${dir})
-               FILE(RELATIVE_PATH myname "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}" ${dir})
-               ADD_TEST(${myname} ${CMAKE_CURRENT_SOURCE_DIR}/runtestcases ${CMAKE_BINARY_DIR}/tools/testsolv ${dir})
-           ENDIF(IS_DIRECTORY ${dir})
-        ENDFOREACH(dir)
-    ENDIF(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}")
-ENDFOREACH(tcdir)
diff --git a/libsolv-0.6.15/test/runtestcases b/libsolv-0.6.15/test/runtestcases
deleted file mode 100755 (executable)
index 3d73663..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-cmd=$1
-dir=$2
-
-if test -z "$cmd" -o -z "$dir"; then
-  echo "Usage: runtestcases <cmd> <dir>";
-  exit 1
-fi
-
-ex=0
-for tc in $(find $dir -name \*.t) ; do
-  $cmd $tc >/dev/null
-  tex=$?
-  tcn="${tc#$dir/} .................................................."
-  tcn="${tcn:0:50}"
-  if test "$tex" -eq 0 ; then
-    echo "$tcn   Passed"
-  elif test "$tex" -eq 77 ; then
-    echo "$tcn   Skipped"
-  else
-    echo "$tcn***Failed"
-    ex=1
-  fi
-done
-exit $ex
diff --git a/libsolv-0.6.15/test/testcases/choose/default.t b/libsolv-0.6.15/test/testcases/choose/default.t
deleted file mode 100644 (file)
index bb5b9f4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: X 1 1 noarch
-#>=Req: Y
-#>=Pkg: B 1 1 noarch
-#>=Prv: Y
-#>=Pkg: A 1 1 noarch
-#>=Prv: Y
-system i686 rpm system
-job install name X
-result transaction,problems <inline>
-#>install A-1-1.noarch@test
-#>install X-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/choose/enhanced.t b/libsolv-0.6.15/test/testcases/choose/enhanced.t
deleted file mode 100644 (file)
index da6cfd5..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: X 1 1 noarch
-#>=Req: Y
-#>=Pkg: B 1 1 noarch
-#>=Prv: Y
-#>=Enh: X
-#>=Pkg: A 1 1 noarch
-#>=Prv: Y
-system i686 rpm system
-job install name X
-result transaction,problems <inline>
-#>install B-1-1.noarch@test
-#>install X-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/choose/oldversion.t b/libsolv-0.6.15/test/testcases/choose/oldversion.t
deleted file mode 100644 (file)
index d83e2b6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: X 1 1 noarch
-#>=Req: Y
-#>=Pkg: B 1 1 noarch
-#>=Prv: Y
-#>=Pkg: C 1 1 noarch
-#>=Prv: Y
-#>=Pkg: A 1 1 noarch
-#>=Prv: Y
-#>=Pkg: A 2 1 noarch
-system i686 rpm system
-job install name X
-result transaction,problems <inline>
-#>install B-1-1.noarch@test
-#>install X-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/choose/suggested.t b/libsolv-0.6.15/test/testcases/choose/suggested.t
deleted file mode 100644 (file)
index cad4742..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: X 1 1 noarch
-#>=Req: Y
-#>=Sug: B
-#>=Pkg: B 1 1 noarch
-#>=Prv: Y
-#>=Pkg: A 1 1 noarch
-#>=Prv: Y
-system i686 rpm system
-job install name X
-result transaction,problems <inline>
-#>install B-1-1.noarch@test
-#>install X-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/choose/versioned.t b/libsolv-0.6.15/test/testcases/choose/versioned.t
deleted file mode 100644 (file)
index d5089c8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: X 1 1 noarch
-#>=Req: Y
-#>=Pkg: B 1 1 noarch
-#>=Prv: Y = 2
-#>=Pkg: C 1 1 noarch
-#>=Prv: Y = 1.1
-#>=Pkg: A 1 1 noarch
-#>=Prv: Y = 1
-system i686 rpm system
-job install name X
-result transaction,problems <inline>
-#>install B-1-1.noarch@test
-#>install X-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/choose/versioned2.t b/libsolv-0.6.15/test/testcases/choose/versioned2.t
deleted file mode 100644 (file)
index 99c5712..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: X 1 1 noarch
-#>=Req: Y
-#>=Pkg: B 1 1 noarch
-#>=Prv: Y < 2
-#>=Pkg: C 1 1 noarch
-#>=Prv: Y <= 2
-#>=Pkg: A 1 1 noarch
-#>=Prv: Y = 1
-system i686 rpm system
-job install name X
-result transaction,problems <inline>
-#>install C-1-1.noarch@test
-#>install X-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_dup.t b/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_dup.t
deleted file mode 100644 (file)
index 7002434..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Req: B1
-#>=Pkg: B1 1 1 noarch
-repo test 0 testtags <inline>
-#>=Pkg: A 1 2 noarch
-#>=Req: B1
-#>=Pkg: A 2 1 noarch
-#>=Req: B2 = 1
-#>=Pkg: B1 1 1 noarch
-#>=Pkg: B2 1 1 noarch
-system i686 rpm system
-
-# check untargeted
-job distupgrade name A [cleandeps]
-result transaction,problems <inline>
-#>erase B1-1-1.noarch@system
-#>install B2-1-1.noarch@test
-#>upgrade A-1-1.noarch@system A-2-1.noarch@test
-
-# check targeted
-nextjob
-job distupgrade name A = 2 [cleandeps]
-result transaction,problems <inline>
-#>erase B1-1-1.noarch@system
-#>install B2-1-1.noarch@test
-#>upgrade A-1-1.noarch@system A-2-1.noarch@test
-
-# check targeted to 1-2
-nextjob
-job distupgrade name A = 1-2 [cleandeps]
-result transaction,problems <inline>
-#>upgrade A-1-1.noarch@system A-1-2.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_in.t b/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_in.t
deleted file mode 100644 (file)
index 3edacb5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Req: B1
-#>=Pkg: B1 1 1 noarch
-repo test 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Req: B2 = 1
-#>=Pkg: B1 1 1 noarch
-#>=Pkg: B2 1 1 noarch
-system i686 rpm system
-job install name A = 2 [cleandeps]
-result transaction,problems <inline>
-#>erase B1-1-1.noarch@system
-#>install B2-1-1.noarch@test
-#>upgrade A-1-1.noarch@system A-2-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_up.t b/libsolv-0.6.15/test/testcases/cleandeps/cleandeps_up.t
deleted file mode 100644 (file)
index 9bb26d2..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Req: B1
-#>=Pkg: B1 1 1 noarch
-repo test 0 testtags <inline>
-#>=Pkg: A 1 2 noarch
-#>=Req: B1
-#>=Pkg: A 2 1 noarch
-#>=Req: B2 = 1
-#>=Pkg: B1 1 1 noarch
-#>=Pkg: B2 1 1 noarch
-system i686 rpm system
-
-# check untargeted
-job update name A [cleandeps]
-result transaction,problems <inline>
-#>erase B1-1-1.noarch@system
-#>install B2-1-1.noarch@test
-#>upgrade A-1-1.noarch@system A-2-1.noarch@test
-
-# check targeted
-nextjob
-job update name A = 2 [cleandeps]
-result transaction,problems <inline>
-#>erase B1-1-1.noarch@system
-#>install B2-1-1.noarch@test
-#>upgrade A-1-1.noarch@system A-2-1.noarch@test
-
-# check targeted to 1-2
-nextjob
-job update name A = 1-2 [cleandeps]
-result transaction,problems <inline>
-#>upgrade A-1-1.noarch@system A-1-2.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/cleandeps/mistake.t b/libsolv-0.6.15/test/testcases/cleandeps/mistake.t
deleted file mode 100644 (file)
index 48099a8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Req: B
-#>=Pkg: B 2 1 noarch
-repo test 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Req: B = 1-1
-#>=Pkg: B 1 1 noarch
-system unset deb system
-job install name A = 2-1 [cleandeps]
-result transaction,problems <inline>
-#>problem b5abcb9c info package A-2-1.noarch requires B = 1-1, but none of the providers can be installed
-#>problem b5abcb9c solution 3b3a37c0 deljob install name A = 2-1 [cleandeps]
-#>problem b5abcb9c solution 3c170283 replace B-2-1.noarch@system B-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_allowuninstall b/libsolv-0.6.15/test/testcases/distupgrade/dup_allowuninstall
deleted file mode 100644 (file)
index 86a8af9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 i686
-#>=Pkg: b 2 1 i686
-repo available 0 testtags <inline>
-#>=Pkg: a 2 1 i586
-#>=Con: b = 1-1
-#>=Pkg: b 1 1 i586
-system i686 * system
-solverflags !dupallowarchchange allowuninstall
-job distupgrade all packages
-result transaction,problems <inline>
-#>erase b-2-1.i686@system
-#>upgrade a-1-1.i686@system a-2-1.i586@available
diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion1 b/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion1
deleted file mode 100644 (file)
index 326de7a..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-# test dup with multiversion packages
-#
-# part 1: simple update
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 i686
-repo available 0 testtags <inline>
-#>=Pkg: a 2 1 i686
-system i686 * system
-
-job multiversion name a
-job distupgrade all packages
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-nextjob
-
-job multiversion name a
-job distupgrade repo available
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-### same with keeporphans
-
-nextjob
-
-solverflags keeporphans
-job multiversion name a
-job distupgrade all packages
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-nextjob
-
-solverflags keeporphans
-job multiversion name a
-job distupgrade repo available
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-### same with allowuninstall
-
-nextjob
-
-solverflags allowuninstall
-job multiversion name a
-job distupgrade all packages
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-nextjob
-
-solverflags allowuninstall
-job multiversion name a
-job distupgrade repo available
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-### same with allowuninstall and keeporphans
-
-nextjob
-
-solverflags allowuninstall keeporphans
-job multiversion name a
-job distupgrade all packages
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-nextjob
-
-solverflags allowuninstall keeporphans
-job multiversion name a
-job distupgrade repo available
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-
-
-
diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2 b/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion2
deleted file mode 100644 (file)
index 18909eb..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-# test dup with multiversion packages
-# same as with dup_multiversion1, but we can't keep the orphan
-
-#
-# part 1: simple update
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 i686
-#>=Pkg: b 1 1 i686
-repo available 0 testtags <inline>
-#>=Pkg: a 2 1 i686
-#>=Pkg: b 2 1 i686
-#>=Con: a = 1-1
-system i686 * system
-
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-#>install a-2-1.i686@available
-#>upgrade b-1-1.i686@system b-2-1.i686@available
-
-nextjob
-
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-#>install a-2-1.i686@available
-#>upgrade b-1-1.i686@system b-2-1.i686@available
-
-
-### same with keeporphans, this will result in problems as we cannot keep the orphan
-
-nextjob
-
-solverflags keeporphans
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-#>problem 4d4de423 info package b-2-1.i686 conflicts with a = 1-1 provided by a-1-1.i686
-#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
-#>problem 4d4de423 solution 2cf4745c replace a-1-1.i686@system a-2-1.i686@available
-#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
-#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
-
-nextjob
-
-solverflags keeporphans
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>install a-2-1.i686@available
-#>problem 4d4de423 info package b-2-1.i686 conflicts with a = 1-1 provided by a-1-1.i686
-#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
-#>problem 4d4de423 solution 2cf4745c replace a-1-1.i686@system a-2-1.i686@available
-#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
-#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
-
-### same with allowuninstall
-
-nextjob
-
-solverflags allowuninstall
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-#>install a-2-1.i686@available
-#>upgrade b-1-1.i686@system b-2-1.i686@available
-
-nextjob
-
-solverflags allowuninstall
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-#>install a-2-1.i686@available
-#>upgrade b-1-1.i686@system b-2-1.i686@available
-
-
-### same with allowuninstall and keeporphans
-
-nextjob
-
-solverflags allowuninstall keeporphans
-job multiversion name a
-job distupgrade all packages
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>erase b-1-1.i686@system
-#>install a-2-1.i686@available
-
-
-nextjob
-
-solverflags allowuninstall keeporphans
-job multiversion name a
-job distupgrade repo available
-# a-1-1 is treated as orphaned and stays behind
-result transaction,problems <inline>
-#>erase b-1-1.i686@system
-#>install a-2-1.i686@available
-
-
diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3 b/libsolv-0.6.15/test/testcases/distupgrade/dup_multiversion3
deleted file mode 100644 (file)
index 8be3190..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-# test dup with multiversion packages where we cannot install the
-# target. Should give problems except for allowuninstall.
-#
-# part 1: simple update
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 i686
-repo available 0 testtags <inline>
-#>=Pkg: a 2 1 i686
-#>=Req: c
-system i686 * system
-
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>problem 251f1f35 info nothing provides c needed by a-2-1.i686
-#>problem 251f1f35 solution 2f2d254c allow a-1-1.i686@system
-
-nextjob
-
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-#>problem 251f1f35 info nothing provides c needed by a-2-1.i686
-#>problem 251f1f35 solution 2f2d254c allow a-1-1.i686@system
-
-### same with keeporphans
-
-nextjob
-
-solverflags keeporphans
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>problem 771581fd info nothing provides c needed by a-2-1.i686
-#>problem 771581fd solution 179b72ed allow a-1-1.i686@system
-#>problem 771581fd solution 2cf4745c erase a-1-1.i686@system
-
-nextjob
-
-solverflags keeporphans
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>problem 771581fd info nothing provides c needed by a-2-1.i686
-#>problem 771581fd solution 179b72ed allow a-1-1.i686@system
-#>problem 771581fd solution 2cf4745c erase a-1-1.i686@system
-
-### same with allowuninstall
-
-nextjob
-
-solverflags allowuninstall
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-
-
-nextjob
-
-solverflags allowuninstall
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-
-
-### same with allowuninstall and keeporphans
-
-nextjob
-
-solverflags allowuninstall keeporphans
-job multiversion name a
-job distupgrade all packages
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-
-
-nextjob
-
-solverflags allowuninstall keeporphans
-job multiversion name a
-job distupgrade repo available
-result transaction,problems <inline>
-#>erase a-1-1.i686@system
-
-
diff --git a/libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange b/libsolv-0.6.15/test/testcases/distupgrade/dup_noarchchange
deleted file mode 100644 (file)
index f500d9b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 i686
-#>=Pkg: b 1 1 i686
-repo available 0 testtags <inline>
-#>=Pkg: a 2 1 i586
-#>=Pkg: b 2 1 i586
-#>=Pkg: b 2 1 i686
-system i686 * system
-solverflags !dupallowarchchange
-job distupgrade all packages
-result transaction,problems <inline>
-#>problem c43b1300 info problem with installed package a-1-1.i686
-#>problem c43b1300 solution c43b1300 replace a-1-1.i686@system a-2-1.i586@available
-#>upgrade a-1-1.i686@system a-2-1.i586@available
-#>upgrade b-1-1.i686@system b-2-1.i686@available
diff --git a/libsolv-0.6.15/test/testcases/evrcmp/conflicts.repo b/libsolv-0.6.15/test/testcases/evrcmp/conflicts.repo
deleted file mode 100644 (file)
index c979cb0..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-=Ver: 2.0
-#
-=Pkg: CEQ2 1 1 noarch
-=Con: B = 2
-=Pkg: CEQ22 1 1 noarch
-=Con: B = 2-2
-#
-=Pkg: CLT2 1 1 noarch
-=Con: B < 2
-=Pkg: CLT22 1 1 noarch
-=Con: B < 2-2
-#
-=Pkg: CGT2 1 1 noarch
-=Con: B > 2
-=Pkg: CGT22 1 1 noarch
-=Con: B > 2-2
-#
-=Pkg: CLE2 1 1 noarch
-=Con: B <= 2
-=Pkg: CLE22 1 1 noarch
-=Con: B <= 2-2
-#
-=Pkg: CGE2 1 1 noarch
-=Con: B >= 2
-=Pkg: CGE22 1 1 noarch
-=Con: B >= 2-2
diff --git a/libsolv-0.6.15/test/testcases/evrcmp/system.repo b/libsolv-0.6.15/test/testcases/evrcmp/system.repo
deleted file mode 100644 (file)
index 233b6b9..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-=Ver: 2.0
-#
-=Pkg: AEQ1 1 1 noarch
-=Prv: B = 1
-=Pkg: AEQ11 1 1 noarch
-=Prv: B = 1-1
-=Pkg: AEQ12 1 1 noarch
-=Prv: B = 1-2
-=Pkg: AEQ13 1 1 noarch
-=Prv: B = 1-3
-=Pkg: AEQ2 1 1 noarch
-=Prv: B = 2
-=Pkg: AEQ21 1 1 noarch
-=Prv: B = 2-1
-=Pkg: AEQ22 1 1 noarch
-=Prv: B = 2-2
-=Pkg: AEQ23 1 1 noarch
-=Prv: B = 2-3
-=Pkg: AEQ3 1 1 noarch
-=Prv: B = 3
-=Pkg: AEQ31 1 1 noarch
-=Prv: B = 3-1
-=Pkg: AEQ32 1 1 noarch
-=Prv: B = 3-2
-=Pkg: AEQ33 1 1 noarch
-=Prv: B = 3-3
-#
-=Pkg: ALT1 1 1 noarch
-=Prv: B < 1
-=Pkg: ALT11 1 1 noarch
-=Prv: B < 1-1
-=Pkg: ALT12 1 1 noarch
-=Prv: B < 1-2
-=Pkg: ALT13 1 1 noarch
-=Prv: B < 1-3
-=Pkg: ALT2 1 1 noarch
-=Prv: B < 2
-=Pkg: ALT21 1 1 noarch
-=Prv: B < 2-1
-=Pkg: ALT22 1 1 noarch
-=Prv: B < 2-2
-=Pkg: ALT23 1 1 noarch
-=Prv: B < 2-3
-=Pkg: ALT3 1 1 noarch
-=Prv: B < 3
-=Pkg: ALT31 1 1 noarch
-=Prv: B < 3-1
-=Pkg: ALT32 1 1 noarch
-=Prv: B < 3-2
-=Pkg: ALT33 1 1 noarch
-=Prv: B < 3-3
-#
-=Pkg: AGT1 1 1 noarch
-=Prv: B > 1
-=Pkg: AGT11 1 1 noarch
-=Prv: B > 1-1
-=Pkg: AGT12 1 1 noarch
-=Prv: B > 1-2
-=Pkg: AGT13 1 1 noarch
-=Prv: B > 1-3
-=Pkg: AGT2 1 1 noarch
-=Prv: B > 2
-=Pkg: AGT21 1 1 noarch
-=Prv: B > 2-1
-=Pkg: AGT22 1 1 noarch
-=Prv: B > 2-2
-=Pkg: AGT23 1 1 noarch
-=Prv: B > 2-3
-=Pkg: AGT3 1 1 noarch
-=Prv: B > 3
-=Pkg: AGT31 1 1 noarch
-=Prv: B > 3-1
-=Pkg: AGT32 1 1 noarch
-=Prv: B > 3-2
-=Pkg: AGT33 1 1 noarch
-=Prv: B > 3-3
-#
-=Pkg: ALE1 1 1 noarch
-=Prv: B <= 1
-=Pkg: ALE11 1 1 noarch
-=Prv: B <= 1-1
-=Pkg: ALE12 1 1 noarch
-=Prv: B <= 1-2
-=Pkg: ALE13 1 1 noarch
-=Prv: B <= 1-3
-=Pkg: ALE2 1 1 noarch
-=Prv: B <= 2
-=Pkg: ALE21 1 1 noarch
-=Prv: B <= 2-1
-=Pkg: ALE22 1 1 noarch
-=Prv: B <= 2-2
-=Pkg: ALE23 1 1 noarch
-=Prv: B <= 2-3
-=Pkg: ALE3 1 1 noarch
-=Prv: B <= 3
-=Pkg: ALE31 1 1 noarch
-=Prv: B <= 3-1
-=Pkg: ALE32 1 1 noarch
-=Prv: B <= 3-2
-=Pkg: ALE33 1 1 noarch
-=Prv: B <= 3-3
-#
-=Pkg: AGE1 1 1 noarch
-=Prv: B >= 1
-=Pkg: AGE11 1 1 noarch
-=Prv: B >= 1-1
-=Pkg: AGE12 1 1 noarch
-=Prv: B >= 1-2
-=Pkg: AGE13 1 1 noarch
-=Prv: B >= 1-3
-=Pkg: AGE2 1 1 noarch
-=Prv: B >= 2
-=Pkg: AGE21 1 1 noarch
-=Prv: B >= 2-1
-=Pkg: AGE22 1 1 noarch
-=Prv: B >= 2-2
-=Pkg: AGE23 1 1 noarch
-=Prv: B >= 2-3
-=Pkg: AGE3 1 1 noarch
-=Prv: B >= 3
-=Pkg: AGE31 1 1 noarch
-=Prv: B >= 3-1
-=Pkg: AGE32 1 1 noarch
-=Prv: B >= 3-2
-=Pkg: AGE33 1 1 noarch
-=Prv: B >= 3-3
-#
diff --git a/libsolv-0.6.15/test/testcases/evrcmp/testevr.t b/libsolv-0.6.15/test/testcases/evrcmp/testevr.t
deleted file mode 100644 (file)
index 842c63c..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-#
-# these tests check all dependency match combinations,
-# both with release present and missing
-#
-repo system 0 testtags system.repo
-repo c 0 testtags conflicts.repo
-system i686 rpm system
-solverflags allowuninstall
-job install name CEQ2
-result transaction,problems <inline>
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ21-1-1.noarch@system
-#>erase AEQ22-1-1.noarch@system
-#>erase AEQ23-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGE23-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase AGT22-1-1.noarch@system
-#>erase AGT23-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE21-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT21-1-1.noarch@system
-#>erase ALT22-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CEQ2-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CEQ22
-result transaction,problems <inline>
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ22-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CEQ22-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CLT2
-result transaction,problems <inline>
-#>erase AEQ1-1-1.noarch@system
-#>erase AEQ11-1-1.noarch@system
-#>erase AEQ12-1-1.noarch@system
-#>erase AEQ13-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase ALE1-1-1.noarch@system
-#>erase ALE11-1-1.noarch@system
-#>erase ALE12-1-1.noarch@system
-#>erase ALE13-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE21-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT1-1-1.noarch@system
-#>erase ALT11-1-1.noarch@system
-#>erase ALT12-1-1.noarch@system
-#>erase ALT13-1-1.noarch@system
-#>erase ALT2-1-1.noarch@system
-#>erase ALT21-1-1.noarch@system
-#>erase ALT22-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CLT2-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CLT22
-result transaction,problems <inline>
-#>erase AEQ1-1-1.noarch@system
-#>erase AEQ11-1-1.noarch@system
-#>erase AEQ12-1-1.noarch@system
-#>erase AEQ13-1-1.noarch@system
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ21-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase ALE1-1-1.noarch@system
-#>erase ALE11-1-1.noarch@system
-#>erase ALE12-1-1.noarch@system
-#>erase ALE13-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE21-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT1-1-1.noarch@system
-#>erase ALT11-1-1.noarch@system
-#>erase ALT12-1-1.noarch@system
-#>erase ALT13-1-1.noarch@system
-#>erase ALT2-1-1.noarch@system
-#>erase ALT21-1-1.noarch@system
-#>erase ALT22-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CLT22-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CGT2
-result transaction,problems <inline>
-#>erase AEQ3-1-1.noarch@system
-#>erase AEQ31-1-1.noarch@system
-#>erase AEQ32-1-1.noarch@system
-#>erase AEQ33-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGE23-1-1.noarch@system
-#>erase AGE3-1-1.noarch@system
-#>erase AGE31-1-1.noarch@system
-#>erase AGE32-1-1.noarch@system
-#>erase AGE33-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT2-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase AGT22-1-1.noarch@system
-#>erase AGT23-1-1.noarch@system
-#>erase AGT3-1-1.noarch@system
-#>erase AGT31-1-1.noarch@system
-#>erase AGT32-1-1.noarch@system
-#>erase AGT33-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CGT2-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CGT22
-result transaction,problems <inline>
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ23-1-1.noarch@system
-#>erase AEQ3-1-1.noarch@system
-#>erase AEQ31-1-1.noarch@system
-#>erase AEQ32-1-1.noarch@system
-#>erase AEQ33-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGE23-1-1.noarch@system
-#>erase AGE3-1-1.noarch@system
-#>erase AGE31-1-1.noarch@system
-#>erase AGE32-1-1.noarch@system
-#>erase AGE33-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT2-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase AGT22-1-1.noarch@system
-#>erase AGT23-1-1.noarch@system
-#>erase AGT3-1-1.noarch@system
-#>erase AGT31-1-1.noarch@system
-#>erase AGT32-1-1.noarch@system
-#>erase AGT33-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CGT22-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CLE2
-result transaction,problems <inline>
-#>erase AEQ1-1-1.noarch@system
-#>erase AEQ11-1-1.noarch@system
-#>erase AEQ12-1-1.noarch@system
-#>erase AEQ13-1-1.noarch@system
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ21-1-1.noarch@system
-#>erase AEQ22-1-1.noarch@system
-#>erase AEQ23-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGE23-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase AGT22-1-1.noarch@system
-#>erase AGT23-1-1.noarch@system
-#>erase ALE1-1-1.noarch@system
-#>erase ALE11-1-1.noarch@system
-#>erase ALE12-1-1.noarch@system
-#>erase ALE13-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE21-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT1-1-1.noarch@system
-#>erase ALT11-1-1.noarch@system
-#>erase ALT12-1-1.noarch@system
-#>erase ALT13-1-1.noarch@system
-#>erase ALT2-1-1.noarch@system
-#>erase ALT21-1-1.noarch@system
-#>erase ALT22-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CLE2-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CLE22
-result transaction,problems <inline>
-#>erase AEQ1-1-1.noarch@system
-#>erase AEQ11-1-1.noarch@system
-#>erase AEQ12-1-1.noarch@system
-#>erase AEQ13-1-1.noarch@system
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ21-1-1.noarch@system
-#>erase AEQ22-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase ALE1-1-1.noarch@system
-#>erase ALE11-1-1.noarch@system
-#>erase ALE12-1-1.noarch@system
-#>erase ALE13-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE21-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT1-1-1.noarch@system
-#>erase ALT11-1-1.noarch@system
-#>erase ALT12-1-1.noarch@system
-#>erase ALT13-1-1.noarch@system
-#>erase ALT2-1-1.noarch@system
-#>erase ALT21-1-1.noarch@system
-#>erase ALT22-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CLE22-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CGE2
-result transaction,problems <inline>
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ21-1-1.noarch@system
-#>erase AEQ22-1-1.noarch@system
-#>erase AEQ23-1-1.noarch@system
-#>erase AEQ3-1-1.noarch@system
-#>erase AEQ31-1-1.noarch@system
-#>erase AEQ32-1-1.noarch@system
-#>erase AEQ33-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGE23-1-1.noarch@system
-#>erase AGE3-1-1.noarch@system
-#>erase AGE31-1-1.noarch@system
-#>erase AGE32-1-1.noarch@system
-#>erase AGE33-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT2-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase AGT22-1-1.noarch@system
-#>erase AGT23-1-1.noarch@system
-#>erase AGT3-1-1.noarch@system
-#>erase AGT31-1-1.noarch@system
-#>erase AGT32-1-1.noarch@system
-#>erase AGT33-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE21-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT21-1-1.noarch@system
-#>erase ALT22-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CGE2-1-1.noarch@c
-nextjob
-solverflags allowuninstall
-job install name CGE22
-result transaction,problems <inline>
-#>erase AEQ2-1-1.noarch@system
-#>erase AEQ22-1-1.noarch@system
-#>erase AEQ23-1-1.noarch@system
-#>erase AEQ3-1-1.noarch@system
-#>erase AEQ31-1-1.noarch@system
-#>erase AEQ32-1-1.noarch@system
-#>erase AEQ33-1-1.noarch@system
-#>erase AGE1-1-1.noarch@system
-#>erase AGE11-1-1.noarch@system
-#>erase AGE12-1-1.noarch@system
-#>erase AGE13-1-1.noarch@system
-#>erase AGE2-1-1.noarch@system
-#>erase AGE21-1-1.noarch@system
-#>erase AGE22-1-1.noarch@system
-#>erase AGE23-1-1.noarch@system
-#>erase AGE3-1-1.noarch@system
-#>erase AGE31-1-1.noarch@system
-#>erase AGE32-1-1.noarch@system
-#>erase AGE33-1-1.noarch@system
-#>erase AGT1-1-1.noarch@system
-#>erase AGT11-1-1.noarch@system
-#>erase AGT12-1-1.noarch@system
-#>erase AGT13-1-1.noarch@system
-#>erase AGT2-1-1.noarch@system
-#>erase AGT21-1-1.noarch@system
-#>erase AGT22-1-1.noarch@system
-#>erase AGT23-1-1.noarch@system
-#>erase AGT3-1-1.noarch@system
-#>erase AGT31-1-1.noarch@system
-#>erase AGT32-1-1.noarch@system
-#>erase AGT33-1-1.noarch@system
-#>erase ALE2-1-1.noarch@system
-#>erase ALE22-1-1.noarch@system
-#>erase ALE23-1-1.noarch@system
-#>erase ALE3-1-1.noarch@system
-#>erase ALE31-1-1.noarch@system
-#>erase ALE32-1-1.noarch@system
-#>erase ALE33-1-1.noarch@system
-#>erase ALT23-1-1.noarch@system
-#>erase ALT3-1-1.noarch@system
-#>erase ALT31-1-1.noarch@system
-#>erase ALT32-1-1.noarch@system
-#>erase ALT33-1-1.noarch@system
-#>install CGE22-1-1.noarch@c
diff --git a/libsolv-0.6.15/test/testcases/forcebest/forcebest_dup.t b/libsolv-0.6.15/test/testcases/forcebest/forcebest_dup.t
deleted file mode 100644 (file)
index 7f1fbba..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Vnd: foo
-#>=Pkg: D 1 1 noarch
-#>=Vnd: foo
-#>=Con: A = 3-1
-repo available 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Vnd: foo
-#>=Pkg: A 3 1 noarch
-#>=Vnd: bar
-system i686 rpm system
-
-job distupgrade name A [forcebest]
-result transaction,problems <inline>
-#>erase D-1-1.noarch@system
-#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
-#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution d85f7c4e allow A-2-1.noarch@available
-#>upgrade A-1-1.noarch@system A-3-1.noarch@available
-
-# test if bestobeypolicy is a noop for dup jobs
-nextjob
-solverflags bestobeypolicy
-job distupgrade name A [forcebest]
-result transaction,problems <inline>
-#>erase D-1-1.noarch@system
-#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
-#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution d85f7c4e allow A-2-1.noarch@available
-#>upgrade A-1-1.noarch@system A-3-1.noarch@available
diff --git a/libsolv-0.6.15/test/testcases/forcebest/forcebest_in.t b/libsolv-0.6.15/test/testcases/forcebest/forcebest_in.t
deleted file mode 100644 (file)
index aaf2aa1..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: D 1 1 noarch
-#>=Vnd: foo
-#>=Con: A = 3-1
-repo available 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Vnd: foo
-#>=Pkg: A 3 1 noarch
-#>=Vnd: bar
-system i686 rpm system
-
-job install name A [forcebest]
-result transaction,problems <inline>
-#>erase D-1-1.noarch@system
-#>install A-3-1.noarch@available
-#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
-#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution d85f7c4e deljob install name A [forcebest]
-
-# currently bestobeypolicy is a noop for install jobs
-nextjob
-solverflags bestobeypolicy
-job install name A [forcebest]
-result transaction,problems <inline>
-#>erase D-1-1.noarch@system
-#>install A-3-1.noarch@available
-#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
-#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution d85f7c4e deljob install name A [forcebest]
diff --git a/libsolv-0.6.15/test/testcases/forcebest/forcebest_up.t b/libsolv-0.6.15/test/testcases/forcebest/forcebest_up.t
deleted file mode 100644 (file)
index 6e97bf8..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Vnd: foo
-#>=Pkg: D 1 1 noarch
-#>=Vnd: foo
-#>=Con: A = 3-1
-repo available 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Vnd: foo
-#>=Pkg: A 3 1 noarch
-#>=Vnd: bar
-system i686 rpm system
-
-job update name A [forcebest]
-result transaction,problems <inline>
-#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
-#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution 0d75a914 replace A-1-1.noarch@system A-3-1.noarch@available
-#>problem 1210fdfb solution d85f7c4e allow A-2-1.noarch@available
-#>upgrade A-1-1.noarch@system A-2-1.noarch@available
-
-nextjob
-solverflags bestobeypolicy
-job update name A [forcebest]
-result transaction,problems <inline>
-#>upgrade A-1-1.noarch@system A-2-1.noarch@available
diff --git a/libsolv-0.6.15/test/testcases/lockstep/lockstep_install.t b/libsolv-0.6.15/test/testcases/lockstep/lockstep_install.t
deleted file mode 100644 (file)
index f626da0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-repo system 0 empty
-repo test 0 testtags <inline>
-#>=Pkg: A 1 1 i586
-#>=Prv: A(x32)
-#>=Pkg: A 1 1 x86_64
-#>=Prv: A(x64)
-system x86_64 rpm system
-poolflags implicitobsoleteusescolors
-job install provides A(x32)
diff --git a/libsolv-0.6.15/test/testcases/lockstep/lockstep_update.t b/libsolv-0.6.15/test/testcases/lockstep/lockstep_update.t
deleted file mode 100644 (file)
index 128bcc3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 i586
-#>=Pkg: A 1 1 x86_64
-repo test 0 testtags <inline>
-#>=Pkg: A 2 1 i586
-#>=Pkg: A 2 1 x86_64
-#>=Pkg: A 3 1 i586
-#>=Pkg: A 4 1 x86_64
-system x86_64 rpm system
-poolflags implicitobsoleteusescolors
-job update all packages
diff --git a/libsolv-0.6.15/test/testcases/multiversion/multiversion.t b/libsolv-0.6.15/test/testcases/multiversion/multiversion.t
deleted file mode 100644 (file)
index decf22f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Pkg: B 1 1 noarch
-repo test 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Obs: B
-system i686 rpm system
-
-solverflags keepexplicitobsoletes
-job multiversion name A
-job install name A = 2
-result transaction,problems <inline>
-#>erase B-1-1.noarch@system
-#>install A-2-1.noarch@test
-
-nextjob
-solverflags keepexplicitobsoletes
-poolflags noobsoletesmultiversion
-job multiversion name A
-job install name A = 2
-result transaction,problems <inline>
-#>erase B-1-1.noarch@system
-#>install A-2-1.noarch@test
-
-nextjob
-poolflags !noobsoletesmultiversion
-job multiversion name A
-job install name A = 2
-result transaction,problems <inline>
-#>install A-2-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/namespace/namespaceprovides.t b/libsolv-0.6.15/test/testcases/namespace/namespaceprovides.t
deleted file mode 100644 (file)
index 62ca982..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-repo system 0 testtags <inline>
-#>=Ver: 2
-#>=Pkg: B 1 1 noarch
-#>=Prv: locale(en)
-#>=Pkg: C 1 1 noarch
-repo test 0 testtags <inline>
-#>=Ver: 2
-#>=Pkg: A 1 1 noarch
-#>=Prv: locale(de)
-#>=Pkg: C-de 1 1 noarch
-#>=Prv: locale(C:de)
-#>=Pkg: C-en 1 1 noarch
-#>=Prv: locale(C:en)
-system i686 rpm system
-
-# first test an empty job
-namespace namespace:language(de) @SYSTEM
-result transaction,problems <inline>
-
-# then test addalreadyrecommended
-nextjob
-namespace namespace:language(de) @SYSTEM
-solverflags addalreadyrecommended
-result transaction,problems <inline>
-#>install A-1-1.noarch@test
-#>install C-de-1-1.noarch@test
-
-nextjob
-namespace namespace:language(de) @SYSTEM
-job install provides namespace:language(de)
-result transaction,problems <inline>
-#>install A-1-1.noarch@test
-#>install C-de-1-1.noarch@test
-
-nextjob
-namespace namespace:language(de) @SYSTEM
-job erase provides namespace:language(en) [cleandeps]
-result transaction,problems <inline>
-#>erase B-1-1.noarch@system
-
-nextjob
-namespace namespace:language(de) @SYSTEM
-job install provides namespace:language(<NULL>)
-result transaction,problems <inline>
-#>install A-1-1.noarch@test
-#>install C-de-1-1.noarch@test
-
-nextjob
-namespace namespace:language(de) @SYSTEM
-job erase provides namespace:language(<NULL>) [cleandeps]
-result transaction,problems <inline>
-#>erase B-1-1.noarch@system
-
-nextjob
-namespace namespace:language(de) @SYSTEM
-job install provides namespace:language(<NULL>)
-job erase provides namespace:language(<NULL>) [cleandeps]
-result transaction,problems <inline>
-#>erase B-1-1.noarch@system
-#>install A-1-1.noarch@test
-#>install C-de-1-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/sat/assert.t b/libsolv-0.6.15/test/testcases/sat/assert.t
deleted file mode 100644 (file)
index b3a2482..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 x86_64
-#>=Prv: AA
-#>=Pkg: B 1 1 x86_64
-#>=Prv: AA
-system x86_64 * system
-job erase provides AA [weak]
-job install pkg B-1-1.x86_64@system
-result transaction,problems <inline>
diff --git a/libsolv-0.6.15/test/testcases/sat/mm-test.t b/libsolv-0.6.15/test/testcases/sat/mm-test.t
deleted file mode 100644 (file)
index 6665cad..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# testcase to check enabling/disabling of learnt rules
-#
-repo system 0 testtags <inline>
-#>=Ver: 2.0
-#>=Pkg: A 1.0 1 noarch
-#>=Req: D
-#>=Prv: A = 1.0-1
-#>=Con: C
-#>=Pkg: C 1.0 1 noarch
-#>=Prv: foo
-#>=Prv: C = 1.0-1
-#>=Con: D
-#>=Pkg: D 1.0 1 noarch
-#>=Prv: D = 1.0-1
-#>=Pkg: A2 1.0 1 noarch
-#>=Req: D2
-#>=Prv: A2 = 1.0-1
-#>=Con: C2
-#>=Pkg: C2 1.0 1 noarch
-#>=Prv: foo
-#>=Prv: C2 = 1.0-1
-#>=Con: D2
-#>=Pkg: D2 1.0 1 noarch
-#>=Prv: D2 = 1.0-1
-repo test 0 testtags <inline>
-#>=Ver: 2.0
-#>=Pkg: C 2.0 1 noarch
-#>=Prv: C = 2.0-1
-#>=Pkg: A 2.0 1 noarch
-#>=Prv: A = 2.0-1
-#>=Pkg: D 2.0 1 noarch
-#>=Prv: D = 2.0-1
-#>=Pkg: C2 2.0 1 noarch
-#>=Prv: C2 = 2.0-1
-#>=Pkg: A2 2.0 1 noarch
-#>=Prv: A2 = 2.0-1
-#>=Pkg: D2 2.0 1 noarch
-#>=Prv: D2 = 2.0-1
-#>=Pkg: E 2.0 1 noarch
-#>=Req: foo
-#>=Prv: E = 2.0-1
-system unset * system
-job install provides E
-job verify all packages
-result transaction,problems <inline>
-#>erase D-1.0-1.noarch@system
-#>erase D2-1.0-1.noarch@system
-#>problem a3755a16 info package E-2.0-1.noarch requires foo, but none of the providers can be installed
-#>problem a3755a16 solution 6d40bce1 deljob install provides E
-#>problem a3755a16 solution c06ed43e erase D-1.0-1.noarch@system
-#>problem a3755a16 solution c8a04f77 erase D2-1.0-1.noarch@system
-#>upgrade A-1.0-1.noarch@system A-2.0-1.noarch@test
-#>upgrade A2-1.0-1.noarch@system A2-2.0-1.noarch@test
diff --git a/libsolv-0.6.15/test/testcases/targeted/targeted_dup.t b/libsolv-0.6.15/test/testcases/targeted/targeted_dup.t
deleted file mode 100644 (file)
index bce3fef..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Pkg: D 1 1 noarch
-#>=Pkg: Z 1 1 noarch
-#>=Con: D = 2-1 
-repo available 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Pkg: B 1 0 noarch
-#>=Obs: A
-#>=Pkg: C 1 0 noarch
-#>=Obs: A = 1-1 
-#>=Pkg: D 2 1 noarch
-#>=Pkg: D 3 1 noarch
-system unset * system
-
-# first check untargeted
-job distupgrade name A = 1-1
-result transaction,problems <inline>
-#>erase A-1-1.noarch@system B-1-0.noarch@available
-#>install B-1-0.noarch@available
-
-# then targeted to A-2-1
-nextjob
-job distupgrade name A = 2-1
-result transaction,problems <inline>
-#>upgrade A-1-1.noarch@system A-2-1.noarch@available
-
-# then targeted to B
-nextjob
-job distupgrade name B
-result transaction,problems <inline>
-#>erase A-1-1.noarch@system B-1-0.noarch@available
-#>install B-1-0.noarch@available
-
-# first check forced to targeted
-nextjob
-job distupgrade name A = 1-1 [targeted]
-result transaction,problems <inline>
-
-# second check forced to untargeted
-nextjob
-solverflags noautotarget
-job distupgrade name A = 2-1
-result transaction,problems <inline>
-
-# then targeted to D
-nextjob
-job distupgrade name D
-result transaction,problems <inline>
-#>upgrade D-1-1.noarch@system D-3-1.noarch@available
-
-# then targeted to D-2-1 (should not go to D-3-1)
-nextjob
-job distupgrade name D = 2-1 
-result transaction,problems <inline>
-#>problem 840e2c39 info package Z-1-1.noarch conflicts with D = 2-1 provided by D-2-1.noarch
-#>problem 840e2c39 solution 3158736f erase Z-1-1.noarch@system
-#>problem 840e2c39 solution 42076df5 erase D-1-1.noarch@system
-#>problem 840e2c39 solution cdacbabe allow D-3-1.noarch@available
-#>upgrade D-1-1.noarch@system D-3-1.noarch@available
-
diff --git a/libsolv-0.6.15/test/testcases/targeted/targeted_up.t b/libsolv-0.6.15/test/testcases/targeted/targeted_up.t
deleted file mode 100644 (file)
index 1ab09e4..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: A 1 1 noarch
-#>=Pkg: D 1 1 noarch
-#>=Pkg: Z 1 1 noarch
-#>=Con: D = 2-1
-repo available 0 testtags <inline>
-#>=Pkg: A 2 1 noarch
-#>=Pkg: B 1 0 noarch
-#>=Obs: A
-#>=Pkg: C 1 0 noarch
-#>=Obs: A = 1-1
-#>=Pkg: D 2 1 noarch
-#>=Pkg: D 3 1 noarch
-system unset * system
-
-# first check untargeted
-job update name A = 1-1
-result transaction,problems <inline>
-#>erase A-1-1.noarch@system B-1-0.noarch@available
-#>install B-1-0.noarch@available
-
-# then targeted to A-2-1
-nextjob
-job update name A = 2-1
-result transaction,problems <inline>
-#>upgrade A-1-1.noarch@system A-2-1.noarch@available
-
-# then targeted to B
-nextjob
-job update name B
-result transaction,problems <inline>
-#>erase A-1-1.noarch@system B-1-0.noarch@available
-#>install B-1-0.noarch@available
-
-# first check forced to targeted
-nextjob
-job update name A = 1-1 [targeted]
-result transaction,problems <inline>
-
-# second check forced to untargeted
-nextjob
-solverflags noautotarget
-job distupgrade name A = 2-1
-result transaction,problems <inline>
-
-# then targeted to D
-nextjob
-job update name D
-result transaction,problems <inline>
-#>upgrade D-1-1.noarch@system D-3-1.noarch@available
-
-# then targeted to D-2-1 (should not go to D-3-1)
-nextjob
-job update name D = 2-1
-result transaction,problems <inline>
-
diff --git a/libsolv-0.6.15/test/testcases/testcase/str2dep.t b/libsolv-0.6.15/test/testcases/testcase/str2dep.t
deleted file mode 100644 (file)
index d08c110..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-# testcase for testcase_str2dep and testcase_dep2str
-
-#
-# first test literal escaping
-#
-genid dep <NULL>
-result genid <inline>
-#>genid  1: genid null
-#>genid dep <NULL>
-nextjob
-
-genid dep \00
-result genid <inline>
-#>genid  1: genid lit 
-#>genid dep \00
-nextjob
-
-genid dep \21\20\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f\3a\3b\3c\3d\3e\3f\40\5b\5c\5d\5e\5f\60\7b\7c\7d\7e
-result genid <inline>
-#>genid  1: genid lit ! "#$%&'()*+,-./:;<=>?@[\]^_`{|}~
-#>genid dep \21\20"#$%&'\28\29*+,-./:;<=>?@[\5c]^_`{|}~
-# make vim happy again: '
-nextjob
-
-genid dep foo(bar)
-result genid <inline>
-#>genid  1: genid lit foo(bar)
-#>genid dep foo(bar)
-nextjob
-
-genid dep foo()bar\29
-result genid <inline>
-#>genid  1: genid lit foo()bar)
-#>genid dep foo\28\29bar\29
-nextjob
-
-#
-# test namespace hack
-#
-genid dep namespace:foo(bar)
-result genid <inline>
-#>genid  1: genid lit namespace:foo
-#>genid  2: genid lit bar
-#>genid  3: genid op <NAMESPACE>
-#>genid dep namespace:foo(bar)
-nextjob
-genid lit namespace:foo(bar)
-result genid <inline>
-#>genid  1: genid lit namespace:foo(bar)
-#>genid dep namespace\3afoo\28bar\29
-nextjob
-
-#
-# test :any hack
-#
-genid dep foo:any
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit any
-#>genid  3: genid op <MULTIARCH>
-#>genid dep foo:any
-nextjob
-genid lit foo:any
-result genid <inline>
-#>genid  1: genid lit foo:any
-#>genid dep foo\3aany
-nextjob
-
-#
-# test simple ops
-#
-genid dep foo < 1-1
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit 1-1
-#>genid  3: genid op <
-#>genid dep foo < 1-1
-nextjob
-
-genid dep foo = 1-1
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit 1-1
-#>genid  3: genid op =
-#>genid dep foo = 1-1
-nextjob
-
-genid dep foo > 1-1
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit 1-1
-#>genid  3: genid op >
-#>genid dep foo > 1-1
-nextjob
-
-genid dep foo >= 1-1
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit 1-1
-#>genid  3: genid op >=
-#>genid dep foo >= 1-1
-nextjob
-
-genid dep foo <= 1-1
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit 1-1
-#>genid  3: genid op <=
-#>genid dep foo <= 1-1
-nextjob
-
-# test arch op
-genid dep foo . i586
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit i586
-#>genid  3: genid op .
-#>genid dep foo . i586
-nextjob
-
-# test haiku compat dep
-genid dep foo = 2-1 compat >= 1-1
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit 2-1
-#>genid  3: genid lit 1-1
-#>genid  4: genid op compat >=
-#>genid  5: genid op =
-#>genid dep foo = 2-1 compat >= 1-1
-nextjob
-
-#
-# test complex (aka rich) deps
-#
-
-genid dep foo & bar
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit bar
-#>genid  3: genid op &
-#>genid dep foo & bar
-nextjob
-
-genid dep foo & bar & baz
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit bar
-#>genid  3: genid lit baz
-#>genid  4: genid op &
-#>genid  5: genid op &
-#>genid dep foo & bar & baz
-nextjob
-
-genid dep foo & bar | baz
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit bar
-#>genid  3: genid lit baz
-#>genid  4: genid op |
-#>genid  5: genid op &
-#>genid dep foo & (bar | baz)
-nextjob
-
-genid dep (foo & bar) | baz
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit bar
-#>genid  3: genid op &
-#>genid  4: genid lit baz
-#>genid  5: genid op |
-#>genid dep (foo & bar) | baz
-nextjob
-
-genid dep (foo & bar > 2) | baz
-result genid <inline>
-#>genid  1: genid lit foo
-#>genid  2: genid lit bar
-#>genid  3: genid lit 2
-#>genid  4: genid op >
-#>genid  5: genid op &
-#>genid  6: genid lit baz
-#>genid  7: genid op |
-#>genid dep (foo & bar > 2) | baz
-nextjob
-
diff --git a/libsolv-0.6.15/test/testcases/yumobs/split.t b/libsolv-0.6.15/test/testcases/yumobs/split.t
deleted file mode 100644 (file)
index a3921ed..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-repo system 0 testtags <inline>
-#>=Ver: 2.0
-#>=Pkg: c 27 1 x86_64
-repo available 0 testtags <inline>
-#>=Ver: 2.0
-#>=Pkg: d 28 1 x86_64
-#>=Obs: c
-#>=Pkg: e 28 1 x86_64
-#>=Obs: c
-
-system x86_64 rpm system
-
-job update all packages
-result transaction,problems <inline>
-#>erase c-27-1.x86_64@system d-28-1.x86_64@available
-#>install d-28-1.x86_64@available
-
-nextjob
-solverflags yumobsoletes
-job update all packages
-result transaction,problems <inline>
-#>erase c-27-1.x86_64@system d-28-1.x86_64@available
-#>install d-28-1.x86_64@available
-#>install e-28-1.x86_64@available
diff --git a/libsolv-0.6.15/tools/CMakeLists.txt b/libsolv-0.6.15/tools/CMakeLists.txt
deleted file mode 100644 (file)
index 16fa097..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#
-# CMakeLists.txt for tools
-#
-
-ADD_LIBRARY (toolstuff STATIC common_write.c)
-
-SET (tools_list mergesolv dumpsolv installcheck testsolv)
-
-IF (ENABLE_RPMDB)
-ADD_EXECUTABLE (rpmdb2solv rpmdb2solv.c)
-TARGET_LINK_LIBRARIES (rpmdb2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (rpms2solv rpms2solv.c)
-TARGET_LINK_LIBRARIES (rpms2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (findfileconflicts findfileconflicts.c)
-TARGET_LINK_LIBRARIES (findfileconflicts libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} rpmdb2solv rpms2solv)
-ENDIF (ENABLE_RPMDB)
-
-IF (ENABLE_RPMMD)
-ADD_EXECUTABLE (repomdxml2solv repomdxml2solv.c)
-TARGET_LINK_LIBRARIES (repomdxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (rpmmd2solv rpmmd2solv.c)
-TARGET_LINK_LIBRARIES (rpmmd2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (updateinfoxml2solv updateinfoxml2solv.c)
-TARGET_LINK_LIBRARIES (updateinfoxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (deltainfoxml2solv deltainfoxml2solv.c)
-TARGET_LINK_LIBRARIES (deltainfoxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} repomdxml2solv rpmmd2solv updateinfoxml2solv deltainfoxml2solv)
-ENDIF (ENABLE_RPMMD)
-
-IF (ENABLE_HELIXREPO)
-ADD_EXECUTABLE (helix2solv helix2solv.c)
-TARGET_LINK_LIBRARIES (helix2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} helix2solv)
-ENDIF (ENABLE_HELIXREPO)
-
-IF (ENABLE_SUSEREPO)
-ADD_EXECUTABLE (susetags2solv susetags2solv.c)
-TARGET_LINK_LIBRARIES (susetags2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} susetags2solv)
-ENDIF (ENABLE_SUSEREPO)
-
-IF (ENABLE_COMPS)
-ADD_EXECUTABLE (comps2solv comps2solv.c)
-TARGET_LINK_LIBRARIES (comps2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} comps2solv)
-ENDIF (ENABLE_COMPS)
-
-IF (ENABLE_DEBIAN)
-ADD_EXECUTABLE (deb2solv deb2solv.c)
-TARGET_LINK_LIBRARIES (deb2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} deb2solv)
-ENDIF (ENABLE_DEBIAN)
-
-IF (ENABLE_MDKREPO)
-ADD_EXECUTABLE (mdk2solv mdk2solv.c)
-TARGET_LINK_LIBRARIES (mdk2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} mdk2solv)
-ENDIF (ENABLE_MDKREPO)
-
-IF (ENABLE_ARCHREPO)
-ADD_EXECUTABLE (archpkgs2solv archpkgs2solv.c)
-TARGET_LINK_LIBRARIES (archpkgs2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (archrepo2solv archrepo2solv.c)
-TARGET_LINK_LIBRARIES (archrepo2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} archpkgs2solv archrepo2solv)
-ENDIF (ENABLE_ARCHREPO)
-
-IF (ENABLE_CUDFREPO)
-ADD_EXECUTABLE (cudftest cudftest.c)
-TARGET_LINK_LIBRARIES (cudftest libsolvext libsolv ${SYSTEM_LIBRARIES})
-ENDIF (ENABLE_CUDFREPO)
-
-ADD_EXECUTABLE (installcheck installcheck.c)
-TARGET_LINK_LIBRARIES (installcheck libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-IF (SUSE)
-ADD_EXECUTABLE (patchcheck patchcheck.c)
-TARGET_LINK_LIBRARIES (patchcheck libsolvext libsolv ${SYSTEM_LIBRARIES})
-ENDIF (SUSE)
-
-IF (ENABLE_APPDATA)
-ADD_EXECUTABLE (appdata2solv appdata2solv.c)
-TARGET_LINK_LIBRARIES (appdata2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-SET (tools_list ${tools_list} appdata2solv)
-ENDIF (ENABLE_APPDATA)
-
-ADD_EXECUTABLE (dumpsolv dumpsolv.c )
-TARGET_LINK_LIBRARIES (dumpsolv libsolv)
-
-ADD_EXECUTABLE (mergesolv mergesolv.c )
-TARGET_LINK_LIBRARIES (mergesolv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-ADD_EXECUTABLE (testsolv testsolv.c)
-TARGET_LINK_LIBRARIES (testsolv libsolvext libsolv ${SYSTEM_LIBRARIES})
-
-INSTALL (TARGETS ${tools_list} DESTINATION ${BIN_INSTALL_DIR})
-
-INSTALL (PROGRAMS repo2solv.sh DESTINATION ${BIN_INSTALL_DIR})
diff --git a/libsolv-0.6.15/tools/appdata2solv.c b/libsolv-0.6.15/tools/appdata2solv.c
deleted file mode 100644 (file)
index a8753a1..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2013, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * appdata2solv.c
- * 
- * parse AppStream appdata type xml and write out .solv file
- *
- * reads from stdin
- * writes to stdout
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_appdata.h"
-#include "common_write.h"
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool = pool_create();
-  Repo *repo;
-  int c;
-  const char *appdatadir = 0;
-  const char *root = 0;
-
-  while ((c = getopt(argc, argv, "hd:r:")) >= 0)
-    {
-      switch (c)
-       {
-       case 'd':
-         appdatadir = optarg;
-         break;
-       case 'r':
-         root = optarg;
-         break;
-       default:
-         fprintf(stderr, "usage: appdata2solv [-d appdatadir]");
-         exit(c == 'h' ? 0 : 1);
-       }
-    }
-
-  if (root)
-    pool_set_rootdir(pool, root);
-    
-  repo = repo_create(pool, "<stdin>");
-  if (!appdatadir)
-    {
-      if (repo_add_appdata(repo, stdin, 0))
-       {
-         fprintf(stderr, "appdata2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-  else
-    {
-      if (repo_add_appdata_dir(repo, appdatadir, REPO_USE_ROOTDIR))
-       {
-         fprintf(stderr, "appdata2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-  tool_write(repo, 0, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/archpkgs2solv.c b/libsolv-0.6.15/tools/archpkgs2solv.c
deleted file mode 100644 (file)
index 4ce95a4..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * archpkgs2solv - create a solv file from multiple arch packages
- * 
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "util.h"
-#include "pool.h"
-#include "repo.h"
-#include "repo_arch.h"
-#include "repo_solv.h"
-#include "common_write.h"
-
-static char *
-fgets0(char *s, int size, FILE *stream)
-{
-  char *p = s;
-  int c;
-
-  while (--size > 0)
-    {
-      c = getc(stream);
-      if (c == EOF)
-       {
-         if (p == s)
-           return 0;
-         c = 0;
-       }
-      *p++ = c;
-      if (!c)
-       return s;
-    }
-  *p = 0;
-  return s;
-}
-
-int
-main(int argc, char **argv)
-{
-  const char **pkgs = 0;
-  char *manifest = 0;
-  int manifest0 = 0;
-  int i, c, res, npkgs = 0;
-  Pool *pool = pool_create();
-  Repo *repo;
-  FILE *fp;
-  char buf[4096], *p;
-  const char *basefile = 0;
-  int flags = 0;
-
-  while ((c = getopt(argc, argv, "0b:m:i")) >= 0)
-    {
-      switch(c)
-       {
-       case 'b':
-         basefile = optarg;
-         break;
-       case 'm':
-         manifest = optarg;
-         break;
-       case '0':
-         manifest0 = 1;
-         break;
-       case 'i':
-         flags |= ARCH_ADD_WITH_PKGID;
-         break;
-       default:
-         exit(1);
-       }
-    }
-  if (manifest)
-    {
-      if (!strcmp(manifest, "-"))
-        fp = stdin;
-      else if ((fp = fopen(manifest, "r")) == 0)
-       {
-         perror(manifest);
-         exit(1);
-       }
-      for (;;)
-       {
-         if (manifest0)
-           {
-             if (!fgets0(buf, sizeof(buf), fp))
-               break;
-           }
-         else
-           {
-             if (!fgets(buf, sizeof(buf), fp))
-               break;
-             if ((p = strchr(buf, '\n')) != 0)
-               *p = 0;
-           }
-          pkgs = solv_extend(pkgs, npkgs, 1, sizeof(char *), 15);
-         pkgs[npkgs++] = strdup(buf);
-       }
-      if (fp != stdin)
-        fclose(fp);
-    }
-  while (optind < argc)
-    {
-      pkgs = solv_extend(pkgs, npkgs, 1, sizeof(char *), 15);
-      pkgs[npkgs++] = solv_strdup(argv[optind++]);
-    }
-  repo = repo_create(pool, "archpkgs2solv");
-  repo_add_repodata(repo, 0);
-  res = 0;
-  for (i = 0; i < npkgs; i++)
-    if (repo_add_arch_pkg(repo, pkgs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|flags) == 0)
-      {
-       fprintf(stderr, "archpkgs2solv: %s\n", pool_errstr(pool));
-       res = 1;
-      }
-  repo_internalize(repo);
-  tool_write(repo, basefile, 0);
-  pool_free(pool);
-  for (c = 0; c < npkgs; c++)
-    solv_free((char *)pkgs[c]);
-  solv_free(pkgs);
-  exit(res);
-}
-
diff --git a/libsolv-0.6.15/tools/archrepo2solv.c b/libsolv-0.6.15/tools/archrepo2solv.c
deleted file mode 100644 (file)
index 6dcb076..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * archrepo2solv.c
- *
- * parse archlinux repo file
- *
- * reads from stdin
- * writes to stdout
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_arch.h"
-#include "solv_xfopen.h"
-#include "common_write.h"
-
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "archrepo2solv\n"
-          "  reads a repository from <stdin> and writes a .solv file to <stdout>\n"
-          "  -l <dbdir> : read local database\n"
-          "  -h : print help & exit\n"
-         );
-   exit(status);
-}
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool;
-  Repo *repo;
-  int c, ret;
-  const char *localdb = 0;
-
-  while ((c = getopt(argc, argv, "hl:")) >= 0)
-    {
-      switch(c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'l':
-         localdb = optarg;
-         break;
-       default:
-         usage(1);
-         break;
-       }
-    }
-  pool = pool_create();
-  repo = repo_create(pool, "<stdin>");
-  if (localdb)
-    ret = repo_add_arch_local(repo, localdb, 0);
-  else
-    ret = repo_add_arch_repo(repo, stdin, 0);
-  if (ret)
-    {
-      fprintf(stderr, "archrepo2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  tool_write(repo, 0, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/common_write.c b/libsolv-0.6.15/tools/common_write.c
deleted file mode 100644 (file)
index 6de8a69..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_write.h"
-#include "common_write.h"
-
-#define LIBSOLV_TOOLVERSION "1.0"
-
-static Id verticals[] = {
-  SOLVABLE_AUTHORS,
-  SOLVABLE_DESCRIPTION,
-  SOLVABLE_MESSAGEDEL,
-  SOLVABLE_MESSAGEINS,
-  SOLVABLE_EULA,
-  SOLVABLE_DISKUSAGE,
-  SOLVABLE_FILELIST,
-  SOLVABLE_CHANGELOG_AUTHOR,
-  SOLVABLE_CHANGELOG_TEXT,
-  0
-};
-
-static char *languagetags[] = {
-  "solvable:summary:",
-  "solvable:description:",
-  "solvable:messageins:",
-  "solvable:messagedel:",
-  "solvable:eula:",
-  0
-};
-
-static int test_separate = 0;
-
-struct keyfilter_data {
-  char **languages;
-  int nlanguages;
-  int haveaddedfileprovides;
-  int haveexternal;
-};
-
-static int
-keyfilter_solv(Repo *data, Repokey *key, void *kfdata)
-{
-  struct keyfilter_data *kd = kfdata;
-  int i;
-  const char *keyname;
-
-  if (test_separate && key->storage != KEY_STORAGE_SOLVABLE)
-    return KEY_STORAGE_DROPPED;
-  if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
-    return KEY_STORAGE_DROPPED;
-  if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  keyname = pool_id2str(data->pool, key->name);
-  for (i = 0; languagetags[i] != 0; i++)
-    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_attr(Repo *data, Repokey *key, void *kfdata)
-{
-  int i;
-  const char *keyname;
-  if (key->storage == KEY_STORAGE_SOLVABLE)
-    return KEY_STORAGE_DROPPED;
-  /* those must only be in the main solv file */
-  if (key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_TOOLVERSION)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  keyname = pool_id2str(data->pool, key->name);
-  for (i = 0; languagetags[i] != 0; i++)
-    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_language(Repo *repo, Repokey *key, void *kfdata)
-{
-  Pool *pool = repo->pool;
-  const char *name, *p;
-  char *lang = kfdata;
-  int i;
-
-  name = pool_id2str(repo->pool, key->name);
-  p = strrchr(name, ':');
-  if (!p || strcmp(p + 1, lang) != 0)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    {
-      const char *vname = pool_id2str(pool, verticals[i]);
-      if (!strncmp(name, vname, p - name) && vname[p - name] == 0)
-       return KEY_STORAGE_VERTICAL_OFFSET;
-    }
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_DU(Repo *repo, Repokey *key, void *kfdata)
-{
-  int i;
-  if (key->name != SOLVABLE_DISKUSAGE)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_FL(Repo *repo, Repokey *key, void *kfdata)
-{
-  int i;
-  if (key->name != SOLVABLE_FILELIST)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_other(Repo *repo, Repokey *key, void *kfdata)
-{
-  const char *name, *p;
-  struct keyfilter_data *kd = kfdata;
-  int i;
-
-  if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
-    return KEY_STORAGE_DROPPED;
-  if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
-    return KEY_STORAGE_DROPPED;
-
-  if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE)
-    return KEY_STORAGE_DROPPED;
-
-  name = pool_id2str(repo->pool, key->name);
-  p = strrchr(name, ':');
-  if (p)
-    {
-      for (i = 0; i < kd->nlanguages; i++)
-       if (!strcmp(p + 1, kd->languages[i]))
-         return KEY_STORAGE_DROPPED;
-    }
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-/*
- * Write <repo> to stdout
- * If <attrname> is given, write attributes to <attrname>
- * If <basename> is given, split attributes
- */
-
-#define REPODATAFILE_BLOCK 15
-
-static void
-write_info(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Repodata *info, const char *location)
-{
-  Id h;
-  Queue keyq;
-
-  queue_init(&keyq);
-  if (repo_write_filtered(repo, fp, keyfilter, kfdata, &keyq) != 0)
-    {
-      fprintf(stderr, "repo_write failed\n");
-      exit(1);
-    }
-  h = repodata_new_handle(info);
-  if (keyq.count)
-    repodata_set_idarray(info, h, REPOSITORY_KEYS, &keyq);
-  queue_free(&keyq);
-  repodata_set_str(info, h, REPOSITORY_LOCATION, location);
-  repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h);
-}
-
-void
-tool_write(Repo *repo, const char *basename, const char *attrname)
-{
-  Repodata *data;
-  Repodata *info = 0;
-  Repokey *key;
-  char **languages = 0;
-  int nlanguages = 0;
-  int i, j, k, l;
-  struct keyfilter_data kd;
-  Queue addedfileprovides;
-
-  memset(&kd, 0, sizeof(kd));
-  info = repo_add_repodata(repo, 0);
-  repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
-  queue_init(&addedfileprovides);
-  pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0);
-  if (addedfileprovides.count)
-    {
-      kd.haveaddedfileprovides = 1;
-      repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides);
-    }
-  queue_free(&addedfileprovides);
-
-  pool_freeidhashes(repo->pool);       /* free some mem */
-
-  if (basename)
-    {
-      char fn[4096];
-      FILE *fp;
-      int has_DU = 0;
-      int has_FL = 0;
-
-      /* find languages and other info */
-      FOR_REPODATAS(repo, i, data)
-       {
-         for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
-           {
-             const char *keyname = pool_id2str(repo->pool, key->name);
-             if (key->name == SOLVABLE_DISKUSAGE)
-               has_DU = 1;
-             if (key->name == SOLVABLE_FILELIST)
-               has_FL = 1;
-             for (k = 0; languagetags[k] != 0; k++)
-               if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
-                 break;
-             if (!languagetags[k])
-               continue;
-             l = strlen(languagetags[k]);
-             if (strlen(keyname + l) > 5)
-               continue;
-             for (k = 0; k < nlanguages; k++)
-               if (!strcmp(languages[k], keyname + l))
-                 break;
-             if (k < nlanguages)
-               continue;
-             languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *));
-             languages[nlanguages++] = strdup(keyname + l);
-           }
-       }
-      /* write language subfiles */
-      for (i = 0; i < nlanguages; i++)
-        {
-         sprintf(fn, "%s.%s.solv", basename, languages[i]);
-         if (!(fp = fopen(fn, "w")))
-           {
-             perror(fn);
-             exit(1);
-           }
-         write_info(repo, fp, keyfilter_language, languages[i], info, fn);
-         fclose(fp);
-         kd.haveexternal = 1;
-        }
-      /* write DU subfile */
-      if (has_DU)
-       {
-         sprintf(fn, "%s.DU.solv", basename);
-         if (!(fp = fopen(fn, "w")))
-           {
-             perror(fn);
-             exit(1);
-           }
-         write_info(repo, fp, keyfilter_DU, 0, info, fn);
-         fclose(fp);
-         kd.haveexternal = 1;
-       }
-      /* write filelist */
-      if (has_FL)
-       {
-         sprintf(fn, "%s.FL.solv", basename);
-         if (!(fp = fopen(fn, "w")))
-           {
-             perror(fn);
-             exit(1);
-           }
-         write_info(repo, fp, keyfilter_FL, 0, info, fn);
-         fclose(fp);
-         kd.haveexternal = 1;
-       }
-      /* write everything else */
-      sprintf(fn, "%s.solv", basename);
-      if (!(fp = fopen(fn, "w")))
-       {
-         perror(fn);
-         exit(1);
-       }
-      kd.languages = languages;
-      kd.nlanguages = nlanguages;
-      repodata_internalize(info);
-      if (repo_write_filtered(repo, fp, keyfilter_other, &kd, 0) != 0)
-       {
-         fprintf(stderr, "repo_write failed\n");
-         exit(1);
-       }
-      if (fclose(fp) != 0)
-       {
-         perror("fclose");
-         exit(1);
-       }
-      for (i = 0; i < nlanguages; i++)
-       free(languages[i]);
-      solv_free(languages);
-      repodata_free(info);
-    }
-  if (attrname)
-    {
-      FILE *fp;
-      test_separate = 1;
-      fp = fopen(attrname, "w");
-      write_info(repo, fp, keyfilter_attr, 0, info, attrname);
-      fclose(fp);
-      kd.haveexternal = 1;
-    }
-  repodata_internalize(info);
-  if (repo_write_filtered(repo, stdout, keyfilter_solv, &kd, 0) != 0)
-    {
-      fprintf(stderr, "repo_write failed\n");
-      exit(1);
-    }
-  repodata_free(info);
-}
diff --git a/libsolv-0.6.15/tools/common_write.h b/libsolv-0.6.15/tools/common_write.h
deleted file mode 100644 (file)
index 7630edd..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#ifndef COMMON_WRITE_H
-#define COMMON_WRITE_H
-
-#include "repo.h"
-
-void tool_write(Repo *repo, const char *basename, const char *attrname);
-
-#endif
diff --git a/libsolv-0.6.15/tools/comps2solv.c b/libsolv-0.6.15/tools/comps2solv.c
deleted file mode 100644 (file)
index 73854d2..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * comps2solv.c
- * 
- * parse Fedora Comps type xml and write out .solv file
- *
- * reads from stdin
- * writes to stdout
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_comps.h"
-#include "common_write.h"
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-  if (repo_add_comps(repo, stdin, 0))
-    {
-      fprintf(stderr, "comps2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  tool_write(repo, 0, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/cudftest.c b/libsolv-0.6.15/tools/cudftest.c
deleted file mode 100644 (file)
index 75aeef5..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "evr.h"
-#include "solver.h"
-#include "solverdebug.h"
-#include "repo_cudf.h"
-#include "repo_write.h"
-#include "solv_xfopen.h"
-
-static void
-dump_repo(Repo *repo, char *name)
-{
-  FILE *fp;
-  if ((fp = fopen(name, "w")) == 0)
-    {
-      perror(name);
-      exit(1);
-    }
-  repo_write(repo, fp);
-  fclose(fp);
-}
-
-static int
-sortfunc(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = dp;
-  Solvable *sa, *sb;
-  sa = pool->solvables + *(Id *)ap;
-  sb = pool->solvables + *(Id *)bp;
-  if (sa->name != sb->name)
-    {
-      int r = strcmp(pool_id2str(pool, sa->name), pool_id2str(pool, sb->name));
-      if (r)
-       return r;
-    }
-  if (sa->evr != sb->evr)
-    {
-      int r = pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE);
-      if (r)
-       return r;
-    }
-  return *(Id *)ap - *(Id *)bp;
-}
-
-int
-main(int argc, char **argv)
-{
-  char *cudfin;
-  char *cudfout = 0;
-  Pool *pool;
-  Repo *installed, *repo;
-  FILE *fp, *ofp;
-  Solver *solv;
-  Transaction *trans;
-  Queue job;
-  Queue dq;
-  int i;
-  int debug = 0;
-
-  while (argc > 1 && !strcmp(argv[1], "-d"))
-    {
-      debug++;
-      argc--;
-      argv++;
-    }
-  if (argc < 2)
-    {
-      fprintf(stderr, "Usage: cudftest <cudfin> [cudfout]\n");
-      exit(1);
-    }
-  cudfin = argv[1];
-  cudfout = argc > 2 ? argv[2] : 0;
-
-  if ((fp = solv_xfopen(cudfin, 0)) == 0)
-    {
-      perror(cudfin);
-      exit(1);
-    }
-  pool = pool_create();
-  if (debug > 1)
-    pool_setdebuglevel(pool, debug - 1);
-  installed = repo_create(pool, "installed");
-  pool_set_installed(pool, installed);
-  repo = repo_create(pool, "repo");
-  queue_init(&job);
-  repo_add_cudf(repo, installed, fp, &job, 0);
-  fclose(fp);
-
-  pool_createwhatprovides(pool);
-
-  /* debug */
-  if (debug)
-    {
-      dump_repo(installed, "cudf_installed.solv");
-      dump_repo(repo, "cudf_repo.solv");
-    }
-
-  solv = solver_create(pool);
-  solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
-  /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */
-
-  queue_push2(&job, SOLVER_VERIFY | SOLVER_SOLVABLE_ALL, 0);
-  if (solver_solve(solv, &job) != 0)
-    {
-      int problem;
-      int pcnt = solver_problem_count(solv);
-      printf("Found %d problems:\n", pcnt);
-      for (problem = 1; problem <= pcnt; problem++)
-        {
-          printf("Problem %d:\n", problem);
-          solver_printprobleminfo(solv, problem);
-          printf("\n");
-       }
-    }
-  trans = solver_create_transaction(solv);
-  solver_free(solv);
-
-  if (debug)
-    transaction_print(trans);
-
-  queue_init(&dq);
-  transaction_installedresult(trans, &dq);
-  solv_sort(dq.elements, dq.count, sizeof(Id), sortfunc, pool);
-
-  ofp = stdout;
-  if (cudfout && ((ofp = fopen(cudfout, "w")) == 0))
-    {
-      perror(cudfout);
-      exit(1);
-    }
-  for (i = 0; i < dq.count; i++)
-    {
-      Solvable *s = pool_id2solvable(pool, dq.elements[i]);
-      fprintf(ofp, "package: %s\n", pool_id2str(pool, s->name));
-      fprintf(ofp, "version: %s\n", pool_id2str(pool, s->evr));
-      fprintf(ofp, "installed: true\n");
-      if (s->repo == pool->installed)
-        fprintf(ofp, "was-installed: true\n");
-      fprintf(ofp, "\n");
-    }
-  queue_free(&dq);
-  transaction_free(trans);
-  queue_free(&job);
-  pool_free(pool);
-  if (ofp != stdout)
-    {
-      if (fclose(ofp))
-       {
-         perror("fclose");
-         exit(1);
-       }
-    }
-  exit(0);
-}
-
diff --git a/libsolv-0.6.15/tools/deb2solv.c b/libsolv-0.6.15/tools/deb2solv.c
deleted file mode 100644 (file)
index 0d22f24..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * deb2solv - create a solv file from one or multiple debs
- * 
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "util.h"
-#include "pool.h"
-#include "repo.h"
-#include "repo_deb.h"
-#include "repo_solv.h"
-#include "common_write.h"
-
-static char *
-fgets0(char *s, int size, FILE *stream)
-{
-  char *p = s;
-  int c;
-
-  while (--size > 0)
-    {
-      c = getc(stream);
-      if (c == EOF)
-       {
-         if (p == s)
-           return 0;
-         c = 0;
-       }
-      *p++ = c;
-      if (!c)
-       return s;
-    }
-  *p = 0;
-  return s;
-}
-
-int
-main(int argc, char **argv)
-{
-  const char **debs = 0;
-  char *manifest = 0;
-  int manifest0 = 0;
-  int c, i, res, ndebs = 0;
-  Pool *pool = pool_create();
-  Repo *repo;
-  FILE *fp;
-  char buf[4096], *p;
-  const char *basefile = 0;
-
-  while ((c = getopt(argc, argv, "0b:m:")) >= 0)
-    {
-      switch(c)
-       {
-       case 'b':
-         basefile = optarg;
-         break;
-       case 'm':
-         manifest = optarg;
-         break;
-       case '0':
-         manifest0 = 1;
-         break;
-       default:
-         exit(1);
-       }
-    }
-  if (manifest)
-    {
-      if (!strcmp(manifest, "-"))
-        fp = stdin;
-      else if ((fp = fopen(manifest, "r")) == 0)
-       {
-         perror(manifest);
-         exit(1);
-       }
-      for (;;)
-       {
-         if (manifest0)
-           {
-             if (!fgets0(buf, sizeof(buf), fp))
-               break;
-           }
-         else
-           {
-             if (!fgets(buf, sizeof(buf), fp))
-               break;
-             if ((p = strchr(buf, '\n')) != 0)
-               *p = 0;
-           }
-          debs = solv_extend(debs, ndebs, 1, sizeof(char *), 15);
-         debs[ndebs++] = strdup(buf);
-       }
-      if (fp != stdin)
-        fclose(fp);
-    }
-  while (optind < argc)
-    {
-      debs = solv_extend(debs, ndebs, 1, sizeof(char *), 15);
-      debs[ndebs++] = strdup(argv[optind++]);
-    }
-  repo = repo_create(pool, "deb2solv");
-  repo_add_repodata(repo, 0);
-  res = 0;
-  for (i = 0; i < ndebs; i++)
-    {
-      if (repo_add_deb(repo, debs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE) == 0)
-       {
-         fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));
-         res = 1;
-       }
-    }
-  repo_internalize(repo);
-  tool_write(repo, basefile, 0);
-  pool_free(pool);
-  for (c = 0; c < ndebs; c++)
-    free((char *)debs[c]);
-  solv_free(debs);
-  exit(res);
-}
-
diff --git a/libsolv-0.6.15/tools/deltainfoxml2solv.c b/libsolv-0.6.15/tools/deltainfoxml2solv.c
deleted file mode 100644 (file)
index 41616ba..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_deltainfoxml.h"
-#include "common_write.h"
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "deltainfoxml2solv [-a][-h][-n <attrname>]\n"
-         "  reads a 'deltainfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
-         "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
-        );
-  exit(status);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, flags = 0;
-  char *attrname = 0;
-  
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-
-  while ((c = getopt(argc, argv, "hn:")) >= 0)
-    {   
-      switch(c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'n':
-         attrname = optarg;
-         break;
-       default:
-         usage(1);
-         break;
-       }
-    }
-  if (repo_add_deltainfoxml(repo, stdin, flags))
-    {
-      fprintf(stderr, "deltainfoxml2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  tool_write(repo, 0, attrname);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/diskusagexml2solv.c b/libsolv-0.6.15/tools/diskusagexml2solv.c
deleted file mode 100644 (file)
index 59ac79a..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_diskusagexml.h"
-#include "common_write.h"
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "diskusagexml2solv [-a][-h][-n <attrname>]\n"
-         "  reads a 'diskusage.xml' file from <stdin> and writes a .solv file to <stdout>\n"
-         "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
-        );
-  exit(status);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, flags = 0;
-  char *attrname = 0;
-  
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-
-  while ((c = getopt(argc, argv, "hn:")) >= 0)
-    {   
-      switch(c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'n':
-         attrname = optarg;
-         break;
-       default:
-         usage(1);
-         break;
-       }
-    }
-  if (repo_add_diskusagexml(repo, stdin, flags))
-    {
-      fprintf(stderr, "diskusagexml2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  tool_write(repo, 0, attrname);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/dumpsolv.c b/libsolv-0.6.15/tools/dumpsolv.c
deleted file mode 100644 (file)
index 1aaee16..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-static int with_attr;
-static int dump_json;
-
-#include "pool.h"
-#include "chksum.h"
-#include "repo_solv.h"
-
-
-static int
-dump_attr(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  const char *keyname;
-  KeyValue *kvp;
-  int indent = 0;
-
-  keyname = pool_id2str(repo->pool, key->name);
-  for (kvp = kv; (kvp = kvp->parent) != 0; indent += 2)
-    printf("  ");
-  switch(key->type)
-    {
-    case REPOKEY_TYPE_ID:
-      if (data && data->localpool)
-       kv->str = stringpool_id2str(&data->spool, kv->id);
-      else
-       kv->str = pool_dep2str(repo->pool, kv->id);
-      printf("%s: %s\n", keyname, kv->str);
-      break;
-    case REPOKEY_TYPE_CONSTANTID:
-      printf("%s: %s\n", keyname, pool_dep2str(repo->pool, kv->id));
-      break;
-    case REPOKEY_TYPE_IDARRAY:
-      if (!kv->entry)
-        printf("%s:\n%*s", keyname, indent, "");
-      if (data && data->localpool)
-        printf("  %s\n", stringpool_id2str(&data->spool, kv->id));
-      else
-        printf("  %s\n", pool_dep2str(repo->pool, kv->id));
-      break;
-    case REPOKEY_TYPE_STR:
-      printf("%s: %s\n", keyname, kv->str);
-      break;
-    case REPOKEY_TYPE_VOID:
-      printf("%s: (void)\n", keyname);
-      break;
-    case REPOKEY_TYPE_U32:
-    case REPOKEY_TYPE_CONSTANT:
-      printf("%s: %u\n", keyname, kv->num);
-      break;
-    case REPOKEY_TYPE_NUM:
-      printf("%s: %llu\n", keyname, SOLV_KV_NUM64(kv));
-      break;
-    case REPOKEY_TYPE_BINARY:
-      if (kv->num)
-        printf("%s: %02x..%02x len %u\n", keyname, (unsigned char)kv->str[0], (unsigned char)kv->str[kv->num - 1], kv->num);
-      else
-        printf("%s: len 0\n", keyname);
-      break;
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      if (!kv->entry)
-        printf("%s:\n%*s", keyname, indent, "");
-      printf("  %s %u %u\n", repodata_dir2str(data, kv->id, 0), kv->num, kv->num2);
-      break;
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      if (!kv->entry)
-        printf("%s:\n%*s", keyname, indent, "");
-      printf("  %s\n", repodata_dir2str(data, kv->id, kv->str));
-      break;
-    case REPOKEY_TYPE_FIXARRAY:
-    case REPOKEY_TYPE_FLEXARRAY:
-      if (!kv->entry)
-        printf("%s:\n", keyname);
-      else
-        printf("\n");
-      break;
-    default:
-      if (solv_chksum_len(key->type))
-       {
-         printf("%s: %s (%s)\n", keyname, repodata_chk2str(data, key->type, (unsigned char *)kv->str), solv_chksum_type2str(key->type));
-         break;
-       }
-      printf("%s: ?\n", keyname);
-      break;
-    }
-  return 0;
-}
-
-static const char *
-jsonstring(Pool *pool, const char *s)
-{
-  int needed = 0;
-  const unsigned char *s1;
-  char *r, *rp;
-  
-  for (s1 = (const unsigned char *)s; *s1; s1++)
-    {
-      if (*s1 < 32)
-       needed += *s1 == '\n' ? 2 : 6;
-      else if (*s1 == '\\' || *s1 == '\"')
-       needed += 2;
-      else
-       needed++;
-    }
-  r = rp = pool_alloctmpspace(pool, needed + 3);
-  *rp++ = '\"';
-  for (s1 = (const unsigned char *)s; *s1; s1++)
-    {
-      if (*s1 < 32)
-       {
-         int x;
-         if (*s1 == '\n')
-           {
-             *rp++ = '\\';
-             *rp++ = 'n';
-             continue;
-           }
-         *rp++ = '\\';
-         *rp++ = 'u';
-         *rp++ = '0';
-         *rp++ = '0';
-         x = *s1 / 16;
-         *rp++ = (x < 10 ? '0' : 'a' - 10) + x;
-         x = *s1 & 15;
-         *rp++ = (x < 10 ? '0' : 'a' - 10) + x;
-       }
-      else if (*s1 == '\\' || *s1 == '\"')
-       {
-         *rp++ = '\\';
-         *rp++ = *s1;
-       }
-      else
-        *rp++ = *s1;
-    }
-  *rp++ = '\"';
-  *rp = 0;
-  return r;
-}
-
-struct cbdata {
-  unsigned char *first;
-  int nfirst;
-  int baseindent;
-};
-
-static int
-dump_attr_json(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv, struct cbdata *cbdata)
-{
-  Pool *pool = repo->pool;
-  const char *keyname;
-  KeyValue *kvp;
-  int indent = cbdata->baseindent;
-  int isarray = 0;
-  const char *str;
-  int depth = 0;
-
-  keyname = pool_id2str(repo->pool, key->name);
-  for (kvp = kv; (kvp = kvp->parent) != 0; indent += 4)
-    depth++;
-  if (cbdata->nfirst < depth + 1)
-    {
-      cbdata->first = solv_realloc(cbdata->first, depth + 16);
-      memset(cbdata->first + cbdata->nfirst, 0, depth + 16 - cbdata->nfirst);
-      cbdata->nfirst = depth + 16;
-    }
-  switch(key->type)
-    {
-    case REPOKEY_TYPE_IDARRAY:
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      isarray = 1;
-      break;
-    case REPOKEY_TYPE_FIXARRAY:
-    case REPOKEY_TYPE_FLEXARRAY:
-      isarray = 2;
-      break;
-    default:
-      break;
-    }
-  if (!isarray || !kv->entry)
-    {
-      if (cbdata->first[depth])
-       printf(",\n");
-      printf("%*s%s: ", indent, "", jsonstring(pool, keyname));
-      cbdata->first[depth] = 1;
-    }
-  if (isarray == 1 && !kv->entry)
-    printf("[\n%*s", indent + 2, "");
-  else if (isarray == 1 && kv->entry)
-    printf("%*s", indent + 2, "");
-  switch(key->type)
-    {
-    case REPOKEY_TYPE_ID:
-      if (data && data->localpool)
-       str = stringpool_id2str(&data->spool, kv->id);
-      else
-       str = pool_dep2str(repo->pool, kv->id);
-      printf("%s", jsonstring(pool, str));
-      break;
-    case REPOKEY_TYPE_CONSTANTID:
-      str = pool_dep2str(repo->pool, kv->id);
-      printf("%s", jsonstring(pool, str));
-      break;
-    case REPOKEY_TYPE_IDARRAY:
-      if (data && data->localpool)
-        str = stringpool_id2str(&data->spool, kv->id);
-      else
-        str = pool_dep2str(repo->pool, kv->id);
-      printf("%s", jsonstring(pool, str));
-      break;
-    case REPOKEY_TYPE_STR:
-      str = kv->str;
-      printf("%s", jsonstring(pool, str));
-      break;
-    case REPOKEY_TYPE_VOID:
-      printf("null");
-      break;
-    case REPOKEY_TYPE_U32:
-    case REPOKEY_TYPE_CONSTANT:
-      printf("%u", kv->num);
-      break;
-    case REPOKEY_TYPE_NUM:
-      printf("%llu", SOLV_KV_NUM64(kv));
-      break;
-    case REPOKEY_TYPE_BINARY:
-      printf("\"<binary>\"");
-      break;
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      printf("{\n");
-      printf("%*s    \"dir\": %s,\n", indent, "", jsonstring(pool, repodata_dir2str(data, kv->id, 0)));
-      printf("%*s    \"num1\": %u,\n", indent, "", kv->num);
-      printf("%*s    \"num2\": %u\n", indent, "", kv->num2);
-      printf("%*s  }", indent, "");
-      break;
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      printf("%s", jsonstring(pool, repodata_dir2str(data, kv->id, kv->str)));
-      break;
-    case REPOKEY_TYPE_FIXARRAY:
-    case REPOKEY_TYPE_FLEXARRAY:
-      cbdata->first[depth + 1] = 0;
-      if (!kv->entry)
-       printf("[\n");
-      else
-       {
-         if (kv->eof != 2)
-            printf("\n%*s  },\n", indent, "");
-         else
-            printf("\n%*s  }\n", indent, "");
-       }
-      if (kv->eof != 2)
-        printf("%*s  {\n", indent, "");
-      else
-        printf("%*s]", indent, "");
-      break;
-    default:
-      if (solv_chksum_len(key->type))
-       {
-         printf("{\n");
-         printf("%*s  \"value\": %s,\n", indent, "", jsonstring(pool, repodata_chk2str(data, key->type, (unsigned char *)kv->str)));
-         printf("%*s  \"type\": %s\n", indent, "", jsonstring(pool, solv_chksum_type2str(key->type)));
-         printf("%*s}", indent, "");
-         break;
-       }
-      printf("\"?\"");
-      break;
-    }
-  if (isarray == 1)
-    {
-      if (!kv->eof)
-        printf(",\n");
-      else
-        printf("\n%*s]", indent, "");
-    }
-  return 0;
-}
-
-static int
-dump_repodata_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  if (key->name == REPOSITORY_SOLVABLES)
-    return SEARCH_NEXT_SOLVABLE;
-  if (!dump_json)
-    return dump_attr(data->repo, data, key, kv);
-  else
-    return dump_attr_json(data->repo, data, key, kv, vcbdata);
-}
-
-static void
-dump_repodata(Repo *repo)
-{
-  int i;
-  Repodata *data;
-  if (repo->nrepodata == 0)
-    return;
-  printf("repo contains %d repodata sections:\n", repo->nrepodata - 1);
-  FOR_REPODATAS(repo, i, data)
-    {
-      unsigned int j;
-      printf("\nrepodata %d has %d keys, %d schemata\n", i, data->nkeys - 1, data->nschemata - 1);
-      for (j = 1; j < data->nkeys; j++)
-       printf("  %s (type %s size %d storage %d)\n", pool_id2str(repo->pool, data->keys[j].name), pool_id2str(repo->pool, data->keys[j].type), data->keys[j].size, data->keys[j].storage);
-      if (data->localpool)
-       printf("  localpool has %d strings, size is %d\n", data->spool.nstrings, data->spool.sstrings);
-      if (data->dirpool.ndirs)
-       printf("  localpool has %d directories\n", data->dirpool.ndirs);
-      printf("\n");
-      repodata_search(data, SOLVID_META, 0, SEARCH_ARRAYSENTINEL|SEARCH_SUB, dump_repodata_cb, 0);
-    }
-  printf("\n");
-}
-
-static void
-dump_repodata_json(Repo *repo, struct cbdata *cbdata)
-{
-  int i;
-  Repodata *data;
-  if (repo->nrepodata == 0)
-    return;
-  cbdata->baseindent = 6;
-  FOR_REPODATAS(repo, i, data)
-    repodata_search(data, SOLVID_META, 0, SEARCH_ARRAYSENTINEL|SEARCH_SUB, dump_repodata_cb, cbdata);
-}
-
-/*
- * dump all attributes for Id <p>
- */
-
-void
-dump_solvable(Repo *repo, Id p, struct cbdata *cbdata)
-{
-  Dataiterator di;
-  dataiterator_init(&di, repo->pool, repo, p, 0, 0, SEARCH_ARRAYSENTINEL|SEARCH_SUB);
-  if (cbdata && cbdata->first)
-    cbdata->first[0] = 0;
-  if (cbdata)
-    cbdata->baseindent = 10;
-  while (dataiterator_step(&di))
-    {
-      if (!dump_json)
-        dump_attr(repo, di.data, di.key, &di.kv);
-      else
-        dump_attr_json(repo, di.data, di.key, &di.kv, cbdata);
-    }
-  dataiterator_free(&di);
-}
-
-static int
-loadcallback(Pool *pool, Repodata *data, void *vdata)
-{
-  FILE *fp = 0;
-  int r;
-  const char *location;
-
-  location = repodata_lookup_str(data, SOLVID_META, REPOSITORY_LOCATION);
-  if (!location || !with_attr)
-    return 0;
-  fprintf(stderr, "[Loading SOLV file %s]\n", location);
-  fp = fopen (location, "r");
-  if (!fp)
-    {
-      perror(location);
-      return 0;
-    }
-  r = repo_add_solv(data->repo, fp, REPO_USE_LOADING|REPO_LOCALPOOL);
-  fclose(fp);
-  return !r ? 1 : 0;
-}
-
-
-static void
-usage(int status)
-{
-  fprintf( stderr, "\nUsage:\n"
-          "dumpsolv [-a] [-j] [<solvfile>]\n"
-          "  -a  read attributes.\n"
-          "  -j  dump json format.\n"
-          );
-  exit(status);
-}
-
-int main(int argc, char **argv)
-{
-  Repo *repo;
-  Pool *pool;
-  int c, i, j, n;
-  Solvable *s;
-  
-  pool = pool_create();
-  pool_setloadcallback(pool, loadcallback, 0);
-
-  while ((c = getopt(argc, argv, "haj")) >= 0)
-    {
-      switch(c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'a':
-         with_attr = 1;
-         break;
-       case 'j':
-         dump_json = 1;
-         break;
-       default:
-          usage(1);
-          break;
-       }
-    }
-  if (!dump_json)
-    pool_setdebuglevel(pool, 1);
-  if (dump_json)
-    pool->debugmask |= SOLV_DEBUG_TO_STDERR;
-  for (; optind < argc; optind++)
-    {
-      if (freopen(argv[optind], "r", stdin) == 0)
-       {
-         perror(argv[optind]);
-         exit(1);
-       }
-      repo = repo_create(pool, argv[optind]);
-      if (repo_add_solv(repo, stdin, 0))
-       {
-         fprintf(stderr, "could not read repository: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-  if (!pool->urepos)
-    {
-      repo = repo_create(pool, argc != 1 ? argv[1] : "<stdin>");
-      if (repo_add_solv(repo, stdin, 0))
-       {
-         fprintf(stderr, "could not read repository: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-
-  if (dump_json)
-    {
-      int openrepo = 0;
-      struct cbdata cbdata;
-
-      memset(&cbdata, 0, sizeof(cbdata));
-      printf("{\n");
-      printf("  \"repositories\": [\n");
-      FOR_REPOS(j, repo)
-       {
-         int open = 0;
-
-         if (openrepo)
-           printf("\n    },");
-         printf("    {\n");
-         openrepo = 1;
-         if (cbdata.first)
-           cbdata.first[0] = 0;
-         dump_repodata_json(repo, &cbdata);
-         if (cbdata.first[0])
-           printf(",\n");
-         printf("      \"solvables\": [\n");
-         FOR_REPO_SOLVABLES(repo, i, s)
-           {
-             if (open)
-               printf("\n        },\n");
-             printf("        {\n");
-             open = 1;
-             dump_solvable(repo, i, &cbdata);
-           }
-         if (open)
-           printf("\n        }\n");
-         printf("      ]\n");
-       }
-      if (openrepo)
-       printf("    }\n");
-      printf("  ]\n");
-      printf("}\n");
-      solv_free(cbdata.first);
-    }
-  else
-    {
-      printf("pool contains %d strings, %d rels, string size is %d\n", pool->ss.nstrings, pool->nrels, pool->ss.sstrings);
-      n = 0;
-      FOR_REPOS(j, repo)
-       {
-         dump_repodata(repo);
-         printf("repo %d contains %d solvables\n", j, repo->nsolvables);
-         printf("repo start: %d end: %d\n", repo->start, repo->end);
-         FOR_REPO_SOLVABLES(repo, i, s)
-           {
-             n++;
-             printf("\n");
-             printf("solvable %d (%d):\n", n, i);
-             dump_solvable(repo, i, 0);
-           }
-       }
-    }
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/findfileconflicts.c b/libsolv-0.6.15/tools/findfileconflicts.c
deleted file mode 100644 (file)
index 712602d..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* vim: sw=2 et
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "solver.h"
-#include "solverdebug.h"
-#include "hash.h"
-#include "repo_rpmdb.h"
-#include "pool_fileconflicts.h"
-
-static void *
-iterate_handle(Pool *pool, Id p, void *cbdata)
-{
-  Solvable *s = pool->solvables + p;
-  Id rpmdbid;
-  void *handle;
-  
-  if (!s->repo->rpmdbid)
-    return 0;
-  rpmdbid = s->repo->rpmdbid[p - s->repo->start];
-  if (!rpmdbid)
-    return 0;
-  handle = rpm_byrpmdbid(cbdata, rpmdbid);
-  if (!handle)
-    fprintf(stderr, "rpm_byrpmdbid: %s\n", pool_errstr(pool));
-  return handle;
-}
-
-int main(int argc, char **argv)
-{
-  Pool *pool;
-  Repo *installed;
-  Solvable *s;
-  Id p;
-  int i;
-  Queue todo, conflicts;
-  void *state = 0;
-  char *rootdir = 0;
-  if (argc == 3 && !strcmp(argv[1], "--root"))
-    rootdir = argv[2];
-  pool = pool_create();
-  if (rootdir)
-    pool_set_rootdir(pool, rootdir);
-  pool_setdebuglevel(pool, 1);
-  installed = repo_create(pool, "@System");
-  pool_set_installed(pool, installed);
-  if (repo_add_rpmdb(installed, 0, REPO_USE_ROOTDIR))
-    {
-      fprintf(stderr, "findfileconflicts: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  queue_init(&todo);
-  queue_init(&conflicts);
-  FOR_REPO_SOLVABLES(installed, p, s)
-    queue_push(&todo, p);
-  state = rpm_state_create(pool, pool_get_rootdir(pool));
-  pool_findfileconflicts(pool, &todo, 0, &conflicts, FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, &iterate_handle, state);
-  rpm_state_free(state);
-  queue_free(&todo);
-  for (i = 0; i < conflicts.count; i += 6)
-    {
-      if (conflicts.elements[i] != conflicts.elements[i + 3])
-        printf("%s - %s: %s[%s] %s[%s]\n", pool_id2str(pool, conflicts.elements[i]), pool_id2str(pool, conflicts.elements[i + 3]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_id2str(pool, conflicts.elements[i + 2]), pool_solvid2str(pool, conflicts.elements[i + 4]), pool_id2str(pool, conflicts.elements[i + 5]));
-      else
-        printf("%s: %s[%s] %s[%s]\n", pool_id2str(pool, conflicts.elements[i]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_id2str(pool, conflicts.elements[i + 2]), pool_solvid2str(pool, conflicts.elements[i + 4]), pool_id2str(pool, conflicts.elements[i + 5]));
-    }
-  if (conflicts.count)
-    {
-      Queue job;
-      int problemcnt;
-
-      queue_init(&job);
-      pool_add_fileconflicts_deps(pool, &conflicts);
-      pool_addfileprovides(pool);
-      pool_createwhatprovides(pool);
-      pool_setdebuglevel(pool, 0);
-      Solver *solv = solver_create(pool);
-      queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0);
-#if 0
-      solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
-#endif
-      problemcnt = solver_solve(solv, &job);
-      if (problemcnt)
-        solver_printallsolutions(solv);
-      else
-       {
-         Transaction *trans = solver_create_transaction(solv);
-          transaction_print(trans);
-          transaction_free(trans);
-       }
-      queue_free(&job);
-      solver_free(solv);
-    }
-  queue_free(&conflicts);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/helix2solv.c b/libsolv-0.6.15/tools/helix2solv.c
deleted file mode 100644 (file)
index d893fb1..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * helix2solv.c
- * 
- * parse 'helix' type xml and write out .solv file
- *
- * reads from stdin
- * writes to stdout
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "pool.h"
-#include "repo_helix.h"
-#include "common_write.h"
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-  if (repo_add_helix(repo, stdin, 0))
-    {
-      fprintf(stderr, "helix2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  tool_write(repo, 0, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/installcheck.c b/libsolv-0.6.15/tools/installcheck.c
deleted file mode 100644 (file)
index e8be171..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/* vim: sw=2 et cino=>4,n-2,{1s
- */
-
-/*
- * Copyright (c) 2009-2015, SUSE LLC
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <zlib.h>
-
-#include "pool.h"
-#include "poolarch.h"
-#include "repo_solv.h"
-#ifdef ENABLE_SUSEREPO
-#include "repo_susetags.h"
-#endif
-#ifdef ENABLE_RPMMD
-#include "repo_rpmmd.h"
-#endif
-#ifdef ENABLE_DEBIAN
-#include "repo_deb.h"
-#endif
-#ifdef ENABLE_ARCHREPO
-#include "repo_arch.h"
-#endif
-#include "solver.h"
-#include "solv_xfopen.h"
-
-
-void
-usage(char** argv)
-{
-  printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
-         "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
-         "packagenames to ignore\n"
-         "\t--withobsoletes\t\tCheck for obsoletes on packages contained in repos\n"
-         "\t--nocheck\t\tDo not warn about all following repos (only use them to fulfill dependencies)\n"
-         "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
-         , argv[0]);
-  exit(1);
-}
-
-static int
-strlen_comp(const char *str)
-{
-  size_t l = strlen(str);
-  if (l > 3 && !strcmp(str + l - 3, ".gz"))
-    return l - 3;
-  if (l > 3 && !strcmp(str + l - 3, ".xz"))
-    return l - 3;
-  if (l > 4 && !strcmp(str + l - 4, ".bz2"))
-    return l - 4;
-  if (l > 5 && !strcmp(str + l - 4, ".lzma"))
-    return l - 5;
-  return l;
-}
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool;
-  Solver *solv;
-  Repo *repo;
-  Queue job;
-  Queue rids;
-  Queue cand;
-  char *arch, *exclude_pat;
-  int i, j;
-  Id p;
-  Id archid, noarchid;
-  Id rpmrel;
-#ifndef DEBIAN
-  Id rpmid;
-#endif
-  int status = 0;
-  int nocheck = 0;
-  int withsrc = 0;
-  int obsoletepkgcheck = 0;
-
-  exclude_pat = 0;
-  if (argc < 3)
-    usage(argv);
-
-  arch = argv[1];
-  pool = pool_create();
-  pool_setarch(pool, arch);
-  noarchid = pool->solvables[SYSTEMSOLVABLE].arch;
-  for (i = 2; i < argc; i++)
-    {
-      FILE *fp;
-      int r, l;
-
-      if (!strcmp(argv[i], "--withsrc"))
-       {
-         withsrc++;
-         continue;
-       }
-      if (!strcmp(argv[i], "--withobsoletes"))
-        {
-          obsoletepkgcheck++;
-          continue;
-        }
-      if (!strcmp(argv[i], "--nocheck"))
-       {
-         if (!nocheck)
-           nocheck = pool->nsolvables;
-         continue;
-       }
-      if (!strcmp(argv[i], "--exclude"))
-        {
-          if (i + 1 >= argc)
-            {
-              printf("--exclude needs a whitespace separated list of substrings as parameter\n");
-              exit(1);
-            }
-          exclude_pat = argv[i + 1];
-          ++i;
-          continue;
-        }
-      l = strlen_comp(argv[i]);
-      if (!strcmp(argv[i], "-"))
-       fp = stdin;
-      else if ((fp = solv_xfopen(argv[i], 0)) == 0)
-       {
-         perror(argv[i]);
-         exit(1);
-       }
-      repo = repo_create(pool, argv[i]);
-      r = 0;
-      if (0)
-        {
-        }
-#ifdef ENABLE_SUSEREPO
-      else if (l >= 8 && !strncmp(argv[i] + l - 8, "packages", 8))
-       {
-         r = repo_add_susetags(repo, fp, 0, 0, 0);
-       }
-#endif
-#ifdef ENABLE_RPMMD
-      else if (l >= 11 && !strncmp(argv[i] + l - 11, "primary.xml", 11))
-       {
-         r = repo_add_rpmmd(repo, fp, 0, 0);
-          if (!r && i + 1 < argc)
-            {
-              l = strlen_comp(argv[i + 1]);
-              if (l >= 13 && !strncmp(argv[i + 1] + l - 13, "filelists.xml", 13))
-                {
-                  i++;
-                  fclose(fp);
-                  if ((fp = solv_xfopen(argv[i], 0)) == 0)
-                    {
-                      perror(argv[i]);
-                      exit(1);
-                    }
-                  r = repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
-                }
-            }
-       }
-#endif
-#ifdef ENABLE_DEBIAN
-      else if (l >= 8 && !strncmp(argv[i] + l - 8, "Packages", 8))
-       {
-         r = repo_add_debpackages(repo, fp, 0);
-       }
-#endif
-#ifdef ENABLE_ARCHREPO
-      else if (l >= 7 && (!strncmp(argv[i] + l - 7, ".db.tar", 7)))
-        {
-         r = repo_add_arch_repo(repo, fp, 0);
-        }
-#endif
-      else
-       r = repo_add_solv(repo, fp, 0);
-      if (r)
-       {
-         fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool));
-         exit(1);
-       }
-      if (fp != stdin)
-        fclose(fp);
-    }
-  pool_addfileprovides(pool);
-  pool_createwhatprovides(pool);
-  archid = pool_str2id(pool, arch, 0);
-#ifndef DEBIAN
-  rpmid = pool_str2id(pool, "rpm", 0);
-  rpmrel = 0;
-  if (rpmid && archid)
-    {
-      for (p = 1; p < pool->nsolvables; p++)
-       {
-         Solvable *s = pool->solvables + p;
-         if (s->name == rpmid && s->arch == archid && pool_installable(pool, s))
-           break;
-       }
-      if (p < pool->nsolvables)
-        rpmrel = pool_rel2id(pool, rpmid, archid, REL_ARCH, 1);
-    }
-#else
-  rpmrel = 0;
-#endif
-  
-  queue_init(&job);
-  queue_init(&rids);
-  queue_init(&cand);
-  for (p = 1; p < (nocheck ? nocheck : pool->nsolvables); p++)
-    {
-      Solvable *s = pool->solvables + p;
-      if (!s->repo)
-       continue;
-      if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
-       {
-         queue_push(&cand, p);
-         continue;
-       }
-      if (!pool_installable(pool, s))
-       continue;
-      if (archid && s->arch != archid && s->arch != noarchid)
-       {
-         /* check if we will conflict with a infarch rule, if yes,
-          * don't bother checking the package */
-         Id rp, rpp;
-         FOR_PROVIDES(rp, rpp, s->name)
-           {
-             if (pool->solvables[rp].name != s->name)
-               continue;
-             if (pool->solvables[rp].arch == archid)
-               break;
-           }
-         if (rp)
-           continue;
-       }
-      queue_push(&cand, p);
-    }
-  if (obsoletepkgcheck)
-    {
-      int obsoleteusesprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
-      int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
-
-      for (i = 0; i < cand.count; i++)
-       {
-         Solvable *s;
-         s = pool->solvables + cand.elements[i];
-
-         if (s->obsoletes)
-           {
-             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
-
-             while ((obs = *obsp++) != 0)
-               {
-                 Id op, opp;
-                 FOR_PROVIDES(op, opp, obs)
-                   {
-                     Solvable *os = pool->solvables + op;
-                     if (nocheck && op >= nocheck)
-                       continue;
-                     if (solvable_identical(s, os))
-                       continue;
-                     if (!obsoleteusesprovides && !pool_match_nevr(pool, os, obs))
-                       continue;
-                     if (obsoleteusescolors && !pool_colormatch(pool, s, os))
-                       continue;
-                     status = 2;
-                     printf("can't install %s:\n", pool_solvid2str(pool, op));
-                     printf("  package is obsoleted by %s\n", pool_solvable2str(pool, s));
-                   }
-               }
-           }
-       }
-    }
-
-  solv = solver_create(pool);
-
-  /* prune cand by doing weak installs */
-  while (cand.count)
-    {
-      queue_empty(&job);
-      for (i = 0; i < cand.count; i++)
-       {
-         p = cand.elements[i];
-         queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK, p);
-       }
-      if (rpmrel)
-       queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
-      solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
-      solver_solve(solv, &job);
-      /* prune... */
-      for (i = j = 0; i < cand.count; i++)
-       {
-         p = cand.elements[i];
-         if (solver_get_decisionlevel(solv, p) <= 0)
-           {
-             cand.elements[j++] = p;
-             continue;
-           }
-       }
-      cand.count = j;
-      if (i == j)
-       break;
-    }
-
-  /* now check every candidate */
-  for (i = 0; i < cand.count; i++)
-    {
-      Solvable *s;
-      int problemcount;
-
-      p = cand.elements[i];
-      if (exclude_pat)
-        {
-          char *ptr, *save = 0, *pattern;
-          int match = 0;
-          pattern = solv_strdup(exclude_pat);
-
-          for (ptr = strtok_r(pattern, " ", &save);
-              ptr;
-              ptr = strtok_r(NULL, " ", &save))
-            {
-              if (*ptr && strstr(pool_solvid2str(pool, p), ptr))
-                {
-                  match = 1;
-                  break;
-                }
-            }
-          solv_free(pattern);
-          if (match)
-            continue;
-        }
-      s = pool->solvables + p;
-      queue_empty(&job);
-      queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE, p);
-      if (rpmrel)
-       queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
-      solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
-      problemcount = solver_solve(solv, &job);
-      if (problemcount)
-       {
-         Id problem = 0;
-         Solvable *s2;
-
-         status = 1;
-         printf("can't install %s:\n", pool_solvable2str(pool, s));
-         while ((problem = solver_next_problem(solv, problem)) != 0)
-           {
-             solver_findallproblemrules(solv, problem, &rids);
-             for (j = 0; j < rids.count; j++)
-               {
-                 Id probr = rids.elements[j];
-                 int k;
-                 Queue rinfo;
-                 queue_init(&rinfo);
-
-                 solver_allruleinfos(solv, probr, &rinfo);
-                 for (k = 0; k < rinfo.count; k += 4)
-                   {
-                     Id dep, source, target;
-                     source = rinfo.elements[k + 1];
-                     target = rinfo.elements[k + 2];
-                     dep = rinfo.elements[k + 3];
-                     switch (rinfo.elements[k])
-                       {
-                       case SOLVER_RULE_DISTUPGRADE:
-                         break;
-                       case SOLVER_RULE_INFARCH:
-                         s = pool_id2solvable(pool, source);
-                         printf("  %s has inferior architecture\n", pool_solvable2str(pool, s));
-                         break;
-                       case SOLVER_RULE_UPDATE:
-                         s = pool_id2solvable(pool, source);
-                         printf("  %s can not be updated\n", pool_solvable2str(pool, s));
-                         break;
-                       case SOLVER_RULE_JOB:
-                       case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
-                       case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
-                       case SOLVER_RULE_JOB_UNSUPPORTED:
-                         break;
-                       case SOLVER_RULE_RPM:
-                         printf("  some dependency problem\n");
-                         break;
-                       case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
-                         printf("  nothing provides requested %s\n", pool_dep2str(pool, dep));
-                         break;
-                       case SOLVER_RULE_RPM_NOT_INSTALLABLE:
-                         s = pool_id2solvable(pool, source);
-                         printf("  package %s is not installable\n", pool_solvable2str(pool, s));
-                         break;
-                       case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
-                         s = pool_id2solvable(pool, source);
-                         printf("  nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvable2str(pool, s));
-                         if (ISRELDEP(dep))
-                           {
-                             Reldep *rd = GETRELDEP(pool, dep);
-                             if (!ISRELDEP(rd->name))
-                               {
-                                 Id rp, rpp;
-                                 FOR_PROVIDES(rp, rpp, rd->name)
-                                   printf("    (we have %s)\n", pool_solvable2str(pool, pool->solvables + rp));
-                               }
-                           }
-                         break;
-                       case SOLVER_RULE_RPM_SAME_NAME:
-                         s = pool_id2solvable(pool, source);
-                         s2 = pool_id2solvable(pool, target);
-                         printf("  cannot install both %s and %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2));
-                         break;
-                       case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
-                         s = pool_id2solvable(pool, source);
-                         s2 = pool_id2solvable(pool, target);
-                         printf("  package %s conflicts with %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
-                         break;
-                       case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
-                         s = pool_id2solvable(pool, source);
-                         s2 = pool_id2solvable(pool, target);
-                         printf("  package %s obsoletes %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
-                         break;
-                       case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
-                         s = pool_id2solvable(pool, source);
-                         printf("  package %s requires %s, but none of the providers can be installed\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
-                         break;
-                       case SOLVER_RULE_RPM_SELF_CONFLICT:
-                         s = pool_id2solvable(pool, source);
-                         printf("  package %s conflicts with %s provided by itself\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
-                         break;
-                       }
-                   }
-               }
-           }
-       }
-    }
-  solver_free(solv);
-  exit(status);
-}
diff --git a/libsolv-0.6.15/tools/mdk2solv.c b/libsolv-0.6.15/tools/mdk2solv.c
deleted file mode 100644 (file)
index dcf9d6f..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2012, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * mdk2solv.c
- *
- * parse Mandriva/Mageie synthesis file
- *
- * reads from stdin
- * writes to stdout
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_mdk.h"
-#include "solv_xfopen.h"
-#include "common_write.h"
-
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "mdk2solv [-i <infoxml>]\n"
-          "  reads a 'synthesis' repository from <stdin> and writes a .solv file to <stdout>\n"
-          "  -i : info.xml file for extra attributes\n"
-          "  -f : files.xml file for extra attributes\n"
-          "  -h : print help & exit\n"
-         );
-   exit(status);
-}
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool;
-  Repo *repo;
-  char *infofile = 0, *filesfile = 0;
-  int c;
-
-  while ((c = getopt(argc, argv, "hi:f:")) >= 0)
-    {
-      switch(c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'i':
-         infofile = optarg;
-         break;
-       case 'f':
-         filesfile = optarg;
-         break;
-       default:
-         usage(1);
-         break;
-       }
-    }
-  pool = pool_create();
-  repo = repo_create(pool, "<stdin>");
-  if (repo_add_mdk(repo, stdin, REPO_NO_INTERNALIZE))
-    {
-      fprintf(stderr, "mdk2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  if (infofile)
-    {
-      FILE *fp = solv_xfopen(infofile, "r");
-      if (!fp)
-       {
-         perror(infofile);
-         exit(1);
-       }
-      if (repo_add_mdk_info(repo, fp, REPO_EXTEND_SOLVABLES | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-       {
-         fprintf(stderr, "mdk2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-      fclose(fp);
-    }
-  if (filesfile)
-    {
-      FILE *fp = solv_xfopen(filesfile, "r");
-      if (!fp)
-       {
-         perror(filesfile);
-         exit(1);
-       }
-      if (repo_add_mdk_info(repo, fp, REPO_EXTEND_SOLVABLES | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-       {
-         fprintf(stderr, "mdk2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-      fclose(fp);
-    }
-  repo_internalize(repo);
-  tool_write(repo, 0, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/mergesolv.c b/libsolv-0.6.15/tools/mergesolv.c
deleted file mode 100644 (file)
index 6719c8c..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * mergesolv
- * 
- */
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "pool.h"
-#include "repo_solv.h"
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-#include "common_write.h"
-
-static void
-usage()
-{
-  fprintf(stderr, "\nUsage:\n"
-         "mergesolv [file] [file] [...]\n"
-         "  merges multiple solv files into one and writes it to stdout\n"
-         );
-  exit(0);
-}
-
-static int
-loadcallback (Pool *pool, Repodata *data, void *vdata)
-{
-  FILE *fp;
-  const char *location = repodata_lookup_str(data, SOLVID_META, REPOSITORY_LOCATION);
-  int r;
-
-  if (!location)
-    return 0;
-  fprintf(stderr, "Loading SOLV file %s\n", location);
-  fp = fopen (location, "r");
-  if (!fp)
-    {
-      perror(location);
-      return 0;
-    }
-  r = repo_add_solv(data->repo, fp, REPO_USE_LOADING|REPO_LOCALPOOL);
-  fclose(fp);
-  return r ? 0 : 1;
-}
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool;
-  Repo *repo;
-  const char *basefile = 0;
-  int with_attr = 0;
-#ifdef SUSE
-  int add_auto = 0;
-#endif
-  int c;
-
-  pool = pool_create();
-  repo = repo_create(pool, "<mergesolv>");
-  
-  while ((c = getopt(argc, argv, "ahb:X")) >= 0)
-    {
-      switch (c)
-      {
-       case 'h':
-         usage();
-         break;
-       case 'a':
-         with_attr = 1;
-         break;
-       case 'b':
-         basefile = optarg;
-         break;
-       case 'X':
-#ifdef SUSE
-         add_auto = 1;
-#endif
-         break;
-       default:
-         usage();
-         exit(1);
-      }
-    }
-  if (with_attr)
-    pool_setloadcallback(pool, loadcallback, 0);
-
-  for (; optind < argc; optind++)
-    {
-      FILE *fp;
-      if ((fp = fopen(argv[optind], "r")) == NULL)
-       {
-         perror(argv[optind]);
-         exit(1);
-       }
-      if (repo_add_solv(repo, fp, 0))
-       {
-         fprintf(stderr, "repo %s: %s\n", argv[optind], pool_errstr(pool));
-         exit(1);
-       }
-      fclose(fp);
-    }
-#ifdef SUSE
-  if (add_auto)
-    repo_add_autopattern(repo, 0);
-#endif
-  tool_write(repo, basefile, 0);
-  pool_free(pool);
-  return 0;
-}
diff --git a/libsolv-0.6.15/tools/patchcheck.c b/libsolv-0.6.15/tools/patchcheck.c
deleted file mode 100644 (file)
index 6a5c3f7..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-/* vim: sw=2 et
- */
-
-/*
- * Copyright (c) 2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <zlib.h>
-
-#include "pool.h"
-#include "evr.h"
-#include "poolarch.h"
-#include "repo_solv.h"
-#ifdef ENABLE_SUSEREPO
-#include "repo_susetags.h"
-#endif
-#ifdef ENABLE_RPMMD
-#include "repo_updateinfoxml.h"
-#include "repo_rpmmd.h"
-#endif
-#include "solver.h"
-#include "solverdebug.h"
-
-#include "solv_xfopen.h"
-
-void
-showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys)
-{
-  Pool *pool = solv->pool;
-  Queue rids, rinfo;
-  Id problem = 0;
-  int jj;
-  int rerun = 0;
-
-  queue_init(&rids);
-  queue_init(&rinfo);
-  printf("can't install %s:\n", pool_solvable2str(pool, s));
-  while ((problem = solver_next_problem(solv, problem)) != 0)
-    {
-      solver_findallproblemrules(solv, problem, &rids);
-      for (jj = 0; jj < rids.count; jj++)
-       {
-         Id probr = rids.elements[jj];
-         int k, l;
-
-         queue_empty(&rinfo);
-         solver_allruleinfos(solv, probr, &rinfo);
-         for (k = 0; k < rinfo.count; k += 4)
-           {
-             Id dep, source, target;
-             source = rinfo.elements[k + 1];
-             target = rinfo.elements[k + 2];
-             dep = rinfo.elements[k + 3];
-             switch (rinfo.elements[k])
-               {
-               case SOLVER_RULE_DISTUPGRADE:
-                 break;
-               case SOLVER_RULE_INFARCH:
-                 printf("  %s has inferior architecture\n", pool_solvid2str(pool, source));
-                 break;
-               case SOLVER_RULE_UPDATE:
-                 printf("  update rule for %s\n", pool_solvid2str(pool, source));
-                 if (badguys)
-                   queue_pushunique(badguys, source);
-                 if (!cand)
-                   break;
-                 /* only drop update problem packages from cand so that we see all problems of this patch */
-                 for (l = 0; l < cand->count; l++)
-                   if (cand->elements[l] == source || cand->elements[l] == -source)
-                     break;
-                 if (l == cand->count)
-                   break;
-                 if (!rerun)
-                   {
-                     for (l = 0; l < cand->count; l++)
-                       if (cand->elements[l] < 0)
-                         cand->elements[l] = -cand->elements[l];
-                     rerun = 1;
-                   }
-                 for (l = 0; l < cand->count; l++)
-                   if (cand->elements[l] == source)
-                     {
-                       cand->elements[l] = -source;
-                     }
-                 break;
-               case SOLVER_RULE_JOB:
-               case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
-               case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
-               case SOLVER_RULE_JOB_UNSUPPORTED:
-                 break;
-               case SOLVER_RULE_RPM:
-                 printf("  some dependency problem\n");
-                 break;
-               case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
-                 printf("  nothing provides requested %s\n", pool_dep2str(pool, dep));
-                 break;
-               case SOLVER_RULE_RPM_NOT_INSTALLABLE:
-                 printf("  package %s is not installable\n", pool_solvid2str(pool, source));
-                 break;
-               case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
-                 printf("  nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, source));
-                 if (ISRELDEP(dep))
-                   {
-                     Reldep *rd = GETRELDEP(pool, dep);
-                     if (!ISRELDEP(rd->name))
-                       {
-                         Id rp, rpp;
-                         FOR_PROVIDES(rp, rpp, rd->name)
-                           printf("    (we have %s)\n", pool_solvid2str(pool, rp));
-                       }
-                   }
-                 break;
-               case SOLVER_RULE_RPM_SAME_NAME:
-                 printf("  cannot install both %s and %s\n", pool_solvid2str(pool, source), pool_solvid2str(pool, target));
-                 break;
-               case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
-                 printf("  package %s conflicts with %s provided by %s\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep), pool_solvid2str(pool, target));
-                 break;
-               case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
-                 printf("  package %s obsoletes %s provided by %s\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep), pool_solvid2str(pool, target));
-                 break;
-               case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
-                 printf("  package %s requires %s, but none of the providers can be installed\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep));
-                 break;
-               case SOLVER_RULE_RPM_SELF_CONFLICT:
-                 printf("  package %s conflicts with %s provided by itself\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep));
-                 break;
-               }
-           }
-       }
-    }
-  queue_free(&rids);
-  queue_free(&rinfo);
-}
-
-void
-toinst(Solver *solv, Repo *repo, Repo *instrepo)
-{
-  Pool *pool = solv->pool;
-  Queue q;
-  int k;
-  Id p;
-
-  queue_init(&q);
-  solver_get_decisionqueue(solv, &q);
-  for (k = 0; k < q.count; k++)
-    {
-      p = q.elements[k];
-      if (p < 0 || p == SYSTEMSOLVABLE)
-       continue;
-
-     /* printf(" toinstall %s\n", pool_solvid2str(pool, p));*/
-      /* oh my! */
-      pool->solvables[p].repo = instrepo;
-    }
-  queue_free(&q);
-}
-
-void
-dump_instrepo(Repo *instrepo, Pool *pool)
-{
-  Solvable *s;
-  Id p;
-
-  printf("instrepo..\n");
-  FOR_REPO_SOLVABLES(instrepo, p, s)
-    printf("  %s\n", pool_solvable2str(pool, s));
-  printf("done.\n");
-}
-
-void
-frominst(Solver *solv, Repo *repo, Repo *instrepo)
-{
-  Pool *pool = solv->pool;
-  int k;
-
-  for (k = 1; k < pool->nsolvables; k++)
-    if (pool->solvables[k].repo == instrepo)
-      pool->solvables[k].repo = repo;
-}
-
-void
-usage(char** argv)
-{
-
-  printf("%s: <arch> <patchnameprefix>  [--install-available] [repos] [--updaterepos] [repos]...\n"
-      "\t --install-available: installation repository is available during update\n"
-      "\t repos: repository ending in\n"
-      "\t\tpackages, packages.gz, primary.xml.gz, updateinfo.xml.gz or .solv\n",
-      argv[0]);
-
-  exit(1);
-}
-
-typedef struct {
-  int updatestart;
-  int shown;
-  int status;
-  int install_available;
-  Repo *repo;
-  Repo *instrepo;
-} context_t;
-
-#define SHOW_PATCH(c) if (!(c)->shown++) printf("%s:\n", pool_solvable2str(pool, s));
-#define PERF_DEBUGGING 0
-static Pool *pool;
-
-void
-test_all_old_patches_included(context_t *c, Id pid)
-{
-  Id p, pp;
-  Id con, *conp;
-  Solvable *s = pool->solvables + pid;
-  /* Test 1: are all old patches included */
-  FOR_PROVIDES(p, pp, s->name)
-    {
-      Solvable *s2 = pool->solvables + p;
-      Id con2, *conp2;
-
-      if (!s2->conflicts)
-        continue;
-      if (pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
-        continue;
-      conp2 = s2->repo->idarraydata + s2->conflicts;
-      while ((con2 = *conp2++) != 0)
-        {
-          Reldep *rd2, *rd;
-          if (!ISRELDEP(con2))
-            continue;
-          rd2 = GETRELDEP(pool, con2);
-          conp = s->repo->idarraydata + s->conflicts;
-          while ((con = *conp++) != 0)
-            {
-              if (!ISRELDEP(con))
-                continue;
-              rd = GETRELDEP(pool, con);
-              if (rd->name == rd2->name)
-                break;
-            }
-          if (!con)
-            {
-              SHOW_PATCH(c);
-              printf("  %s contained %s\n", pool_solvable2str(pool, s2), pool_dep2str(pool, rd2->name));
-            }
-          else
-           {
-             if (pool_evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0)
-               {
-                 SHOW_PATCH(c);
-                 printf("  %s required newer version %s-%s of %s-%s\n",
-                     pool_solvable2str(pool, s2), pool_dep2str(pool, rd2->name), pool_dep2str(pool, rd2->evr),
-                     pool_dep2str(pool, rd->name), pool_dep2str(pool, rd->evr));
-               }
-           }
-
-        }
-    }
-}
-
-void
-test_all_packages_installable(context_t *c, Id pid)
-{
-  Solver *solv;
-  Queue job;
-  Id p, pp;
-  Id con, *conp;
-  unsigned int now, solver_runs;
-  int i;
-  Solvable *s = pool->solvables + pid;
-
-  queue_init(&job);
-
-  now = solv_timems(0);
-  solver_runs = 0;
-
-  conp = s->repo->idarraydata + s->conflicts;
-  while ((con = *conp++) != 0)
-    {
-      FOR_PROVIDES(p, pp, con)
-        {
-          queue_empty(&job);
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
-          queue_push(&job, p);
-
-          /* also set up some minimal system */
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-          queue_push(&job, pool_str2id(pool, "rpm", 1));
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-          queue_push(&job, pool_str2id(pool, "aaa_base", 1));
-
-          solv = solver_create(pool);
-          /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */
-          ++solver_runs;
-          if (solver_solve(solv, &job))
-            {
-              c->status = 1;
-              printf("error installing original package\n");
-              showproblems(solv, s, 0, 0);
-            }
-          toinst(solv, c->repo, c->instrepo);
-          solver_free(solv);
-
-#if 0
-          dump_instrepo(instrepo, pool);
-
-#endif
-          if (!c->install_available)
-            {
-              queue_empty(&job);
-              for (i = 1; i < c->updatestart; i++)
-                {
-                  if (pool->solvables[i].repo != c->repo || i == pid)
-                    continue;
-                  queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
-                  queue_push(&job, i);
-                }
-            }
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
-          queue_push(&job, pid);
-          solv = solver_create(pool);
-          /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */
-          ++solver_runs;
-          if (solver_solve(solv, &job))
-            {
-              c->status = 1;
-              showproblems(solv, s, 0, 0);
-            }
-          frominst(solv, c->repo, c->instrepo);
-          solver_free(solv);
-        }
-    }
-
-  if (PERF_DEBUGGING)
-    printf("  test_all_packages_installable took %d ms in %d runs\n", solv_timems(now), solver_runs);
-}
-
-void
-test_can_upgrade_all_packages(context_t *c, Id pid)
-{
-  Solver *solv;
-  Id p;
-  Id con, *conp;
-  Queue job;
-  Queue cand;
-  Queue badguys;
-  int i, j;
-  unsigned int now, solver_runs;
-  Solvable *s = pool->solvables + pid;
-
-  queue_init(&job);
-  queue_init(&cand);
-  queue_init(&badguys);
-
-  now = solv_timems(0);
-  solver_runs = 0;
-
-  /* Test 3: can we upgrade all packages? */
-  for (p = 1; p < pool->nsolvables; p++)
-    {
-      Solvable *s = pool->solvables + p;
-      if (!s->repo)
-        continue;
-      if (strchr(pool_id2str(pool, s->name), ':'))
-        continue;      /* only packages, please */
-      if (!pool_installable(pool, s))
-        continue;
-      queue_push(&cand, p);
-    }
-  while (cand.count)
-    {
-      solv = solver_create(pool);
-      queue_empty(&job);
-      for (i = 0; i < badguys.count; i++)
-        {
-          queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
-          queue_push(&job, badguys.elements[i]);
-        }
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-        {
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-          queue_push(&job, con);
-        }
-      for (i = 0; i < cand.count; i++)
-        {
-          p = cand.elements[i];
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
-          queue_push(&job, p);
-        }
-      ++solver_runs;
-      solver_solve(solv, &job);
-#if 0
-      solver_printdecisions(solv);
-#endif
-      /* put packages into installed repo and prune them from cand */
-      toinst(solv, c->repo, c->instrepo);
-      for (i = 0; i < cand.count; i++)
-        {
-          p = cand.elements[i];
-          if (p > 0 && solver_get_decisionlevel(solv, p) > 0)
-            cand.elements[i] = -p;     /* drop candidate */
-        }
-      solver_free(solv);
-
-      /* now the interesting part: test patch */
-      queue_empty(&job);
-      if (!c->install_available)
-        {
-          for (i = 1; i < c->updatestart; i++)
-            {
-              if (pool->solvables[i].repo != c->repo || i == pid)
-                continue;
-              queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
-              queue_push(&job, i);
-            }
-        }
-      queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
-      queue_push(&job, pid);
-      solv = solver_create(pool);
-      solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
-      ++solver_runs;
-      if (solver_solve(solv, &job))
-        {
-          c->status = 1;
-          showproblems(solv, s, &cand, &badguys);
-        }
-      frominst(solv, c->repo, c->instrepo);
-      solver_free(solv);
-      /* now drop all negative elements from cand */
-      for (i = j = 0; i < cand.count; i++)
-        {
-          if (cand.elements[i] < 0)
-            continue;
-          cand.elements[j++] = cand.elements[i];
-        }
-      if (i == j)
-        break; /* no progress */
-      cand.count = j;
-    }
-  if (PERF_DEBUGGING)
-    printf("  test_can_upgrade_all_packages took %d ms in %d runs\n", solv_timems(now), solver_runs);
-}
-
-void
-test_no_ga_package_fulfills_dependency(context_t *c, Id pid)
-{
-  Id con, *conp;
-  Solvable *s = pool->solvables + pid;
-
-  /* Test 4: no GA package fulfills patch dependency */
-  conp = s->repo->idarraydata + s->conflicts;
-  while ((con = *conp++) != 0)
-    {
-      Reldep *rd;
-      Id rp, rpp;
-
-      if (!ISRELDEP(con))
-        continue;
-      rd = GETRELDEP(pool, con);
-      FOR_PROVIDES(rp, rpp, rd->name)
-        {
-          Solvable *s2 = pool_id2solvable(pool, rp);
-          if (rp < c->updatestart
-              && pool_evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0
-              && pool_match_nevr_rel(pool, s2, rd->name)
-             )
-            {
-              SHOW_PATCH(c);
-              printf("  conflict %s < %s satisfied by non-updated package %s\n",
-                  pool_dep2str(pool, rd->name), pool_dep2str(pool, rd->evr), pool_solvable2str(pool, s2));
-              break;
-            }
-        }
-    }
-}
-
-int
-main(int argc, char **argv)
-{
-  char *arch, *mypatch;
-  const char *pname;
-  int l, r;
-  FILE *fp;
-  int i;
-  Id pid, p, pp;
-  int tests = 0;
-  context_t c;
-  static const char* langs[] = {"en"};
-
-  c.install_available = 0;
-  c.updatestart = 0;
-  c.status = 0;
-
-  if (argc <= 3)
-    usage(argv);
-
-  arch = argv[1];
-  pool = pool_create();
-  pool_setarch(pool, arch);
-  pool_set_languages(pool, langs, 1);
-
-#if 0
-  pool_setdebuglevel(pool, 2);
-#endif
-
-  mypatch = argv[2];
-
-  c.repo = repo_create(pool, 0);
-  c.instrepo = repo_create(pool, 0);
-  for (i = 3; i < argc; i++)
-    {
-      if (!strcmp(argv[i], "--updaterepos"))
-       {
-         c.updatestart = pool->nsolvables;
-         continue;
-       }
-
-      if (!strcmp(argv[i], "--install-available"))
-       {
-         c.install_available = 1;
-         continue;
-       }
-      l = strlen(argv[i]);
-      if (!strcmp(argv[i], "-"))
-        fp = stdin;
-      else if ((fp = solv_xfopen(argv[i], 0)) == 0)
-        {
-          perror(argv[i]);
-          exit(1);
-        }
-      r = 0;
-      if (0)
-       {
-       }
-#ifdef ENABLE_SUSEREPO
-      else if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
-        {
-          r = repo_add_susetags(c.repo, fp, 0, 0, 0);
-        }
-      else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
-        {
-          r = repo_add_susetags(c.repo, fp, 0, 0, 0);
-        }
-#endif
-#ifdef ENABLE_RPMMD
-      else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
-        {
-          r = repo_add_rpmmd(c.repo, fp, 0, 0);
-        }
-      else if (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz"))
-       {
-          r = repo_add_updateinfoxml(c.repo, fp, 0);
-       }
-#endif
-      else
-       r = repo_add_solv(c.repo, fp, 0);
-      if (r)
-        {
-          fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool));
-          exit(1);
-        }
-      if (fp != stdin)
-        fclose(fp);
-    }
-
-  pool_addfileprovides(pool);
-
-  /* bad hack ahead: clone repo */
-  c.instrepo->idarraydata = c.repo->idarraydata;
-  c.instrepo->idarraysize = c.repo->idarraysize;
-  c.instrepo->start = c.repo->start;
-  c.instrepo->end = c.repo->end;
-  c.instrepo->nsolvables = c.repo->nsolvables; /* sic! */
-  pool_set_installed(pool, c.instrepo);
-  pool_createwhatprovides(pool);
-
-  for (pid = 1; pid < pool->nsolvables; pid++)
-    {
-      Solvable *s;
-      c.shown = 0;
-      s = pool->solvables + pid;
-      if (!s->repo)
-        continue;
-      if (!pool_installable(pool, s))
-        continue;
-      pname = pool_id2str(pool, s->name);
-      if (strncmp(pname, "patch:", 6) != 0)
-       continue;
-
-      if (*mypatch)
-       {
-         if (strncmp(mypatch, pname + 6, strlen(pname + 6)) != 0)
-           continue;
-         if (strcmp(mypatch, pname + 6) != 0)
-           {
-             l = strlen(pname + 6);
-             if (mypatch[l] != '-')
-               continue;
-             if (strcmp(mypatch + l + 1, pool_id2str(pool, s->evr)) != 0)
-               continue;
-           }
-       }
-      else
-       {
-         FOR_PROVIDES(p, pp, s->name)
-           {
-             Solvable *s2 = pool->solvables + p;
-             if (pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) < 0)
-               break;
-           }
-         if (p) {
-            /* printf("found a newer one for %s\n", pname+6); */
-           continue;   /* found a newer one */
-          }
-       }
-      tests++;
-      if (!s->conflicts)
-       continue;
-
-#if 0
-      printf("testing patch %s-%s\n", pname + 6, pool_id2str(pool, s->evr));
-#endif
-
-      test_all_old_patches_included(&c, pid);
-      test_all_packages_installable(&c, pid);
-      test_can_upgrade_all_packages(&c, pid);
-      test_no_ga_package_fulfills_dependency(&c, pid);
-    }
-
-  exit(c.status);
-}
diff --git a/libsolv-0.6.15/tools/repo2solv.sh b/libsolv-0.6.15/tools/repo2solv.sh
deleted file mode 100755 (executable)
index 11c6567..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-#! /bin/sh
-# repo2solv
-#
-# give it a directory of a local mirror of a repo and this
-# tries to detect the repo type and generate one SOLV file on stdout
-
-get_DESCRDIR () {
-  local d=$(grep '^DESCRDIR' content | sed 's/^DESCRDIR[[:space:]]\+\(.*[^[:space:]]\)[[:space:]]*$/\1/')
-  if  test -z "$d"; then
-    echo suse/setup/descr
-  else
-    echo ${d}
-  fi
-}
-
-test_susetags() {
-  if test -s content; then
-    DESCR=$(get_DESCRDIR)
-    test -d $DESCR
-    return $?
-  else
-    return 1
-  fi
-}
-
-repomd_findfile() {
-  local t=$1
-  local p=$2
-  local f
-  if test -n "$t" -a -s repomd.xml ; then
-    f=`repomdxml2solv -q $t:location < repomd.xml 2>/dev/null`
-    f=${f##*/}
-    if test -f "$f" ; then
-      echo "$f"
-      return
-    fi
-  fi
-  if test -f "$p.bz2" ; then
-    echo "$p.bz2"
-  elif test -f "$p.gz" ; then
-    echo "$p.gz"
-  elif test -f "$p" ; then
-    echo "$p"
-  fi
-}
-
-repomd_decompress() {
-  case $1 in
-   *.gz) gzip -dc "$1" ;;
-   *.bz2) bzip2 -dc "$1" ;;
-   *.lzma) lzma -dc "$1" ;;
-   *.xz) xz -dc "$1" ;;
-   *) cat "$1" ;;
-  esac
-}
-
-susetags_findfile() {
-  if test -s "$1.xz" ; then
-    echo "$1.xz"
-  elif test -s "$1.lzma" ; then
-    echo "$1.lzma"
-  elif test -s "$1.bz2" ; then
-    echo "$1.bz2"
-  elif test -s "$1.gz" ; then
-    echo "$1.gz"
-  fi
-}
-
-susetags_findfile_cat() {
-  if test -s "$1.xz" ; then
-    xz -dc "$1.xz"
-  elif test -s "$1.lzma" ; then
-    lzma -dc "$1.lzma"
-  elif test -s "$1.bz2" ; then
-    bzip2 -dc "$1.bz2"
-  elif test -s "$1.gz" ; then
-    gzip -dc "$1.gz"
-  elif test -s "$1" ; then
-    cat "$1"
-  fi
-}
-
-# signal an error if there is a problem
-set -e
-
-LANG=C
-unset CDPATH
-parser_options=${PARSER_OPTIONS:-}
-
-findopt="-prune"
-repotype=
-addautooption=
-
-while true ; do
-  if test "$1" = "-o" ; then
-    exec > "$2"
-    shift
-    shift
-  elif test "$1" = "-R" ; then
-    # recursive
-    findopt=
-    repotype=plaindir
-    shift
-  elif test "$1" = "-X" ; then
-    addautooption=-X
-    shift
-  elif test "$1" = "-A" ; then
-    shift
-  else
-    break
-  fi
-done
-
-dir="$1"
-cd "$dir" || exit 1
-
-if test -z "$repotype" ; then
-  # autodetect repository type
-  if test -d repodata -o -f repomd.xml; then
-    repotype=rpmmd
-  elif test_susetags ; then
-    repotype=susetags
-  else
-    repotype=plaindir
-  fi
-fi
-
-if test "$repotype" = rpmmd ; then
-  test -d repodata && {
-    cd repodata || exit 2
-  }
-
-  primfile=
-  primxml=`repomd_findfile primary primary.xml`
-  if test -n "$primxml" -a -s "$primxml" ; then
-    primfile=`mktemp` || exit 3
-    (
-     # fake tag to combine primary.xml and extensions
-     # like susedata.xml, other.xml, filelists.xml
-     echo '<rpmmd>'
-     if test -f $primxml ; then
-       repomd_decompress $primxml
-         # add a newline
-        echo
-     fi
-     susedataxml=`repomd_findfile susedata susedata.xml`
-     if test -f "$susedataxml" ; then
-       repomd_decompress "$susedataxml"
-     fi
-     echo '</rpmmd>'
-    ) | sed 's/<?xml[^>]*>//g' | sed '1i\<?xml version="1.0" encoding="UTF-8"?>' | rpmmd2solv $parser_options > $primfile || exit 4
-  fi
-
-  prodfile=
-  prodxml=`repomd_findfile products products.xml`
-  if test -z "$prodxml" ; then
-    prodxml=`repomd_findfile product product.xml`
-  fi
-  if test -n "$prodxml" -a -s "$prodxml" ; then
-      prodfile=`mktemp` || exit 3
-      repomd_decompress "$prodxml" | rpmmd2solv $parser_options > $prodfile || exit 4
-  fi
-
-  patternfile=
-  patternxml=`repomd_findfile 'patterns' patterns.xml`
-  if test -n "$patternxml" -a -s "$patternxml" ; then
-      patternfile=`mktemp` || exit 3
-      repomd_decompress "$patternxml" | rpmmd2solv $parser_options > $patternfile || exit 4
-  fi
-
-  # This contains repomd.xml
-  # for now we only read some keys like timestamp
-  repomdfile=
-  repomdxml=`repomd_findfile '' repomd.xml`
-  if test -n "$repomdxml" -a -s "$repomdxml" ; then
-      repomdfile=`mktemp` || exit 3
-      repomd_decompress "$repomdxml" | repomdxml2solv $parser_options > $repomdfile || exit 4
-  fi
-
-  # This contains suseinfo.xml, which is an extension to repomd.xml
-  # for now we only read some keys like expiration and products
-  suseinfofile=
-  suseinfoxml=`repomd_findfile suseinfo suseinfo.xml`
-  if test -n "$suseinfoxml" -a -s "$suseinfoxml" ; then
-      suseinfofile=`mktemp` || exit 3
-      repomd_decompress "$suseinfoxml" | repomdxml2solv $parser_options > $suseinfofile || exit 4
-  fi
-
-  # This contains a updateinfo.xml* and maybe patches
-  updateinfofile=
-  updateinfoxml=`repomd_findfile updateinfo updateinfo.xml`
-  if test -n "$updateinfoxml" -a -s "$updateinfoxml" ; then
-      updateinfofile=`mktemp` || exit 3
-      repomd_decompress "$updateinfoxml" | updateinfoxml2solv $parser_options > $updateinfofile || exit 4
-  fi
-
-  # This contains a deltainfo.xml*
-  deltainfofile=
-  deltainfoxml=`repomd_findfile deltainfo deltainfo.xml`
-  if test -z "$deltainfoxml"; then 
-      deltainfoxml=`repomd_findfile prestodelta prestodelta.xml`
-  fi
-  if test -n "$deltainfoxml" -a -s "$deltainfoxml" ; then
-      deltainfofile=`mktemp` || exit 3
-      repomd_decompress "$deltainfoxml" | deltainfoxml2solv $parser_options > $deltainfofile || exit 4
-  fi
-
-  # This contains appdata
-  appdataxml=
-  appdatafile=
-  if test -x /usr/bin/appdata2solv ; then
-      appdataxml=`repomd_findfile appdata appdata.xml`
-  fi
-  if test -n "$appdataxml" -a -s "$appdataxml" ; then
-      appdatafile=`mktemp` || exit 3
-      repomd_decompress "$appdataxml" | appdata2solv $parser_options > $appdatafile || exit 4
-  fi
-
-  # Now merge primary, patches, updateinfo, and deltainfo
-  mergesolv $addautooption $repomdfile $suseinfofile $primfile $prodfile $patternfile $updateinfofile $deltainfofile $appdatafile
-  rm -f $repomdfile $suseinfofile $primfile $patternfile $prodfile $updateinfofile $deltainfofile $appdatafile
-
-elif test "$repotype" = susetags ; then
-  olddir=`pwd`
-  DESCR=$(get_DESCRDIR)
-  cd ${DESCR} || exit 2
-  appdataxml=
-  appdatafile=
-  if test -x /usr/bin/appdata2solv ; then
-      appdataxml=`susetags_findfile appdata.xml`
-  fi
-  if test -n "$appdataxml" ; then
-      appdatafile=`mktemp` || exit 3
-      repomd_decompress "$appdataxml" | appdata2solv $parser_options > $appdatafile || exit 4
-      parser_options="-M $appdatafile $parser_options"
-  fi
-  (
-    # First packages
-    susetags_findfile_cat packages
-
-    # DU
-    susetags_findfile_cat packages.DU
-
-    # Now default language
-    susetags_findfile_cat packages.en
-
-    # Now patterns.  Not simply those files matching *.pat{,.gz,bz2},
-    # but only those mentioned in the file 'patterns'
-    if test -f patterns ; then
-      for i in `cat patterns`; do
-        if test -s "$i" ; then
-         repomd_decompress "$i"
-       fi
-      done
-    fi
-
-    # Now all other packages.{lang}.  Needs to come last as it switches
-    # languages for all following susetags files
-    for i in packages.* ; do
-      case $i in
-       *.gz|*.bz2|*.xz|*.lzma) name="${i%.*}" ;;
-       *) name="$i" ;;
-      esac
-      case $name in
-       # ignore files we handled already
-       *.DU | *.en | *.FL | packages ) continue ;;
-       *)
-         suff=${name#packages.}
-         echo "=Lan: $suff"
-         repomd_decompress "$i"
-      esac
-    done
-
-  ) | susetags2solv $addautooption -c "${olddir}/content" $parser_options || exit 4
-  test -n "$appdatafile" && rm -f "$appdatafile"
-  cd "$olddir"
-elif test "$repotype" = plaindir ; then
-  find * -name .\* -prune -o $findopt -name \*.delta.rpm -o -name \*.patch.rpm -o -name \*.rpm -a -type f -print0 | rpms2solv $addautooption -0 -m -
-else
-  echo "unknown repository type '$repotype'" >&2
-  exit 1
-fi
diff --git a/libsolv-0.6.15/tools/repomdxml2solv.c b/libsolv-0.6.15/tools/repomdxml2solv.c
deleted file mode 100644 (file)
index f32c35d..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2007-2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "chksum.h"
-#include "repo_repomdxml.h"
-#include "common_write.h"
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "repomdxml2solv [-q query]\n"
-         "  reads a 'repomd.xml' file from <stdin> and writes a .solv file to <stdout>\n"
-         "  -q : query a repomd data entry\n"
-         "  -h : print help & exit\n"
-        );
-   exit(status);
-}
-
-static void
-doquery(Pool *pool, Repo *repo, const char *query)
-{
-  Id id, type = 0;
-  char qbuf[256];
-  const char *qp;
-  Dataiterator di;
-
-  qp = strchr(query, ':');
-  if (qp)
-    {
-      type = pool_strn2id(pool, query, qp - query, 0);
-      if (!type)
-       exit(0);
-      qp++;
-    }
-  else
-    qp = query;
-  snprintf(qbuf, sizeof(qbuf), "repository:repomd:%s", qp);
-  id = pool_str2id(pool, qbuf, 0);
-  if (!id)
-    exit(0);
-  dataiterator_init(&di, pool, repo, SOLVID_META, id, 0, 0);
-  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
-  while (dataiterator_step(&di))
-    {
-      if (type)
-       {
-         dataiterator_setpos_parent(&di);
-         if (pool_lookup_id(pool, SOLVID_POS, REPOSITORY_REPOMD_TYPE) != type)
-           continue;
-       }
-      switch (di.key->type)
-       {
-       case REPOKEY_TYPE_ID:
-       case REPOKEY_TYPE_CONSTANTID:
-         printf("%s\n", pool_id2str(pool, di.kv.id));
-         break;
-       case REPOKEY_TYPE_STR:
-         printf("%s\n", di.kv.str);
-         break;
-       case REPOKEY_TYPE_NUM:
-       case REPOKEY_TYPE_CONSTANT:
-         printf("%llu\n", SOLV_KV_NUM64(&di.kv));
-         break;
-       default:
-         if (solv_chksum_len(di.key->type))
-           printf("%s:%s\n", solv_chksum_type2str(di.key->type), repodata_chk2str(di.data, di.key->type, (unsigned char *)di.kv.str));
-         break;
-       }
-    }
-  dataiterator_free(&di);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, flags = 0;
-  const char *query = 0;
-  
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-
-  while ((c = getopt (argc, argv, "hq:")) >= 0)
-    {
-      switch(c)
-        {
-        case 'h':
-          usage(0);
-          break;
-        case 'q':
-         query = optarg;
-          break;
-       default:
-          usage(1);
-          break;
-        }
-    }
-  if (repo_add_repomdxml(repo, stdin, flags))
-    {
-      fprintf(stderr, "repomdxml2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  if (query)
-    doquery(pool, repo, query);
-  else
-    tool_write(repo, 0, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/rpmdb2solv.c b/libsolv-0.6.15/tools/rpmdb2solv.c
deleted file mode 100644 (file)
index 3b1d41b..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * rpmdb2solv
- * 
- * Reads rpm database (and evtl. more, like product metadata) to build
- * a .solv file of 'installed' solvables.
- * Writes .solv to stdout
- * 
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_rpmdb.h"
-#ifdef ENABLE_PUBKEY
-#include "repo_pubkey.h"
-#endif
-#include "repo_products.h"
-#include "repo_solv.h"
-#include "common_write.h"
-#ifdef ENABLE_APPDATA
-#include "repo_appdata.h"
-#endif
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-         "rpmdb2solv [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
-         " -n : No packages, do not read rpmdb, useful to only parse products\n"
-         " -b <basefile> : Write .solv to <basefile>.solv instead of stdout\n"
-         " -p <productsdir> : Scan <productsdir> for .prod files, representing installed products\n"
-         " -r <root> : Prefix rpmdb path and <productsdir> with <root>\n"
-         " -o <solv> : Write .solv to file instead of stdout\n"
-        );
-  exit(status);
-}
-
-
-int
-main(int argc, char **argv)
-{
-  FILE *reffp = 0;
-  Pool *pool = pool_create();
-  Repo *repo;
-  Repodata *data;
-  int c, percent = 0;
-  int nopacks = 0;
-  const char *root = 0;
-  const char *basefile = 0;
-  const char *refname = 0;
-#ifdef ENABLE_SUSEREPO
-  char *proddir = 0;
-#endif
-  char *outfile = 0;
-#ifdef ENABLE_PUBKEY
-  int pubkeys = 0;
-#endif
-#ifdef ENABLE_APPDATA
-  int add_appdata = 0;
-#endif
-#ifdef SUSE
-  int add_auto = 0;
-#endif
-
-  /*
-   * parse arguments
-   */
-  
-  while ((c = getopt(argc, argv, "APhnkxXb:r:p:o:")) >= 0)
-    switch (c)
-      {
-      case 'h':
-         usage(0);
-       break;
-      case 'r':
-        root = optarg;
-        break;
-      case 'b':
-        basefile = optarg;
-        break;
-      case 'n':
-       nopacks = 1;
-       break;
-      case 'P':
-       percent = 1;
-       break;
-      case 'p':
-#ifdef ENABLE_SUSEREPO
-       proddir = optarg;
-#endif
-       break;
-      case 'x':
-        break; /* extrapool no longer supported */
-      case 'X':
-#ifdef SUSE
-       add_auto = 1;
-#endif
-       break;
-      case 'A':
-#ifdef ENABLE_APPDATA
-       add_appdata = 1;
-#endif
-       break;
-      case 'o':
-        outfile = optarg;
-        break;
-#ifdef ENABLE_PUBKEY
-      case 'k':
-        nopacks = 1;
-        pubkeys = 1;
-        break;
-#endif
-      default:
-       usage(1);
-      }
-  
-  if (outfile && !freopen(outfile, "w", stdout))
-    {
-      perror(outfile);
-      exit(1);
-    }
-    
-  /*
-   * optional arg is old version of rpmdb solv file
-   * should make this a real option instead
-   */
-  
-  if (optind < argc)
-    refname = argv[optind];
-
-  if (refname && !nopacks)
-    {
-      if ((reffp = fopen(refname, "r")) == NULL)
-        perror(refname);
-    }
-
-  /*
-   * create 'installed' repository
-   * add products
-   * add rpmdb
-   * write .solv
-   */
-
-  if (root && *root)
-    pool_set_rootdir(pool, root);
-
-  repo = repo_create(pool, "installed");
-  data = repo_add_repodata(repo, 0);
-
-  if (!nopacks)
-    {
-      if (repo_add_rpmdb_reffp(repo, reffp, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | (percent ? RPMDB_REPORT_PROGRESS : 0)))
-       {
-         fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-#ifdef ENABLE_PUBKEY
-  if (pubkeys)
-    {
-      if (repo_add_rpmdb_pubkeys(repo, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | ADD_WITH_KEYSIGNATURES))
-       {
-         fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-#endif
-
-#ifdef ENABLE_SUSEREPO
-  if (proddir && *proddir)
-    {
-      if (root && *root)
-       {
-         int rootlen = strlen(root);
-         if (!strncmp(root, proddir, rootlen))
-           {
-             proddir += rootlen;
-             if (*proddir != '/' && proddir[-1] == '/')
-               proddir--;
-           }
-       }
-      if (repo_add_products(repo, proddir, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-       {
-         fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-#endif
-
-#ifdef ENABLE_APPDATA
-  if (add_appdata)
-    repo_add_appdata_dir(repo, "/usr/share/appdata", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
-#endif
-  repodata_internalize(data);
-
-  if (reffp)
-    fclose(reffp);
-
-#ifdef SUSE
-  if (add_auto)
-    repo_add_autopattern(repo, ADD_NO_AUTOPRODUCTS);
-#endif
-
-  tool_write(repo, basefile, 0);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/rpmmd2solv.c b/libsolv-0.6.15/tools/rpmmd2solv.c
deleted file mode 100644 (file)
index d4fe2ff..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <zlib.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_rpmmd.h"
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-#include "common_write.h"
-#include "solv_xfopen.h"
-
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "rpmmd2solv [-a][-h][-n <attrname>][-l <locale>]\n"
-         "  reads 'primary' from a 'rpmmd' repository from <stdin> and writes a .solv file to <stdout>\n"
-         "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
-         "  -l <locale>: parse localization data for <locale>\n"
-        );
-   exit(status);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, flags = 0;
-  const char *attrname = 0;
-  const char *basefile = 0;
-  const char *dir = 0;
-  const char *locale = 0;
-#ifdef SUSE
-  int add_auto = 0;
-#endif
-  
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-
-  while ((c = getopt (argc, argv, "hn:b:d:l:X")) >= 0)
-    {
-      switch(c)
-       {
-        case 'h':
-          usage(0);
-          break;
-        case 'n':
-          attrname = optarg;
-          break;
-        case 'b':
-          basefile = optarg;
-          break;
-        case 'd':
-          dir = optarg;
-          break;
-       case 'l':
-         locale = optarg;
-         break;
-       case 'X':
-#ifdef SUSE
-         add_auto = 1;
-#endif
-         break;
-        default:
-          usage(1);
-          break;
-       }
-    }
-  if (dir)
-    {
-      FILE *fp;
-      int l;
-      char *fnp;
-      l = strlen(dir) + 128;
-      fnp = solv_malloc(l+1);
-      snprintf(fnp, l, "%s/primary.xml.gz", dir);
-      if (!(fp = solv_xfopen(fnp, 0)))
-       {
-         perror(fnp);
-         exit(1);
-       }
-      if (repo_add_rpmmd(repo, fp, 0, flags))
-       {
-         fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool));
-         exit(1);
-       }
-      fclose(fp);
-      snprintf(fnp, l, "%s/diskusagedata.xml.gz", dir);
-      if ((fp = solv_xfopen(fnp, 0)))
-       {
-         if (repo_add_rpmmd(repo, fp, 0, flags))
-           {
-             fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool));
-             exit(1);
-           }
-         fclose(fp);
-       }
-      if (locale)
-       {
-         if (snprintf(fnp, l, "%s/translation-%s.xml.gz", dir, locale) >= l)
-           {
-             fprintf(stderr, "-l parameter too long\n");
-             exit(1);
-           }
-         while (!(fp = solv_xfopen(fnp, 0)))
-           {
-             fprintf(stderr, "not opened %s\n", fnp);
-             if (strlen(locale) > 2)
-               {
-                 if (snprintf(fnp, l, "%s/translation-%.2s.xml.gz", dir, locale) >= l)
-                   {
-                     fprintf(stderr, "-l parameter too long\n");
-                     exit(1);
-                   }
-                 if ((fp = solv_xfopen(fnp, 0)))
-                   break;
-               }
-             perror(fnp);
-             exit(1);
-           }
-         fprintf(stderr, "opened %s\n", fnp);
-         if (repo_add_rpmmd(repo, fp, 0, flags))
-           {
-             fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool));
-             exit(1);
-           }
-         fclose(fp);
-       }
-      solv_free(fnp);
-    }
-  else
-    {
-      if (repo_add_rpmmd(repo, stdin, 0, flags))
-       {
-         fprintf(stderr, "rpmmd2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-#ifdef SUSE
-  if (add_auto)
-    repo_add_autopattern(repo, 0);
-#endif
-  tool_write(repo, basefile, attrname);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/rpms2solv.c b/libsolv-0.6.15/tools/rpms2solv.c
deleted file mode 100644 (file)
index 7852b08..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-/*
- * rpms2solv - create a solv file from multiple rpms
- * 
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "util.h"
-#include "pool.h"
-#include "repo.h"
-#include "repo_rpmdb.h"
-#ifdef ENABLE_PUBKEY
-#include "repo_pubkey.h"
-#include "solv_xfopen.h"
-#endif
-#include "repo_solv.h"
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-#include "common_write.h"
-
-static char *
-fgets0(char *s, int size, FILE *stream)
-{
-  char *p = s;
-  int c;
-
-  while (--size > 0)
-    {
-      c = getc(stream);
-      if (c == EOF)
-       {
-         if (p == s)
-           return 0;
-         c = 0;
-       }
-      *p++ = c;
-      if (!c)
-       return s;
-    }
-  *p = 0;
-  return s;
-}
-
-int
-main(int argc, char **argv)
-{
-  const char **rpms = 0;
-  char *manifest = 0;
-  int manifest0 = 0;
-  int c, i, res, nrpms = 0;
-  Pool *pool = pool_create();
-  Repo *repo;
-  FILE *fp;
-  char buf[4096], *p;
-  const char *basefile = 0;
-#ifdef ENABLE_PUBKEY
-  int pubkeys = 0;
-#endif
-#ifdef SUSE
-  int add_auto = 0;
-#endif
-  int filtered_filelist = 0;
-
-  while ((c = getopt(argc, argv, "0XkKb:m:F")) >= 0)
-    {
-      switch(c)
-       {
-       case 'b':
-         basefile = optarg;
-         break;
-       case 'm':
-         manifest = optarg;
-         break;
-       case '0':
-         manifest0 = 1;
-         break;
-       case 'F':
-         filtered_filelist = 1;
-         break;
-#ifdef ENABLE_PUBKEY
-       case 'k':
-         pubkeys = 1;
-         break;
-       case 'K':
-         pubkeys = 2;
-         break;
-#endif
-       case 'X':
-#ifdef SUSE
-         add_auto = 1;
-#endif
-         break;
-       default:
-         exit(1);
-       }
-    }
-  if (manifest)
-    {
-      if (!strcmp(manifest, "-"))
-        fp = stdin;
-      else if ((fp = fopen(manifest, "r")) == 0)
-       {
-         perror(manifest);
-         exit(1);
-       }
-      for (;;)
-       {
-         if (manifest0)
-           {
-             if (!fgets0(buf, sizeof(buf), fp))
-               break;
-           }
-         else
-           {
-             if (!fgets(buf, sizeof(buf), fp))
-               break;
-             if ((p = strchr(buf, '\n')) != 0)
-               *p = 0;
-           }
-          rpms = solv_extend(rpms, nrpms, 1, sizeof(char *), 15);
-         rpms[nrpms++] = strdup(buf);
-       }
-      if (fp != stdin)
-        fclose(fp);
-    }
-  while (optind < argc)
-    {
-      rpms = solv_extend(rpms, nrpms, 1, sizeof(char *), 15);
-      rpms[nrpms++] = strdup(argv[optind++]);
-    }
-  repo = repo_create(pool, "rpms2solv");
-  repo_add_repodata(repo, 0);
-  res = 0;
-  for (i = 0; i < nrpms; i++)
-    {
-#ifdef ENABLE_PUBKEY
-      if (pubkeys == 2)
-       {
-         FILE *fp = solv_xfopen(rpms[i], "r");
-         if (!fp)
-           {
-             perror(rpms[i]);
-             res = 1;
-             continue;
-           }
-         if (repo_add_keyring(repo, fp, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|ADD_WITH_KEYSIGNATURES))
-           {
-             fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool));
-             res = 1;
-           }
-         fclose(fp);
-         continue;
-       }
-      if (pubkeys)
-        {
-         if (repo_add_pubkey(repo, rpms[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|ADD_WITH_KEYSIGNATURES) == 0)
-           {
-             fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool));
-             res = 1;
-           }
-         continue;
-        }
-#endif
-      if (repo_add_rpm(repo, rpms[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0)) == 0)
-       {
-         fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool));
-         res = 1;
-       }
-    }
-  repo_internalize(repo);
-#ifdef SUSE
-  if (add_auto)
-    repo_add_autopattern(repo, 0);
-#endif
-  tool_write(repo, basefile, 0);
-  pool_free(pool);
-  for (c = 0; c < nrpms; c++)
-    free((char *)rpms[c]);
-  solv_free(rpms);
-  exit(res);
-}
-
diff --git a/libsolv-0.6.15/tools/susetags2solv.c b/libsolv-0.6.15/tools/susetags2solv.c
deleted file mode 100644 (file)
index 71c65d8..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <zlib.h>
-#include <getopt.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_solv.h"
-#include "repo_susetags.h"
-#include "repo_content.h"
-#ifdef SUSE
-#include "repo_autopattern.h"
-#endif
-#include "common_write.h"
-#include "solv_xfopen.h"
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "susetags2solv [-b <base>][-c <content>][-d <descrdir>][-h][-n <name>]\n"
-         "  reads a 'susetags' repository from <stdin> and writes a .solv file to <stdout>\n"
-         "  -b <base>: save as multiple files starting with <base>\n"
-         "  -c <contentfile> : parse given contentfile (for product information)\n"
-          "  -d <descrdir> : do not read from stdin, but use data in descrdir\n"
-         "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
-        );
-   exit(status);
-}
-
-/* content file query */
-static void
-doquery(Pool *pool, Repo *repo, const char *arg)
-{
-  char qbuf[256];
-  const char *str;
-  Id id;
-
-  snprintf(qbuf, sizeof(qbuf), "susetags:%s", arg);
-  id = pool_str2id(pool, qbuf, 0);
-  if (!id)
-    return;
-  str = repo_lookup_str(repo, SOLVID_META, id);
-  if (str)
-    printf("%s\n", str);
-}
-
-int
-main(int argc, char **argv)
-{
-  const char *contentfile = 0;
-  const char *attrname = 0;
-  const char *descrdir = 0;
-  const char *basefile = 0;
-  const char *query = 0;
-  const char *mergefile = 0;
-  Id defvendor = 0;
-  int flags = 0;
-#ifdef SUSE
-  int add_auto = 0;
-#endif
-  int c;
-  Pool *pool;
-  Repo *repo;
-
-  while ((c = getopt(argc, argv, "hn:c:d:b:q:M:X")) >= 0)
-    {
-      switch (c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'n':
-         attrname = optarg;
-         break;
-       case 'c':
-         contentfile = optarg;
-         break;
-       case 'd':
-         descrdir = optarg;
-         break;
-       case 'b':
-         basefile = optarg;
-         break;
-       case 'q':
-         query = optarg;
-         break;
-       case 'M':
-         mergefile = optarg;
-         break;
-       case 'X':
-#ifdef SUSE
-         add_auto = 1;
-#endif
-         break;
-       default:
-         usage(1);
-         break;
-       }
-    }
-  pool = pool_create();
-  repo = repo_create(pool, "<susetags>");
-
-  repo_add_repodata(repo, 0);
-
-  if (contentfile)
-    {
-      FILE *fp = fopen(contentfile, "r");
-      if (!fp)
-        {
-         perror(contentfile);
-         exit(1);
-       }
-      if (repo_add_content(repo, fp, REPO_REUSE_REPODATA))
-       {
-         fprintf(stderr, "susetags2solv: %s: %s\n", contentfile, pool_errstr(pool));
-         exit(1);
-       }
-      defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
-      fclose(fp);
-    }
-
-  if (attrname)
-    {
-      /* ensure '.attr' suffix */
-      const char *dot = strrchr(attrname, '.');
-      if (!dot || strcmp(dot, ".attr"))
-      {
-       int len = strlen (attrname);
-       char *newname = (char *)malloc(len + 6); /* alloc for <attrname>+'.attr'+'\0' */
-       strcpy (newname, attrname);
-       strcpy (newname+len, ".attr");
-       attrname = newname;
-      }
-    }
-
-  /*
-   * descrdir path given, open files and read from there
-   */
-  
-  if (descrdir)
-    {
-      char *fnp;
-      int ndirs, i;
-      struct dirent **files;
-
-      ndirs = scandir(descrdir, &files, 0, alphasort);
-      if (ndirs < 0)
-       {
-         perror(descrdir);
-         exit(1);
-       }
-
-      /* bring packages to front */
-      for (i = 0; i < ndirs; i++)
-       {
-         char *fn = files[i]->d_name;
-         if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz"))
-           break;
-        }
-      if (i == ndirs)
-       {
-         fprintf(stderr, "found no packages file\n");
-         exit(1);
-       }
-      if (i)
-       {
-         struct dirent *de = files[i];
-         memmove(files + 1, files, i * sizeof(de));
-         files[0] = de;
-       }
-
-      fnp = solv_malloc(strlen(descrdir) + 128);
-      for (i = 0; i < ndirs; i++)
-       {
-         char *fn = files[i]->d_name;
-
-         if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz"))
-           {
-             FILE *fp;
-             sprintf(fnp, "%s/%s", descrdir, fn);
-             fp = solv_xfopen(fnp, 0);
-             if (!fp)
-               {
-                 perror(fn);
-                 exit(1);
-               }
-             if (repo_add_susetags(repo, fp, defvendor, 0, flags | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-               {
-                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
-                 exit(1);
-               }
-             fclose(fp);
-           }
-         else if (!strcmp(fn, "packages.DU") || !strcmp(fn, "packages.DU.gz"))
-           {
-             FILE *fp;
-             sprintf(fnp, "%s/%s", descrdir, fn);
-             fp = solv_xfopen(fnp, 0);
-             if (!fp)
-               {
-                 perror(fn);
-                 exit(1);
-               }
-             if (repo_add_susetags(repo, fp, defvendor, 0, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-               {
-                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
-                 exit(1);
-               }
-             fclose(fp);
-           }
-         else if (!strcmp(fn, "packages.FL") || !strcmp(fn, "packages.FL.gz"))
-           {
-#if 0
-             sprintf(fnp, "%s/%s", descrdir, fn);
-             FILE *fp = solv_xfopen(fnp, 0);
-             if (!fp)
-               {
-                 perror(fn);
-                 exit(1);
-               }
-             if (repo_add_susetags(repo, fp, defvendor, 0, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-               {
-                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
-                 exit(1);
-               }
-             fclose(fp);
-#else
-             /* ignore for now. reactivate when filters work */
-             continue;
-#endif
-           }
-         else if (!strncmp(fn, "packages.", 9))
-           {
-             char lang[6];
-             char *p;
-             FILE *fp;
-             sprintf(fnp, "%s/%s", descrdir, fn);
-             p = strrchr(fnp, '.');
-             if (p && !strcmp(p, ".gz"))
-               {
-                 *p = 0;
-                 p = strrchr(fnp, '.');
-               }
-             if (!p || !p[1] || strlen(p + 1) > 5)
-               continue;
-             strcpy(lang, p + 1);
-             sprintf(fnp, "%s/%s", descrdir, fn);
-             fp = solv_xfopen(fnp, 0);
-             if (!fp)
-               {
-                 perror(fn);
-                 exit(1);
-               }
-             if (repo_add_susetags(repo, fp, defvendor, lang, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-               {
-                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
-                 exit(1);
-               }
-             fclose(fp);
-           }
-       }
-      for (i = 0; i < ndirs; i++)
-       free(files[i]);
-      free(files);
-      free(fnp);
-      repo_internalize(repo);
-    }
-  else
-    {
-      /* read data from stdin */
-      if (repo_add_susetags(repo, stdin, defvendor, 0, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
-       {
-         fprintf(stderr, "susetags2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-    }
-  repo_internalize(repo);
-  if (mergefile)
-    {
-      FILE *fp = fopen(mergefile, "r");
-      if (!fp)
-       {
-         perror(mergefile);
-         exit(1);
-       }
-      if (repo_add_solv(repo, fp, 0))
-       {
-         fprintf(stderr, "susetags2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
-      fclose(fp);
-    }
-#ifdef SUSE
-  if (add_auto)
-    repo_add_autopattern(repo, 0); 
-#endif
-
-  if (query)
-    doquery(pool, repo, query);
-  else
-    tool_write(repo, basefile, attrname);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.6.15/tools/testsolv.c b/libsolv-0.6.15/tools/testsolv.c
deleted file mode 100644 (file)
index d0328ae..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "solver.h"
-#include "selection.h"
-#include "solverdebug.h"
-#include "testcase.h"
-
-static struct resultflags2str {
-  Id flag;
-  const char *str;
-} resultflags2str[] = {
-  { TESTCASE_RESULT_TRANSACTION,        "transaction" },
-  { TESTCASE_RESULT_PROBLEMS,           "problems" },
-  { TESTCASE_RESULT_ORPHANED,           "orphaned" },
-  { TESTCASE_RESULT_RECOMMENDED,        "recommended" },
-  { TESTCASE_RESULT_UNNEEDED,           "unneeded" },
-  { TESTCASE_RESULT_ALTERNATIVES,       "alternatives" },
-  { TESTCASE_RESULT_RULES,              "rules" },
-  { TESTCASE_RESULT_GENID,              "genid" },
-  { 0, 0 }
-};
-
-static void
-usage(int ex)
-{
-  fprintf(ex ? stderr : stdout, "Usage: testsolv <testcase>\n");
-  exit(ex);
-}
-
-struct reportsolutiondata {
-  int count;
-  char *result;
-};
-
-static int
-reportsolutioncb(Solver *solv, void *cbdata)
-{
-  struct reportsolutiondata *sd = cbdata;
-  char *res;
-
-  sd->count++;
-  res = testcase_solverresult(solv, TESTCASE_RESULT_TRANSACTION);
-  if (*res)
-    {
-      char prefix[64];
-      char *p2, *p = res;
-      sprintf(prefix, "callback%d:", sd->count);
-      while ((p2 = strchr(p, '\n')) != 0)
-       {
-         char c = p2[1];
-         p2[1] = 0;
-         sd->result = solv_dupappend(sd->result, prefix, p);
-         p2[1] = c;
-         p = p2 + 1;
-       }
-    }
-  solv_free(res);
-  return 0;
-}
-
-int
-main(int argc, char **argv)
-{
-  Pool *pool;
-  Queue job;
-  Queue solq;
-  Solver *solv;
-  char *result = 0;
-  int resultflags = 0;
-  int debuglevel = 0;
-  int writeresult = 0;
-  char *writetestcase = 0;
-  int multijob = 0;
-  int rescallback = 0;
-  int c;
-  int ex = 0;
-  const char *list = 0;
-  FILE *fp;
-  const char *p;
-
-  queue_init(&solq);
-  while ((c = getopt(argc, argv, "vmrhl:s:T:")) >= 0)
-    {
-      switch (c)
-      {
-        case 'v':
-          debuglevel++;
-          break;
-        case 'r':
-          writeresult++;
-          break;
-        case 'm':
-          rescallback = 1;
-          break;
-        case 'h':
-         usage(0);
-          break;
-        case 'l':
-         list = optarg;
-          break;
-        case 's':
-         if ((p = strchr(optarg, ':')))
-           queue_push2(&solq, atoi(optarg), atoi(p + 1));
-         else
-           queue_push2(&solq, 1, atoi(optarg));
-          break;
-        case 'T':
-         writetestcase = optarg;
-          break;
-        default:
-         usage(1);
-          break;
-      }
-    }
-  if (optind == argc)
-    usage(1);
-  for (; optind < argc; optind++)
-    {
-      pool = pool_create();
-      pool_setdebuglevel(pool, debuglevel);
-
-      fp = fopen(argv[optind], "r");
-      if (!fp)
-       {
-         perror(argv[optind]);
-         exit(0);
-       }
-      while (!feof(fp))
-       {
-         queue_init(&job);
-         result = 0;
-         resultflags = 0;
-         solv = testcase_read(pool, fp, argv[optind], &job, &result, &resultflags);
-         if (!solv)
-           {
-             pool_free(pool);
-             exit(resultflags == 77 ? 77 : 1);
-           }
-
-         if (!multijob && !feof(fp))
-           multijob = 1;
-
-         if (multijob)
-           printf("test %d:\n", multijob++);
-         if (list)
-           {
-             int selflags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL|SELECTION_GLOB|SELECTION_FLAT;
-             if (*list == '/')
-               selflags |= SELECTION_FILELIST;
-             queue_empty(&job);
-             selection_make(pool, &job, list, selflags);
-             if (!job.elements)
-               printf("No match\n");
-             else
-               {
-                 Queue q;
-                 int i;
-                 queue_init(&q);
-                 selection_solvables(pool, &job, &q);
-                 for (i = 0; i < q.count; i++)
-                   printf("  - %s\n", testcase_solvid2str(pool, q.elements[i]));
-                 queue_free(&q);
-               }
-           }
-         else if (result || writeresult)
-           {
-             char *myresult, *resultdiff;
-             struct reportsolutiondata reportsolutiondata;
-             memset(&reportsolutiondata, 0, sizeof(reportsolutiondata));
-             if (rescallback)
-               {
-                 solv->solution_callback = reportsolutioncb;
-                 solv->solution_callback_data = &reportsolutiondata;
-               }
-             solver_solve(solv, &job);
-             solv->solution_callback = 0;
-             solv->solution_callback_data = 0;
-             if (!resultflags)
-               resultflags = TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS;
-             myresult = testcase_solverresult(solv, resultflags);
-             if (rescallback && reportsolutiondata.result)
-               {
-                 reportsolutiondata.result = solv_dupjoin(reportsolutiondata.result, myresult, 0);
-                 solv_free(myresult);
-                 myresult = reportsolutiondata.result;
-               }
-             if (writeresult)
-               {
-                 if (*myresult)
-                   {
-                     if (writeresult > 1)
-                       {
-                         const char *p;
-                         int i;
-                         
-                         printf("result ");
-                         p = "%s";
-                         for (i = 0; resultflags2str[i].str; i++)
-                           if ((resultflags & resultflags2str[i].flag) != 0)
-                             {
-                               printf(p, resultflags2str[i].str);
-                               p = ",%s";
-                             }
-                         printf(" <inline>\n");
-                         p = myresult;
-                         while (*p)
-                           {
-                             const char *p2 = strchr(p, '\n');
-                             p2 = p2 ? p2 + 1 : p + strlen(p);
-                             printf("#>%.*s", (int)(p2 - p), p);
-                             p = p2;
-                           }
-                       }
-                     else
-                       printf("%s", myresult);
-                   }
-               }
-             else
-               {
-                 resultdiff = testcase_resultdiff(result, myresult);
-                 if (resultdiff)
-                   {
-                     printf("Results differ:\n%s", resultdiff);
-                     ex = 1;
-                     solv_free(resultdiff);
-                   }
-               }
-             solv_free(result);
-             solv_free(myresult);
-           }
-         else
-           {
-             int pcnt = solver_solve(solv, &job);
-             if (writetestcase)
-               testcase_write(solv, writetestcase, resultflags, 0, 0);
-             if (pcnt && solq.count)
-               {
-                 int i, taken = 0;
-                 for (i = 0; i < solq.count; i += 2)
-                   {
-                     if (solq.elements[i] > 0 && solq.elements[i] <= pcnt)
-                       if (solq.elements[i + 1] > 0 && solq.elements[i + 1] <=  solver_solution_count(solv, solq.elements[i]))
-                         {
-                           printf("problem %d: taking solution %d\n", solq.elements[i], solq.elements[i + 1]);
-                           solver_take_solution(solv, solq.elements[i], solq.elements[i + 1], &job);
-                           taken = 1;
-                         }
-                   }
-                 if (taken)
-                   pcnt = solver_solve(solv, &job);
-               }
-             if (pcnt)
-               {
-                 int problem, solution, scnt;
-                 printf("Found %d problems:\n", pcnt);
-                 for (problem = 1; problem <= pcnt; problem++)
-                   {
-                     printf("Problem %d:\n", problem);
-#if 1
-                     solver_printprobleminfo(solv, problem);
-#else
-                     {
-                       Queue pq;
-                       int j;
-                       queue_init(&pq);
-                       solver_findallproblemrules(solv, problem, &pq);
-                       for (j = 0; j < pq.count; j++)
-                         solver_printproblemruleinfo(solv, pq.elements[j]);
-                       queue_free(&pq);
-                     }
-#endif
-                     printf("\n");
-                     scnt = solver_solution_count(solv, problem);
-                     for (solution = 1; solution <= scnt; solution++)
-                       {
-                         printf("Solution %d:\n", solution);
-                         solver_printsolution(solv, problem, solution);
-                         printf("\n");
-                       }
-                   }
-               }
-             else
-               {
-                 Transaction *trans = solver_create_transaction(solv);
-                 printf("Transaction summary:\n\n");
-                 transaction_print(trans);
-                 transaction_free(trans);
-               }
-           }
-         queue_free(&job);
-         solver_free(solv);
-       }
-      pool_free(pool);
-      fclose(fp);
-    }
-  queue_free(&solq);
-  exit(ex);
-}
diff --git a/libsolv-0.6.15/tools/updateinfoxml2solv.c b/libsolv-0.6.15/tools/updateinfoxml2solv.c
deleted file mode 100644 (file)
index 5432150..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2007, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#include <sys/types.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "pool.h"
-#include "repo.h"
-#include "repo_updateinfoxml.h"
-#include "common_write.h"
-
-static void
-usage(int status)
-{
-  fprintf(stderr, "\nUsage:\n"
-          "updateinfoxml2solv [-h][-n <attrname>]\n"
-         "  reads a 'updateinfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
-         "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
-        );
-  exit(status);
-}
-
-int
-main(int argc, char **argv)
-{
-  int c, flags = 0;
-  char *attrname = 0;
-  
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-
-  while ((c = getopt(argc, argv, "hn:")) >= 0)
-    {
-      switch(c)
-       {
-       case 'h':
-         usage(0);
-         break;
-       case 'n':
-         attrname = optarg;
-         break;
-       default:
-         usage(1);
-         break;
-       }
-    }
-  if (repo_add_updateinfoxml(repo, stdin, flags))
-    {
-      fprintf(stderr, "updateinfoxml2solv: %s\n", pool_errstr(pool));
-      exit(1);
-    }
-  tool_write(repo, 0, attrname);
-  pool_free(pool);
-  exit(0);
-}
diff --git a/libsolv-0.7.2/.emacs-dirvars b/libsolv-0.7.2/.emacs-dirvars
new file mode 100644 (file)
index 0000000..e224534
--- /dev/null
@@ -0,0 +1,9 @@
+;; -*- emacs-lisp -*-
+;;
+;; This file is processed by the dirvars emacs package.  Each variable
+;; setting below is performed when this dirvars file is loaded.
+;;
+c-file-style: "gnu"; 
+fill-column: 78
+indent-tabs-mode: nil
+tab-width: 8
diff --git a/libsolv-0.7.2/.gitignore b/libsolv-0.7.2/.gitignore
new file mode 100644 (file)
index 0000000..08fac49
--- /dev/null
@@ -0,0 +1,5 @@
+*~
+build
+doc/*.xml
+tests/solver/data.libzypp/*/*.result
+src/solvversion.h
diff --git a/libsolv-0.7.2/.travis.yml b/libsolv-0.7.2/.travis.yml
new file mode 100644 (file)
index 0000000..8d7dda5
--- /dev/null
@@ -0,0 +1,5 @@
+language: C
+before_script: sudo apt-get install cmake
+script: mkdir build && cd build && cmake -DDEBIAN=1 -DMULTI_SEMANTICS=1 .. && make && make test
+
+
diff --git a/libsolv-0.7.2/CMakeLists.txt b/libsolv-0.7.2/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1deef57
--- /dev/null
@@ -0,0 +1,471 @@
+PROJECT (libsolv)
+
+CMAKE_MINIMUM_REQUIRED (VERSION 2.4)
+
+OPTION (ENABLE_STATIC "Build a static version of the libraries?" OFF)
+OPTION (DISABLE_SHARED "Do not build a shared version of the libraries?" OFF)
+
+OPTION (ENABLE_PERL "Build the perl bindings?" OFF)
+OPTION (ENABLE_PYTHON "Build the python bindings?" OFF)
+OPTION (ENABLE_RUBY "Build the ruby bindings?" OFF)
+OPTION (ENABLE_TCL "Build the Tcl bindings?" OFF)
+
+OPTION (USE_VENDORDIRS "Install the bindings in vendor directories?" OFF)
+
+OPTION (ENABLE_RPMDB "Build with rpm database support?" OFF)
+OPTION (ENABLE_RPMPKG "Build with rpm package support?" OFF)
+OPTION (ENABLE_PUBKEY "Build with pubkey support?" OFF)
+OPTION (ENABLE_RPMDB_BYRPMHEADER "Build with rpmdb Header support?" OFF)
+OPTION (ENABLE_RPMDB_LIBRPM "Use librpm to access the rpm database?" OFF)
+OPTION (ENABLE_RPMPKG_LIBRPM "Use librpm to access rpm header information?" OFF)
+OPTION (ENABLE_RPMMD "Build with rpmmd repository support?" OFF)
+OPTION (ENABLE_SUSEREPO "Build with suse repository support?" OFF)
+OPTION (ENABLE_COMPS "Build with fedora comps support?" OFF)
+OPTION (ENABLE_HELIXREPO "Build with helix repository support?" OFF)
+OPTION (ENABLE_DEBIAN "Build with debian database/repository support?" OFF)
+OPTION (ENABLE_MDKREPO "Build with mandriva/mageia repository support?" OFF)
+OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF)
+OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF)
+OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF)
+OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF)
+
+OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF)
+
+OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF)
+OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF)
+OPTION (ENABLE_ZSTD_COMPRESSION "Build with zstd compression support?" OFF)
+OPTION (ENABLE_ZCHUNK_COMPRESSION "Build with zchunk compression support?" OFF)
+OPTION (WITH_SYSTEM_ZCHUNK "Use system zchunk library?" OFF)
+OPTION (WITH_LIBXML2  "Build with libxml2 instead of libexpat?" OFF)
+
+# Library
+IF (DEFINED LIB)
+  SET (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB}")
+ELSE (DEFINED  LIB)
+  IF (CMAKE_SIZEOF_VOID_P MATCHES "8")
+    SET (LIB_SUFFIX "64")
+  ENDIF (CMAKE_SIZEOF_VOID_P MATCHES "8")
+  SET (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}")
+ENDIF (DEFINED  LIB)
+MESSAGE (STATUS "Libraries will be installed in ${LIB_INSTALL_DIR}")
+# Library
+IF (DEFINED INCLUDE)
+  SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${INCLUDE}")
+else (DEFINED INCLUDE)
+  SET (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include")
+ENDIF (DEFINED  INCLUDE)
+MESSAGE (STATUS "Header files will be installed in ${INCLUDE_INSTALL_DIR}")
+SET (BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin")
+IF (NOT MAN_INSTALL_DIR)
+SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man")
+IF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man"  AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man")
+  SET (MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/man")
+ENDIF (IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/man"  AND NOT IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/share/man")
+ENDIF (NOT MAN_INSTALL_DIR)
+MESSAGE(STATUS "Man pages will be installed in ${MAN_INSTALL_DIR}")
+
+IF (NOT PKGCONFIG_INSTALL_DIR)
+  SET (PKGCONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/pkgconfig)
+ENDIF (NOT PKGCONFIG_INSTALL_DIR)
+####################################################################
+# CONFIGURATION                                                    #
+####################################################################
+
+# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
+SET (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
+INSTALL( FILES ${CMAKE_MODULE_PATH}/FindLibSolv.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}/share/cmake/Modules )
+
+INCLUDE (${CMAKE_SOURCE_DIR}/VERSION.cmake)
+
+SET (have_system x)
+
+IF (FEDORA)
+MESSAGE(STATUS "Building for Fedora")
+ADD_DEFINITIONS (-DFEDORA)
+SET (ENABLE_RPMDB ON)
+SET (ENABLE_RPMMD ON)
+SET (have_system ${have_system}x)
+ENDIF (FEDORA)
+
+IF (DEBIAN)
+MESSAGE (STATUS "Building for Debian")
+ADD_DEFINITIONS (-DDEBIAN)
+SET (ENABLE_DEBIAN ON)
+SET (have_system ${have_system}x)
+ENDIF (DEBIAN)
+
+IF (SUSE)
+MESSAGE (STATUS "Building for SUSE")
+ADD_DEFINITIONS (-DSUSE)
+SET (ENABLE_RPMDB ON)
+SET (ENABLE_PUBKEY ON)
+SET (ENABLE_RPMDB_BYRPMHEADER ON)
+SET (ENABLE_RPMMD ON)
+SET (ENABLE_SUSEREPO ON)
+SET (ENABLE_HELIXREPO ON)
+SET (ENABLE_LINKED_PKGS ON)
+SET (have_system ${have_system}x)
+ENDIF (SUSE)
+
+IF (ARCHLINUX)
+MESSAGE (STATUS "Building for Archlinux")
+ADD_DEFINITIONS (-DARCHLINUX)
+SET (ENABLE_ARCHREPO ON)
+SET (have_system ${have_system}x)
+ENDIF (ARCHLINUX)
+
+IF (MANDRIVA)
+MESSAGE (STATUS "Building for Mandriva")
+ADD_DEFINITIONS (-DMANDRIVA)
+SET (ENABLE_MDKREPO ON)
+SET (ENABLE_RPMDB ON)
+SET (have_system ${have_system}x)
+ENDIF (MANDRIVA)
+
+IF (MAGEIA)
+MESSAGE (STATUS "Building for Mageia")
+ADD_DEFINITIONS (-DMAGEIA)
+SET (ENABLE_MDKREPO ON)
+SET (ENABLE_RPMDB ON)
+SET (ENABLE_RPMMD ON)
+SET (ENABLE_LZMA_COMPRESSION ON)
+SET (have_system ${have_system}x)
+ENDIF (MAGEIA)
+
+IF (HAIKU)
+MESSAGE(STATUS "Building for Haiku")
+FIND_LIBRARY(HAIKU_BE_LIBRARY NAMES be)
+FIND_LIBRARY(HAIKU_NETWORK_LIBRARY NAMES network)
+FIND_LIBRARY(HAIKU_PACKAGE_LIBRARY NAMES package)
+SET (HAIKU_SYSTEM_LIBRARIES
+    ${HAIKU_BE_LIBRARY} ${HAIKU_NETWORK_LIBRARY} ${HAIKU_PACKAGE_LIBRARY})
+ADD_DEFINITIONS (-DHAIKU)
+SET (ENABLE_HAIKU ON)
+SET (have_system ${have_system}x)
+ENDIF (HAIKU)
+
+IF (${have_system} STREQUAL x)
+    MESSAGE (STATUS "Building for no system")
+ENDIF (${have_system} STREQUAL x)
+IF (${have_system} STRGREATER xx)
+    MESSAGE (FATAL_ERROR "Can only compile for one system type.")
+ENDIF (${have_system} STRGREATER xx)
+
+SET (ENABLE_ZLIB_COMPRESSION ON)
+IF (ENABLE_ARCHREPO OR ENABLE_DEBIAN)
+SET (ENABLE_LZMA_COMPRESSION ON)
+ENDIF (ENABLE_ARCHREPO OR ENABLE_DEBIAN)
+
+IF (WITH_SYSTEM_ZCHUNK)
+SET (ENABLE_ZCHUNK_COMPRESSION ON)
+FIND_PACKAGE(PkgConfig REQUIRED)
+PKG_CHECK_MODULES(ZCHUNK zck REQUIRED)
+ENDIF (WITH_SYSTEM_ZCHUNK)
+
+IF (ENABLE_ZCHUNK_COMPRESSION)
+SET (ENABLE_ZSTD_COMPRESSION ON)
+ENDIF (ENABLE_ZCHUNK_COMPRESSION)
+
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+IF (WITH_LIBXML2 )
+FIND_PACKAGE (LibXml2 REQUIRED)
+INCLUDE_DIRECTORIES (${LIBXML2_INCLUDE_DIR})
+ELSE(WITH_LIBXML2 )
+FIND_PACKAGE (EXPAT REQUIRED)
+INCLUDE_DIRECTORIES (${EXPAT_INCLUDE_DIRS})
+ENDIF (WITH_LIBXML2 )
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+
+IF (ENABLE_ZLIB_COMPRESSION)
+FIND_PACKAGE (ZLIB REQUIRED)
+ENDIF (ENABLE_ZLIB_COMPRESSION)
+
+IF (ENABLE_LZMA_COMPRESSION)
+FIND_PACKAGE (LZMA REQUIRED)
+ENDIF (ENABLE_LZMA_COMPRESSION)
+
+IF (ENABLE_BZIP2_COMPRESSION)
+FIND_PACKAGE (BZip2 REQUIRED)
+ENDIF (ENABLE_BZIP2_COMPRESSION)
+
+IF (ENABLE_ZSTD_COMPRESSION)
+FIND_LIBRARY (ZSTD_LIBRARY NAMES zstd)
+ENDIF (ENABLE_ZSTD_COMPRESSION)
+
+IF (RPM5)
+MESSAGE (STATUS "Enabling RPM 5 support")
+ADD_DEFINITIONS (-DRPM5)
+SET (ENABLE_RPMDB ON)
+SET (ENABLE_RPMMD ON)
+FIND_PACKAGE (PkgConfig REQUIRED)
+PKG_CHECK_MODULES (RPM REQUIRED rpm)
+INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIRS})
+ENDIF (RPM5)
+
+IF (MULTI_SEMANTICS)
+MESSAGE (STATUS "Enabling multi dist support")
+ENDIF (MULTI_SEMANTICS)
+
+IF (ENABLE_RPMDB)
+SET (ENABLE_RPMPKG ON)
+ENDIF (ENABLE_RPMDB)
+
+INCLUDE (CheckIncludeFile)
+IF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM)
+  FIND_LIBRARY (RPMDB_LIBRARY NAMES rpmdb)
+
+  IF (NOT RPMDB_LIBRARY)
+    FIND_LIBRARY (RPMDB_LIBRARY NAMES rpm)
+  ENDIF (NOT RPMDB_LIBRARY)
+
+  FIND_LIBRARY (RPMIO_LIBRARY NAMES rpmio)
+  IF (RPMIO_LIBRARY)
+    SET(RPMDB_LIBRARY ${RPMIO_LIBRARY} ${RPMDB_LIBRARY})
+  ENDIF (RPMIO_LIBRARY)
+
+  IF (RPM5)
+    FIND_LIBRARY (RPMMISC_LIBRARY NAMES rpmmisc)
+    IF (RPMMISC_LIBRARY)
+      SET (RPMDB_LIBRARY ${RPMMISC_LIBRARY} ${RPMDB_LIBRARY})
+    ENDIF (RPMMISC_LIBRARY)
+  ENDIF (RPM5)
+
+  # check if rpm contains a bundled berkeley db
+  CHECK_INCLUDE_FILE(rpm/db.h HAVE_RPM_DB_H)
+  IF (NOT ENABLE_RPMDB_LIBRPM)
+    IF (NOT HAVE_RPM_DB_H)
+      FIND_LIBRARY (DB_LIBRARY NAMES db)
+      IF (DB_LIBRARY)
+        SET (RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY})
+      ENDIF (DB_LIBRARY)
+      IF (DB_INCLUDE_DIR)
+        INCLUDE_DIRECTORIES (${DB_INCLUDE_DIR})
+      ENDIF (DB_INCLUDE_DIR)
+    ENDIF (NOT HAVE_RPM_DB_H)
+  ENDIF (NOT ENABLE_RPMDB_LIBRPM)
+  INCLUDE (CheckLibraryExists)
+  CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS)
+ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM)
+
+IF (ENABLE_PUBKEY)
+  SET (ENABLE_PGPVRFY ON)
+ENDIF (ENABLE_PUBKEY)
+
+INCLUDE (CheckFunctionExists)
+INCLUDE (TestBigEndian)
+
+CHECK_FUNCTION_EXISTS (strchrnul HAVE_STRCHRNUL)
+CHECK_FUNCTION_EXISTS (fopencookie HAVE_FOPENCOOKIE)
+CHECK_FUNCTION_EXISTS (funopen HAVE_FUNOPEN)
+TEST_BIG_ENDIAN (WORDS_BIGENDIAN)
+
+IF (${CMAKE_MAJOR_VERSION} GREATER 2)
+INCLUDE (CMakePushCheckState)
+INCLUDE (CheckCCompilerFlag)
+MACRO (check_linker_flag FLAG VAR)
+       CMAKE_PUSH_CHECK_STATE (RESET)
+       SET (CMAKE_REQUIRED_FLAGS "${FLAG}")
+       CHECK_C_COMPILER_FLAG ("" "${VAR}")
+       CMAKE_POP_CHECK_STATE ()
+ENDMACRO (check_linker_flag)
+check_linker_flag("-Wl,--as-needed" HAVE_LINKER_AS_NEEDED)
+check_linker_flag("-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver" HAVE_LINKER_VERSION_SCRIPT)
+ELSE (${CMAKE_MAJOR_VERSION} GREATER 2)
+SET (HAVE_LINKER_AS_NEEDED 1)
+SET (HAVE_LINKER_VERSION_SCRIPT 1)
+ENDIF (${CMAKE_MAJOR_VERSION} GREATER 2)
+
+# should create config.h with #cmakedefine instead...
+FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN
+  HAVE_RPM_DB_H HAVE_PGPDIGGETPARAMS WITH_LIBXML2 )
+  IF(${VAR})
+    ADD_DEFINITIONS (-D${VAR}=1)
+    SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
+  ENDIF (${VAR})
+ENDFOREACH (VAR)
+
+FOREACH (VAR
+  ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS)
+  IF(${VAR})
+    ADD_DEFINITIONS (-D${VAR}=1)
+    SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
+    STRING(REPLACE ENABLE_ "" VARX ${VAR})
+    SET (LIBSOLV_FEATURE_${VARX} 1)
+  ENDIF (${VAR})
+ENDFOREACH (VAR)
+
+FOREACH (VAR
+  ENABLE_RPMDB ENABLE_RPMPKG ENABLE_PUBKEY ENABLE_RPMMD
+  ENABLE_RPMPKG_LIBRPM ENABLE_RPMDB_LIBRPM ENABLE_RPMDB_BYRPMHEADER
+  ENABLE_SUSEREPO ENABLE_COMPS ENABLE_TESTCASE_HELIXREPO
+  ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU
+  ENABLE_ZLIB_COMPRESSION ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION
+  ENABLE_ZSTD_COMPRESSION ENABLE_ZCHUNK_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA
+  WITH_SYSTEM_ZCHUNK)
+  IF(${VAR})
+    ADD_DEFINITIONS (-D${VAR}=1)
+    SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
+    STRING(REPLACE ENABLE_ "" VARX ${VAR})
+    SET (LIBSOLVEXT_FEATURE_${VARX} 1)
+  ENDIF (${VAR})
+ENDFOREACH (VAR)
+
+SET (PACKAGE "libsolv")
+SET (VERSION "${LIBSOLV_MAJOR}.${LIBSOLV_MINOR}.${LIBSOLV_PATCH}")
+
+ADD_DEFINITIONS (-D_FILE_OFFSET_BITS=64)
+CONFIGURE_FILE (src/solvversion.h.in src/solvversion.h)
+
+SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Package dependency solver library")
+SET (CPACK_PACKAGE_VENDOR "SUSE")
+SET (CPACK_PACKAGE_VERSION_MAJOR ${LIBSOLV_MAJOR})
+SET (CPACK_PACKAGE_VERSION_MINOR ${LIBSOLV_MINOR})
+SET (CPACK_PACKAGE_VERSION_PATCH ${LIBSOLV_PATCH})
+SET (CPACK_GENERATOR "TBZ2")
+SET (CPACK_SOURCE_GENERATOR "TBZ2")
+SET (CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE}-${VERSION}")
+SET (CPACK_SOURCE_TOPLEVEL_TAG "Linux-Source:")
+SET (CPACK_TOPLEVEL_TAG "Linux-Source:")
+
+# The following components are regex's to match anywhere (unless anchored)
+# in absolute path + filename to find files or directories to be excluded
+# from source tarball.
+SET (CPACK_SOURCE_IGNORE_FILES
+# temporary files
+"\\\\.swp$"
+# backup files
+"~$"
+# eclipse files
+"\\\\.cdtproject$"
+"\\\\.cproject$"
+"\\\\.project$"
+"\\\\.settings/"
+# others
+"\\\\.#"
+"/#"
+"/build/"
+"/_build/"
+"/\\\\.git/"
+# used before
+"/\\\\.libs/"
+"/\\\\.deps/"
+"\\\\.o$"
+"\\\\.lo$"
+"\\\\.la$"
+"Makefile$"
+"Makefile\\\\.in$"
+# cmake cache files
+"DartConfiguration.tcl$"
+"CMakeCache.txt"
+"CMakeFiles"
+"cmake_install.cmake$"
+"CMakeLists.txt.auto$"
+"CTestTestfile.cmake"
+"CPackConfig.cmake$"
+"CPackSourceConfig.cmake$"
+"libsolv.spec$"
+)
+
+INCLUDE(CPack)
+
+####################################################################
+# INCLUDES                                                         #
+####################################################################
+
+#SET (CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
+INCLUDE_DIRECTORIES (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/ext ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}/src SYSTEM )
+
+####################################################################
+
+MESSAGE (STATUS "Looking for modules in ${CMAKE_MODULE_PATH}")
+
+set (CMAKE_C_FLAGS     "${CMAKE_C_FLAGS} -Wall")
+set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3")
+set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -O3")
+set (CMAKE_C_FLAGS_DEBUG     "${CMAKE_C_FLAGS} -g3 -O0")
+
+# set system libraries
+SET (SYSTEM_LIBRARIES "")
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+IF (WITH_LIBXML2 )
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LIBXML2_LIBRARIES})
+ELSE (WITH_LIBXML2 )
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${EXPAT_LIBRARY})
+ENDIF (WITH_LIBXML2 )
+
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+IF (ENABLE_ZLIB_COMPRESSION)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZLIB_LIBRARY})
+ENDIF (ENABLE_ZLIB_COMPRESSION)
+IF (ENABLE_LZMA_COMPRESSION)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${LZMA_LIBRARY})
+ENDIF (ENABLE_LZMA_COMPRESSION)
+IF (ENABLE_BZIP2_COMPRESSION)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${BZIP2_LIBRARIES})
+ENDIF (ENABLE_BZIP2_COMPRESSION)
+IF (ENABLE_ZSTD_COMPRESSION)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZSTD_LIBRARY})
+ENDIF (ENABLE_ZSTD_COMPRESSION)
+IF (WITH_SYSTEM_ZCHUNK)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZCHUNK_LIBRARIES})
+ENDIF (WITH_SYSTEM_ZCHUNK)
+IF (ENABLE_RPMDB)
+SET (SYSTEM_LIBRARIES ${RPMDB_LIBRARY} ${SYSTEM_LIBRARIES})
+ENDIF (ENABLE_RPMDB)
+IF (ENABLE_HAIKU)
+SET (SYSTEM_LIBRARIES ${HAIKU_SYSTEM_LIBRARIES} ${SYSTEM_LIBRARIES})
+ENDIF (ENABLE_HAIKU)
+IF (HAVE_LINKER_AS_NEEDED)
+SET (SYSTEM_LIBRARIES "-Wl,--as-needed" ${SYSTEM_LIBRARIES})
+ENDIF (HAVE_LINKER_AS_NEEDED)
+
+ADD_SUBDIRECTORY (src)
+ADD_SUBDIRECTORY (ext)
+ADD_SUBDIRECTORY (tools)
+IF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL)
+    ADD_SUBDIRECTORY (bindings)
+ENDIF (ENABLE_PERL OR ENABLE_PYTHON OR ENABLE_RUBY OR ENABLE_TCL)
+ADD_SUBDIRECTORY (examples)
+ADD_SUBDIRECTORY (doc)
+
+MESSAGE (STATUS "Version: ${VERSION}")
+
+####################################################################
+# RPM SPEC                                                         #
+####################################################################
+
+MACRO (SPECFILE)
+  MESSAGE (STATUS "Writing spec file...")
+  CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/package/libsolv.spec.in ${CMAKE_BINARY_DIR}/package/libsolv.spec @ONLY)
+ENDMACRO (SPECFILE)
+
+MACRO (PCFILE)
+  MESSAGE (STATUS "Writing pkg-config files...")
+  CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/libsolv.pc.in ${CMAKE_BINARY_DIR}/libsolv.pc @ONLY)
+  INSTALL( FILES ${CMAKE_BINARY_DIR}/libsolv.pc DESTINATION ${PKGCONFIG_INSTALL_DIR} )
+  CONFIGURE_FILE (${CMAKE_SOURCE_DIR}/libsolvext.pc.in ${CMAKE_BINARY_DIR}/libsolvext.pc @ONLY)
+  INSTALL( FILES ${CMAKE_BINARY_DIR}/libsolvext.pc DESTINATION ${PKGCONFIG_INSTALL_DIR} )
+ENDMACRO (PCFILE)
+
+SPECFILE ()
+PCFILE ()
+
+SET (AUTOBUILD_COMMAND
+  COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/package/*.tar.bz2
+  COMMAND mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}
+  COMMAND ${CMAKE_MAKE_PROGRAM} package_source
+  COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2 ${CMAKE_BINARY_DIR}/package
+  COMMAND ${CMAKE_COMMAND} -E remove ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.bz2
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/package/libsolv.changes" "${CMAKE_BINARY_DIR}/package/libsolv.changes"
+)
+
+ADD_CUSTOM_TARGET (srcpackage
+  ${AUTOBUILD_COMMAND}
+)
+
+ADD_CUSTOM_TARGET (srcpackage_local
+  ${AUTOBUILD_COMMAND}
+)
+
+ENABLE_TESTING()
+ADD_SUBDIRECTORY (test)
diff --git a/libsolv-0.7.2/CREDITS b/libsolv-0.7.2/CREDITS
new file mode 100644 (file)
index 0000000..049bcae
--- /dev/null
@@ -0,0 +1,25 @@
+
+Klaus Kaempf
+  - old language bindings
+
+Duncan Mac-Vicar Prett
+  - cmake support
+  - old ruby bindings
+  - many of the xml parsers
+
+Michael Matz
+  - repodata storage
+  - repopage compression
+  - dataiterator code
+
+Michael Schroeder
+  - overall design
+  - pool & solver implementation
+  - new language
+  - debian support
+  - mandriva/mageia support
+  - archlinux support
+
+Ingo Weinhold
+  - haiku support
+
diff --git a/libsolv-0.7.2/INSTALL b/libsolv-0.7.2/INSTALL
new file mode 100644 (file)
index 0000000..5b1df67
--- /dev/null
@@ -0,0 +1,18 @@
+Compiling and installing the software
+
+Requirements:
+
+- C compiler
+- cmake
+- make
+- expat
+
+Steps to compile/install:
+
+1. mkdir build
+2. cd build
+3. cmake ..
+4. make
+
+5. make install
+
diff --git a/libsolv-0.7.2/LICENSE.BSD b/libsolv-0.7.2/LICENSE.BSD
new file mode 100644 (file)
index 0000000..79c9f2d
--- /dev/null
@@ -0,0 +1,28 @@
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of Novell nor the names of its contributors may
+   be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/libsolv-0.7.2/NEWS b/libsolv-0.7.2/NEWS
new file mode 100644 (file)
index 0000000..812a923
--- /dev/null
@@ -0,0 +1,183 @@
+
+This file contains the major changes between
+libsolv versions:
+
+Version 0.7.2
+- bug fixes:
+  * do not autouninstall packages because of forcebest updates
+- new features:
+  * support rpm's new '^' version separator
+  * support set/get_considered_list in bindings
+  * new experimental SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED flag
+
+Version 0.7.1
+- fix nasty off-by-one error in repo_write
+
+Version 0.7.0
+- soname bump to "1"
+- incompatible API changes:
+  * bindings: Selection.flags is now an attribute
+  * repodata_lookup_num now works like the other lookup_num functions
+- new functions:
+  * selection_make_matchsolvable
+  * selection_make_matchsolvablelist
+  * pool_whatmatchessolvable
+  * repodata_search_arrayelement
+  * repodata_lookup_kv_uninternalized
+  * repodata_search_uninternalized
+  * repodata_translate_dir
+- new repowriter interface to write solv files allowing better
+  control over what gets written
+- support for filtered file lists with a custom filter
+- dropped support of (since a long time unused) REPOKEY_TYPE_U32
+
+Version 0.6.35
+- new configuration options:
+  * ENABLE_ZSTD_COMPRESSION: support zstd compression
+  * ENABLE_ZCHUNK_COMPRESSION: support zchunk compression
+- new features:
+  * new repodata_set_kv() function
+  * new pool_solvable2id() inline function
+  * bindings: new str2dir, dir2str, add_dirstr repodata methods
+- other changes
+  * new repo2solv tool replacing the old shell script
+
+Version 0.6.34
+- new features:
+  * also look at suggests for package ordering
+
+Version 0.6.33
+- new features:
+  * new Selection.clone() method in the bindings
+  * new pool.parserpmrichdep() method in the bindings
+
+Version 0.6.32
+- fixed bug that could make fileconflict detection very slow
+  in some cases
+
+Version 0.6.31
+- new configuration options:
+  * ENABLE_RPMDB_LIBRPM: use librpm to read the package
+    database
+  * ENABLE_RPMPKG_LIBRPM: use librpm to access information
+    from package headers
+- new features:
+  * new pool_set_whatprovides function to manually change
+    the whatprovides data
+  * new selection_subtract function to remove packages of
+    one selection from another selection
+  * new selection flags SELECTION_FILTER,
+    SELECTION_WITH_DISABLED and SELECTION_WITH_BADARCH
+  * new map_invertall function to invert a bitmap
+  * new map_clr_at function to clear some bits
+
+Version 0.6.30
+- new features:
+  * many fixes and extenstions for cleandeps, e.g.
+    cleandeps now works for "update all packages"
+  * support debian packages with xz compressed control.tar
+  * always create dup rules for "distupgrade" jobs
+  * use recommends also for ordering packages
+
+Version 0.6.29
+- new features:
+  * support for REL_WITHOUT and REL_UNLESS dependencies
+  * solver_get_recommendations available in bindings
+
+Version 0.6.28
+- new features:
+  * new pool_best_solvables() function
+
+Version 0.6.27
+- new features:
+  * allow building with libxml2 instead of libexpat
+  * better handing of "forcebest with uninstall"
+  * speed improvements for "name = md5sum" dependencies
+
+Version 0.6.26
+- export solvable_matchesdep function, as we now
+  use it in the bindings
+
+Version 0.6.25
+- new features:
+  * new SOLVER_FLAG_STRONG_RECOMMENDS flag
+  * new SOLVER_FLAG_INSTALL_ALSO_UPDATES flag
+  * new matchesdep() method in bindings
+  * SOLVABLE_NAME selects nevr matching for
+    pool_whatmatchesdep and solvable_matchesdep
+Version 0.6.24
+- new features:
+  * new SOLVER_FLAG_FOCUS_BEST flag
+
+Version 0.6.22, 0.6.23
+- bug fix releases, no new features
+
+Version 0.6.21
+- new features:
+  * SOLVER_FAVOR and SOLVER_DISFAVOR job types
+- new functions:
+  * selection_make_matchdepid
+  * pool_whatcontainsdep
+  * pool_parserpmrichdep
+
+Version 0.6.20
+- new features:
+  * filter Requires(pre,post) for installed packages
+
+Version 0.6.13:
+- new features:
+  * SOLVER_ALLOWUNINSTALL job type
+  * ordercycle introspection
+- new functions:
+  * transaction_order_get_cycle
+  * transaction_order_get_cycleids
+
+Version 0.6.12:
+- new features:
+  * tcl bindings
+- new functions:
+  * solv_chksum_cmp
+
+Version 0.6.11:
+- new functions:
+  * pool_ids2whatprovides
+
+Version 0.6.9:
+- new features:
+  * much improved package choosing code
+  * new testcase dependency format
+  * alternatives introspection
+- new functions:
+  * pool_deb_get_autoinstalled
+  * solver_alternative2str
+  * solver_alternatives_count
+  * solver_get_alternative
+  * solver_rule2pkgrule
+  * testcase_dep2str
+
+Version 0.6.5:
+- new features:
+  * support yum style obsolete handling
+
+Version 0.6.1:
+- API change:
+  repodata_stringify() now returns the string
+- new features:
+  * add BREAK_ORPHANS and KEEP_ORPHANS solver flags
+
+Version 0.6.0:
+- ABI change: cleaned up and reordered knownid.h
+- added support for sha224/sha384/sha512
+- API change in the bindings:
+  * dropped solvid arg from most Dataiterator
+    constructors
+  * changed Datamatch results from methods to
+    attributes
+  * automatically delete the pool if the owner
+    object is freed (use the disown method to
+    get the old behavior).
+- new functions:
+  * pool_add_userinstalled_jobs
+  * solver_get_userinstalled
+
diff --git a/libsolv-0.7.2/README b/libsolv-0.7.2/README
new file mode 100644 (file)
index 0000000..0242459
--- /dev/null
@@ -0,0 +1,49 @@
+Libsolv
+=======
+
+This is libsolv, a free package dependency solver using a satisfiability
+algorithm.
+
+The code is based on two major, but independent, blocks:
+
+ 1. Using a dictionary approach to store and retrieve package and
+    dependency information in a fast and space efficient manner.
+
+ 2. Using satisfiability, a well known and researched topic, for
+    resolving package dependencies.
+
+The sat-solver code has been written to aim for the newest packages,
+record the decision tree to provide introspection, and also allows to
+provide the user with suggestions on how to deal with unsolvable
+problems. It also takes advantage of the repository storage to
+minimize memory usage.
+
+Supported package formats:
+
+  - rpm/rpm5
+  - deb
+  - arch linux
+  - haiku
+
+Supported repository formats:
+
+  - rpmmd (primary, filelists, comps, deltainfo/presto, updateinfo)
+  - susetags, suse product formats
+  - mandriva/mageia (synthesis, info, files)
+  - arch linux
+  - red carpet helix format
+  - haiku
+
+Build instructions
+==================
+
+Requires: cmake 2.4.x
+
+    mkdir build
+    cd build
+    cmake ..
+    make
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/TODO_1.0 b/libsolv-0.7.2/TODO_1.0
new file mode 100644 (file)
index 0000000..d77df67
--- /dev/null
@@ -0,0 +1,18 @@
+
+- implement package priority (for things like Debian's pin feature)
+
+- merge SUSETAGS_FILE_* and  REPOSITORY_REPOMD_* keys into REPOSITORY_RESOURCE
+
+- re-order key ids
+
+- deal with DIRSTR entries having dirid 0 (for source rpms)
+
+- drop patchcheck
+
+- make FAVOR handling deal with versions
+
+- write more manpages
+
+IDEAS:
+
+drop SEARCH_FILES and add SEARCH_BASENAME instead?
diff --git a/libsolv-0.7.2/VERSION.cmake b/libsolv-0.7.2/VERSION.cmake
new file mode 100644 (file)
index 0000000..507716c
--- /dev/null
@@ -0,0 +1,53 @@
+# ==================================================
+# Versioning
+# ==========
+#
+# MAJOR Major number for this branch.
+#
+# MINOR The most recent interface number this
+#     library implements.
+#
+# COMPATMINOR The latest binary compatible minor number
+#     this library implements.
+#
+# PATCH The implementation number of the current interface.
+#
+#
+# - The package VERSION will be MAJOR.MINOR.PATCH.
+#
+# - Libtool's -version-info will be derived from MAJOR, MINOR, PATCH
+#   and COMPATMINOR (see configure.ac).
+#
+# - Changing MAJOR always breaks binary compatibility.
+#
+# - Changing MINOR doesn't break binary compatibility by default.
+#   Only if COMPATMINOR is changed as well.
+#
+#
+# 1) After branching from TRUNK increment TRUNKs MAJOR and
+#    start with version `MAJOR.0.0' and also set COMPATMINOR to 0.
+#
+# 2) Update the version information only immediately before a public release
+#    of your software. More frequent updates are unnecessary, and only guarantee
+#    that the current interface number gets larger faster.
+#
+# 3) If the library source code has changed at all since the last update,
+#    then increment PATCH.
+#
+# 4) If any interfaces have been added, removed, or changed since the last
+#    update, increment MINOR, and set PATCH to 0.
+#
+# 5) If any interfaces have been added since the last public release, then
+#    leave COMPATMINOR unchanged. (binary compatible change)
+#
+# 6) If any interfaces have been removed since the last public release, then
+#    set COMPATMINOR to MINOR. (binary incompatible change)
+#
+
+SET(LIBSOLV_SOVERSION "1")
+SET(LIBSOLVEXT_SOVERSION "1")
+
+SET(LIBSOLV_MAJOR "0")
+SET(LIBSOLV_MINOR "7")
+SET(LIBSOLV_PATCH "2")
+
diff --git a/libsolv-0.7.2/bindings/CMakeLists.txt b/libsolv-0.7.2/bindings/CMakeLists.txt
new file mode 100644 (file)
index 0000000..737cee4
--- /dev/null
@@ -0,0 +1,22 @@
+SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+
+FIND_PACKAGE (SWIG)
+
+MESSAGE (STATUS "Found SWIG version ${SWIG_VERSION}")
+SET (SWIG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/solv.i")
+
+IF (ENABLE_PYTHON)
+    ADD_SUBDIRECTORY (python)
+ENDIF (ENABLE_PYTHON)
+IF (ENABLE_PYTHON3)
+    ADD_SUBDIRECTORY (python3)
+ENDIF (ENABLE_PYTHON3)
+IF (ENABLE_PERL)
+    ADD_SUBDIRECTORY (perl)
+ENDIF (ENABLE_PERL)
+IF (ENABLE_RUBY)
+    ADD_SUBDIRECTORY (ruby)
+ENDIF (ENABLE_RUBY)
+IF (ENABLE_TCL)
+    ADD_SUBDIRECTORY (tcl)
+ENDIF (ENABLE_TCL)
diff --git a/libsolv-0.7.2/bindings/perl/CMakeLists.txt b/libsolv-0.7.2/bindings/perl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..49a3902
--- /dev/null
@@ -0,0 +1,37 @@
+FIND_PACKAGE (Perl)
+
+EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{ccflags}" OUTPUT_VARIABLE PERL_CCFLAGS)
+EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{archlib}.\"/CORE\"" OUTPUT_VARIABLE PERL_CORE_DIR)
+EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{ccldflags}" OUTPUT_VARIABLE PERL_CCLDFLAGS)
+EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{installsitearch}" OUTPUT_VARIABLE PERL_SITEARCHDIR)
+EXECUTE_PROCESS(COMMAND ${PERL_EXECUTABLE} -e "use Config; print \$Config{installvendorarch}" OUTPUT_VARIABLE PERL_VENDORARCHDIR)
+
+IF (USE_VENDORDIRS)
+    SET (PERL_INSTALL_DIR ${PERL_VENDORARCHDIR})
+ELSE (USE_VENDORDIRS)
+    SET (PERL_INSTALL_DIR ${PERL_SITEARCHDIR})
+ENDIF (USE_VENDORDIRS)
+
+MESSAGE (STATUS "Perl executable: ${PERL_EXECUTABLE}")
+MESSAGE (STATUS "Perl installation dir: ${PERL_INSTALL_DIR}")
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv_perl.c
+    COMMAND ${SWIG_EXECUTABLE} -perl ${SWIG_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_perl.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    COMMAND sed -i -e "s/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/" solv_perl.c
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    VERBATIM
+)
+
+ADD_DEFINITIONS(${PERL_CCFLAGS} -Wno-unused -Wno-nonnull)
+LINK_DIRECTORIES (${PERL_CORE_DIR})
+INCLUDE_DIRECTORIES (${PERL_INCLUDE_PATH} ${PERL_CORE_DIR})
+
+ADD_LIBRARY (bindings_perl MODULE solv_perl.c)
+SET_TARGET_PROPERTIES (bindings_perl PROPERTIES PREFIX "" OUTPUT_NAME "solv")
+SET_TARGET_PROPERTIES (bindings_perl PROPERTIES LINK_FLAGS "${PERL_CCLDFLAGS}")
+TARGET_LINK_LIBRARIES (bindings_perl libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL (TARGETS bindings_perl LIBRARY DESTINATION ${PERL_INSTALL_DIR})
+INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.pm DESTINATION ${PERL_INSTALL_DIR})
diff --git a/libsolv-0.7.2/bindings/python/CMakeLists.txt b/libsolv-0.7.2/bindings/python/CMakeLists.txt
new file mode 100644 (file)
index 0000000..64ef528
--- /dev/null
@@ -0,0 +1,46 @@
+IF (ENABLE_PYTHON3 AND NOT DEFINED PythonLibs_FIND_VERSION)
+    # if we build both for python2 and python3, make this the python2 build.
+    # see comment in the python3 CMakeLists.txt file
+    SET (PythonLibs_FIND_VERSION 2)
+    SET (PythonLibs_FIND_VERSION_MAJOR 2)
+ENDIF (ENABLE_PYTHON3 AND NOT DEFINED PythonLibs_FIND_VERSION)
+
+FIND_PACKAGE (PythonLibs REQUIRED)
+IF(PYTHONLIBS_VERSION_STRING MATCHES "^([0-9.]+)")
+    SET(python_version "${CMAKE_MATCH_1}")
+ELSE()
+    MESSAGE(FATAL_ERROR "PythonLibs version format unknown '${PYTHONLIBS_VERSION_STRING}'")
+ENDIF()
+FIND_PACKAGE (PythonInterp ${python_version} REQUIRED)
+
+EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON_INSTALL_DIR)
+
+IF (NOT DEFINED PYTHON_VERSION_MAJOR)
+    SET (PYTHON_VERSION_MAJOR 2)
+ENDIF (NOT DEFINED PYTHON_VERSION_MAJOR)
+IF (${PYTHON_VERSION_MAJOR} GREATER 2)
+    SET (SWIG_PY_FLAGS -DPYTHON3=1)
+ENDIF (${PYTHON_VERSION_MAJOR} GREATER 2)
+SET (SWIG_PY_FLAGS ${SWIG_PY_FLAGS} -DSWIG_PYTHON_LEGACY_BOOL=1)
+
+MESSAGE (STATUS "Python executable: ${PYTHON_EXECUTABLE}")
+MESSAGE (STATUS "Python installation dir: ${PYTHON_INSTALL_DIR}")
+MESSAGE (STATUS "Python include path: ${PYTHON_INCLUDE_PATH}")
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv_python.c
+    COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -python ${SWIG_PY_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_python.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
+)
+
+ADD_DEFINITIONS(-Wno-unused)
+INCLUDE_DIRECTORIES (${PYTHON_INCLUDE_PATH})
+
+ADD_LIBRARY (bindings_python MODULE solv_python.c)
+SET_TARGET_PROPERTIES (bindings_python PROPERTIES PREFIX "" OUTPUT_NAME "_solv")
+TARGET_LINK_LIBRARIES (bindings_python libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL (TARGETS bindings_python LIBRARY DESTINATION ${PYTHON_INSTALL_DIR})
+INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.py DESTINATION ${PYTHON_INSTALL_DIR})
+
diff --git a/libsolv-0.7.2/bindings/python3/CMakeLists.txt b/libsolv-0.7.2/bindings/python3/CMakeLists.txt
new file mode 100644 (file)
index 0000000..28e8e00
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# used for building both python2 and python3 bindings
+# do not use if you want to build just one flavor, use the
+# standard python bindings file in that case.
+#
+# we cannot use FIND_PACKAGE PythonLibs here, as this would
+# clash with the python variables.
+#
+IF (NOT DEFINED PYTHON3_EXECUTABLE)
+SET (PYTHON3_EXECUTABLE "/usr/bin/python3")
+ENDIF (NOT DEFINED PYTHON3_EXECUTABLE)
+
+EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_lib(True))" OUTPUT_VARIABLE PYTHON3_INSTALL_DIR)
+EXECUTE_PROCESS(COMMAND ${PYTHON3_EXECUTABLE} -c "from sys import stdout; from distutils import sysconfig; stdout.write(sysconfig.get_python_inc())" OUTPUT_VARIABLE PYTHON3_INCLUDE_DIR)
+
+SET (SWIG_PY3_FLAGS -DPYTHON3=1)
+SET (SWIG_PY3_FLAGS ${SWIG_PY3_FLAGS} -DSWIG_PYTHON_LEGACY_BOOL=1)
+
+MESSAGE (STATUS "Python3 executable: ${PYTHON3_EXECUTABLE}")
+MESSAGE (STATUS "Python3 installation dir: ${PYTHON3_INSTALL_DIR}")
+MESSAGE (STATUS "Python3 include path: ${PYTHON3_INCLUDE_DIR}")
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv_python.c
+    COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -python ${SWIG_PY3_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_python.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
+)
+
+ADD_DEFINITIONS(-Wno-unused)
+INCLUDE_DIRECTORIES (${PYTHON3_INCLUDE_DIR})
+
+ADD_LIBRARY (bindings_python3 SHARED solv_python.c)
+SET_TARGET_PROPERTIES (bindings_python3 PROPERTIES PREFIX "" OUTPUT_NAME "_solv")
+TARGET_LINK_LIBRARIES (bindings_python3 libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL (TARGETS bindings_python3 LIBRARY DESTINATION ${PYTHON3_INSTALL_DIR})
+INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.py DESTINATION ${PYTHON3_INSTALL_DIR})
diff --git a/libsolv-0.7.2/bindings/ruby/CMakeLists.txt b/libsolv-0.7.2/bindings/ruby/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6c3bd50
--- /dev/null
@@ -0,0 +1,26 @@
+FIND_PACKAGE (Ruby)
+
+IF (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR)
+    SET (RUBY_INSTALL_DIR ${RUBY_VENDORARCH_DIR})
+ELSE (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR)
+    SET (RUBY_INSTALL_DIR ${RUBY_SITEARCH_DIR})
+ENDIF (USE_VENDORDIRS AND RUBY_VENDORARCH_DIR)
+
+MESSAGE (STATUS "Ruby executable: ${RUBY_EXECUTABLE}")
+MESSAGE (STATUS "Ruby installation dir: ${RUBY_INSTALL_DIR}")
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv_ruby.c
+    COMMAND ${SWIG_EXECUTABLE} -ruby ${SWIG_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_ruby.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
+)
+
+ADD_DEFINITIONS(-Wno-unused)
+INCLUDE_DIRECTORIES (${RUBY_INCLUDE_PATH})
+
+ADD_LIBRARY (bindings_ruby MODULE solv_ruby.c)
+SET_TARGET_PROPERTIES (bindings_ruby PROPERTIES PREFIX "" OUTPUT_NAME "solv")
+TARGET_LINK_LIBRARIES (bindings_ruby libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL (TARGETS bindings_ruby LIBRARY DESTINATION ${RUBY_INSTALL_DIR})
diff --git a/libsolv-0.7.2/bindings/solv.i b/libsolv-0.7.2/bindings/solv.i
new file mode 100644 (file)
index 0000000..93a97db
--- /dev/null
@@ -0,0 +1,4102 @@
+/*
+ * WARNING: for perl iterator/array support you need to run
+ *   sed -i -e 's/SvTYPE(tsv) == SVt_PVHV/SvTYPE(tsv) == SVt_PVHV || SvTYPE(tsv) == SVt_PVAV/'
+ * on the generated c code
+ */
+
+%module solv
+
+#ifdef SWIGRUBY
+%markfunc Pool "mark_Pool";
+#endif
+
+/**
+ ** binaryblob handling
+ **/
+
+%{
+typedef struct {
+  const void *data;
+  size_t len;
+} BinaryBlob;
+%}
+
+%typemap(in,noblock=1,fragment="SWIG_AsCharPtrAndSize") (const unsigned char *str, size_t len) (int res, char *buf = 0, size_t size = 0, int alloc = 0) {
+#if defined(SWIGTCL)
+  {
+    int bal;
+    unsigned char *ba;
+    res = SWIG_TypeError;
+    ba = Tcl_GetByteArrayFromObj($input, &bal);
+    if (ba) {
+      buf = (char *)ba;
+      size = bal;
+      res = SWIG_OK;
+      alloc = SWIG_OLDOBJ;
+    }
+  }
+#else
+  res = SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc);
+  if (buf && size)
+    size--;
+#endif
+  if (!SWIG_IsOK(res)) {
+#if defined(SWIGPYTHON)
+    const void *pybuf = 0;
+    Py_ssize_t pysize = 0;
+    res = PyObject_AsReadBuffer($input, &pybuf, &pysize);
+    if (res < 0) {
+      %argument_fail(res, "BinaryBlob", $symname, $argnum);
+    } else {
+      buf = (void *)pybuf;
+      size = pysize;
+    }
+#else
+    %argument_fail(res, "const char *", $symname, $argnum);
+#endif
+  }
+  $1 = (unsigned char *)buf;
+  $2 = size;
+}
+
+%typemap(freearg,noblock=1,match="in") (const unsigned char *str, int len) {
+  if (alloc$argnum == SWIG_NEWOBJ) %delete_array(buf$argnum);
+}
+
+%typemap(out,noblock=1,fragment="SWIG_FromCharPtrAndSize") BinaryBlob {
+#if defined(SWIGPYTHON) && defined(PYTHON3)
+  $result = $1.data ? Py_BuildValue("y#", $1.data, $1.len) : SWIG_Py_Void();
+#elif defined(SWIGTCL)
+  Tcl_SetObjResult(interp, $1.data ? Tcl_NewByteArrayObj($1.data, $1.len) : NULL);
+#else
+  $result = SWIG_FromCharPtrAndSize($1.data, $1.len);
+#if defined(SWIGPERL)
+  argvi++;
+#endif
+#endif
+}
+
+/**
+ ** Queue handling
+ **/
+
+%typemap(arginit) Queue {
+  queue_init(&$1);
+}
+%typemap(freearg) Queue {
+  queue_free(&$1);
+}
+
+#if defined(SWIGPYTHON)
+
+%typemap(out) Queue {
+  int i;
+  PyObject *o = PyList_New($1.count);
+  for (i = 0; i < $1.count; i++)
+    PyList_SetItem(o, i, SWIG_From_int($1.elements[i]));
+  queue_free(&$1);
+  $result = o;
+}
+
+%define Queue2Array(type, step, con) %{ {
+  int i;
+  int cnt = $1.count / step;
+  Id *idp = $1.elements;
+  PyObject *o = PyList_New(cnt);
+  for (i = 0; i < cnt; i++, idp += step)
+    {
+      Id id = *idp;
+#define result resultx
+      type result = con;
+      $typemap(out, type)
+      PyList_SetItem(o, i, $result);
+#undef result
+    }
+  queue_free(&$1);
+  $result = o;
+}
+%}
+%enddef
+
+%define Array2Queue(asval_meth,typestr) %{ {
+  int i, size;
+  if (!PyList_Check($input))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  size = PyList_Size($input);
+  for (i = 0; i < size; i++) {
+    PyObject *o = PyList_GetItem($input,i);
+    int v;
+    int e = asval_meth(o, &v);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only" typestr);
+    queue_push(&$1, v);
+  }
+}
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  int i, size;
+  if (!PyList_Check($input))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  size = PyList_Size($input);
+  for (i = 0; i < size; i++) {
+    PyObject *o = PyList_GetItem($input,i);
+    type obj;
+    int e = SWIG_ConvertPtr(o, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
+
+#endif  /* SWIGPYTHON */
+
+#if defined(SWIGPERL)
+/* AV *o = newAV();
+ * av_push(o, SvREFCNT_inc(SWIG_From_int($1.elements[i])));
+ * $result = newRV_noinc((SV*)o); argvi++;
+ */
+%typemap(out) Queue {
+  int i;
+  if (argvi + $1.count + 1 >= items) {
+    EXTEND(sp, (argvi + $1.count + 1) - items + 1);
+  }
+  for (i = 0; i < $1.count; i++)
+    ST(argvi++) = SvREFCNT_inc(SWIG_From_int($1.elements[i]));
+  queue_free(&$1);
+  $result = 0;
+}
+
+%define Queue2Array(type, step, con) %{ {
+  int i;
+  int cnt = $1.count / step;
+  Id *idp = $1.elements;
+  if (argvi + cnt + 1 >= items) {
+    EXTEND(sp, (argvi + cnt + 1) - items + 1);
+  }
+  for (i = 0; i < cnt; i++, idp += step)
+    {
+      Id id = *idp;
+#define result resultx
+      type result = con;
+      $typemap(out, type)
+      SvREFCNT_inc(ST(argvi - 1));
+#undef result
+    }
+  queue_free(&$1);
+  $result = 0;
+}
+%}
+%enddef
+
+%define Array2Queue(asval_meth,typestr) %{ {
+  AV *av;
+  int i, size;
+  if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV)
+    SWIG_croak("argument $argnum is not an array reference.");
+  av = (AV*)SvRV($input);
+  size = av_len(av);
+  for (i = 0; i <= size; i++) {
+    SV **sv = av_fetch(av, i, 0);
+    int v;
+    int e = asval_meth(*sv, &v);
+    if (!SWIG_IsOK(e))
+      SWIG_croak("array in argument $argnum must contain only " typestr);
+    queue_push(&$1, v);
+  }
+}
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  AV *av;
+  int i, size;
+  if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV)
+    SWIG_croak("argument $argnum is not an array reference.");
+  av = (AV*)SvRV($input);
+  size = av_len(av);
+  for (i = 0; i <= size; i++) {
+    SV **sv = av_fetch(av, i, 0);
+    type obj;
+    int e = SWIG_ConvertPtr(*sv, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
+
+#endif  /* SWIGPERL */
+
+
+#if defined(SWIGRUBY)
+%typemap(out) Queue {
+  int i;
+  VALUE o = rb_ary_new2($1.count);
+  for (i = 0; i < $1.count; i++)
+    rb_ary_store(o, i, SWIG_From_int($1.elements[i]));
+  queue_free(&$1);
+  $result = o;
+}
+
+%define Queue2Array(type, step, con) %{ {
+  int i;
+  int cnt = $1.count / step;
+  Id *idp = $1.elements;
+  VALUE o = rb_ary_new2(cnt);
+  for (i = 0; i < cnt; i++, idp += step)
+    {
+      Id id = *idp;
+#define result resultx
+      type result = con;
+      $typemap(out, type)
+      rb_ary_store(o, i, $result);
+#undef result
+    }
+  queue_free(&$1);
+  $result = o;
+}
+%}
+%enddef
+
+%define Array2Queue(asval_meth,typestr) %{ {
+  int size, i;
+  VALUE *o, ary;
+  ary = rb_Array($input);
+  size = RARRAY_LEN(ary);
+  i = 0;
+  o = RARRAY_PTR(ary);
+  for (i = 0; i < size; i++, o++) {
+    int v;
+    int e = asval_meth(*o, &v);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_TypeError, "list in argument $argnum must contain only " typestr);
+    queue_push(&$1, v);
+  }
+}
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  int size, i;
+  VALUE *o, ary;
+  ary = rb_Array($input);
+  size = RARRAY_LEN(ary);
+  i = 0;
+  o = RARRAY_PTR(ary);
+  for (i = 0; i < size; i++, o++) {
+    type obj;
+    int e = SWIG_ConvertPtr(*o, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
+
+#endif  /* SWIGRUBY */
+
+#if defined(SWIGTCL)
+%typemap(out) Queue {
+  Tcl_Obj *objvx[$1.count];
+  int i;
+
+  for (i = 0; i < $1.count; i++) {
+    objvx[i] = SWIG_From_int($1.elements[i]);
+  }
+  Tcl_SetObjResult(interp, Tcl_NewListObj($1.count, objvx));
+  queue_free(&$1);
+}
+
+%define Queue2Array(type, step, con) %{
+  { /* scope is needed to make the goto of SWIG_exception_fail work */
+    int i;
+    int cnt = $1.count / step;
+    Id *idp = $1.elements;
+    Tcl_Obj *objvx[cnt];
+
+    for (i = 0; i < cnt; i++, idp += step) {
+      Id id = *idp;
+#define result resultx
+#define Tcl_SetObjResult(i, x) resultobj = x
+      type result = con;
+      Tcl_Obj *resultobj;
+      $typemap(out, type)
+      objvx[i] = resultobj;
+#undef Tcl_SetObjResult
+#undef result
+    }
+    queue_free(&$1);
+    Tcl_SetObjResult(interp, Tcl_NewListObj(cnt, objvx));
+ }
+%}
+%enddef
+
+%define Array2Queue(asval_meth,typestr) %{ {
+  int size = 0;
+  int i = 0;
+  if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  for (i = 0; i < size; i++) {
+    Tcl_Obj *o = NULL;
+    int e, v;
+
+    if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
+      SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
+    e = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(o, &v);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only " typestr);
+    queue_push(&$1, v);
+  }
+}
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  int size = 0;
+  int i = 0;
+  if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  for (i = 0; i < size; i++) {
+    Tcl_Obj *o = NULL;
+    type obj;
+    int e;
+    if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
+      SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
+    e = SWIG_ConvertPtr(o, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
+
+#endif  /* SWIGTCL */
+
+%typemap(in) Queue Array2Queue(SWIG_AsVal_int, "integers")
+%typemap(in) Queue solvejobs ObjArray2Queue(Job *, queue_push2(&$1, obj->how, obj->what))
+
+
+
+#if defined(SWIGPERL)
+
+/* work around a swig bug for swig versions < 2.0.5 */
+#if SWIG_VERSION < 0x020005
+%{
+#undef SWIG_CALLXS
+#ifdef PERL_OBJECT
+#  define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(cv,pPerl)
+#else
+#  ifndef MULTIPLICITY
+#    define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(cv)
+#  else
+#    define SWIG_CALLXS(_name) TOPMARK=MARK-PL_stack_base;_name(PERL_GET_THX, cv)
+#  endif
+#endif
+%}
+#endif
+
+
+%define perliter(class)
+  %perlcode {
+    sub class##::FETCH {
+      my $i = ${##class##::ITERATORS}{$_[0]};
+      if ($i) {
+        $_[1] == $i->[0] - 1 ? $i->[1] : undef;
+      } else {
+        $_[0]->__getitem__($_[1]);
+      }
+    }
+    sub class##::FETCHSIZE {
+      my $i = ${##class##::ITERATORS}{$_[0]};
+      if ($i) {
+        ($i->[1] = $_[0]->__next__()) ? ++$i->[0]  : 0;
+      } else {
+        $_[0]->__len__();
+      }
+    }
+  }
+%enddef
+
+%{
+
+#define SWIG_PERL_ITERATOR      0x80
+
+SWIGRUNTIMEINLINE SV *
+SWIG_Perl_NewArrayObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) {
+  SV *result = sv_newmortal();
+  if (ptr && (flags & (SWIG_SHADOW | SWIG_POINTER_OWN))) {
+    SV *self;
+    SV *obj=newSV(0);
+    AV *array=newAV();
+    HV *stash;
+    sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+    stash=SvSTASH(SvRV(obj));
+    if (flags & SWIG_POINTER_OWN) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE);
+      if (!isGV(gv))
+        gv_init(gv, stash, "OWNER", 5, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newSViv(1), 0);
+    }
+    if (flags & SWIG_PERL_ITERATOR) {
+      HV *hv;
+      GV *gv=*(GV**)hv_fetch(stash, "ITERATORS", 9, TRUE);
+      AV *av=newAV();
+      if (!isGV(gv))
+        gv_init(gv, stash, "ITERATORS", 9, FALSE);
+      hv=GvHVn(gv);
+      hv_store_ent(hv, obj, newRV_inc((SV *)av), 0);
+    }
+    sv_magic((SV *)array, (SV *)obj, 'P', Nullch, 0);
+    SvREFCNT_dec(obj);
+    self=newRV_noinc((SV *)array);
+    sv_setsv(result, self);
+    SvREFCNT_dec((SV *)self);
+    sv_bless(result, stash);
+  } else {
+    sv_setref_pv(result, (char *) SWIG_Perl_TypeProxyName(t), ptr);
+  }
+  return result;
+}
+
+%}
+
+%typemap(out) Perlarray {
+  ST(argvi) = SWIG_Perl_NewArrayObj(SWIG_PERL_OBJECT_CALL SWIG_as_voidptr(result), $1_descriptor, $owner | $shadow); argvi++;
+}
+%typemap(out) Perliterator {
+  ST(argvi) = SWIG_Perl_NewArrayObj(SWIG_PERL_OBJECT_CALL SWIG_as_voidptr(result), $1_descriptor, $owner | $shadow | SWIG_PERL_ITERATOR); argvi++;
+}
+
+%typemap(out) Pool_solvable_iterator * = Perlarray;
+%typemap(out) Pool_solvable_iterator * solvables_iter = Perliterator;
+%typemap(out) Pool_repo_iterator * = Perlarray;
+%typemap(out) Pool_repo_iterator * repos_iter = Perliterator;
+%typemap(out) Repo_solvable_iterator * = Perlarray;
+%typemap(out) Repo_solvable_iterator * solvables_iter = Perliterator;
+%typemap(out) Dataiterator * = Perliterator;
+
+#endif  /* SWIGPERL */
+
+
+/**
+ ** appdata handling
+ **/
+
+#if defined(SWIGPYTHON)
+typedef PyObject *AppObjectPtr;
+%typemap(in) AppObjectPtr {
+  if ($input)
+    Py_INCREF($input);
+  $1 = $input;
+}
+%typemap(out) AppObjectPtr {
+  $result = $1 ? $1 : Py_None;
+  Py_INCREF($result);
+}
+#elif defined(SWIGPERL)
+typedef SV *AppObjectPtr;
+%typemap(in) AppObjectPtr {
+  if ($input) {
+    $1 = newSV(0);
+    sv_setsv((SV *)$1, $input);
+  } else
+    $1 = (void *)0;
+}
+%typemap(out) AppObjectPtr {
+  $result = sv_2mortal($1 ? SvREFCNT_inc($1) : newSV(0));
+  argvi++;
+}
+#elif defined(SWIGRUBY)
+typedef VALUE AppObjectPtr;
+%typemap(in) AppObjectPtr {
+  $1 = (void *)$input;
+}
+%typemap(out) AppObjectPtr {
+  $result = (VALUE)$1;
+}
+#elif defined(SWIGTCL)
+typedef Tcl_Obj *AppObjectPtr;
+%typemap(in) AppObjectPtr {
+  if ($input)
+    Tcl_IncrRefCount($input);
+  $1 = (void *)$input;
+}
+%typemap(out) AppObjectPtr {
+  Tcl_SetObjResult(interp, $1 ? $1 : Tcl_NewObj());
+}
+#else
+#warning AppObjectPtr not defined for this language!
+#endif
+
+/**
+ ** FILE handling
+ **/
+
+#ifdef SWIGPYTHON
+%include "file.i"
+#else
+%fragment("SWIG_AsValFilePtr","header") {}
+#endif
+
+
+%fragment("SWIG_AsValSolvFpPtr","header", fragment="SWIG_AsValFilePtr") {
+
+SWIGINTERN int
+#ifdef SWIGRUBY
+SWIG_AsValSolvFpPtr(VALUE obj, FILE **val) {
+#elif defined(SWIGTCL)
+SWIG_AsValSolvFpPtr SWIG_TCL_DECL_ARGS_2(void *obj, FILE **val) {
+#else
+SWIG_AsValSolvFpPtr(void *obj, FILE **val) {
+#endif
+  static swig_type_info* desc = 0;
+  void *vptr = 0;
+  int ecode;
+
+  if (!desc) desc = SWIG_TypeQuery("SolvFp *");
+  if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) {
+    if (val)
+      *val = vptr ? ((SolvFp *)vptr)->fp : 0;
+    return SWIG_OK;
+  }
+#ifdef SWIGPYTHON
+  ecode = SWIG_AsValFilePtr(obj, val);
+  if (ecode == SWIG_OK)
+    return ecode;
+#endif
+  return SWIG_TypeError;
+}
+
+#if defined(SWIGTCL)
+#define SWIG_AsValSolvFpPtr(x, y) SWIG_AsValSolvFpPtr SWIG_TCL_CALL_ARGS_2(x, y)
+#endif
+
+}
+
+
+/**
+ ** DepId handling
+ **/
+
+%fragment("SWIG_AsValDepId","header") {
+
+SWIGINTERN int
+#ifdef SWIGRUBY
+SWIG_AsValDepId(VALUE obj, int *val) {
+#elif defined(SWIGTCL)
+SWIG_AsValDepId SWIG_TCL_DECL_ARGS_2(void *obj, int *val) {
+#else
+SWIG_AsValDepId(void *obj, int *val) {
+#endif
+  static swig_type_info* desc = 0;
+  void *vptr = 0;
+  int ecode;
+  if (!desc) desc = SWIG_TypeQuery("Dep *");
+#ifdef SWIGTCL
+  ecode = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(obj, val);
+#else
+  ecode = SWIG_AsVal_int(obj, val);
+#endif
+  if (SWIG_IsOK(ecode))
+    return ecode;
+  if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) {
+    if (val)
+      *val = vptr ? ((Dep *)vptr)->id : 0;
+    return SWIG_OK;
+  }
+  return SWIG_TypeError;
+}
+
+#ifdef SWIGTCL
+#define SWIG_AsValDepId(x, y) SWIG_AsValDepId SWIG_TCL_CALL_ARGS_2(x, y)
+#endif
+}
+
+/**
+ ** Pool disown helper
+ **/
+
+%typemap(out) disown_helper {
+#if defined(SWIGRUBY)
+  SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
+#elif defined(SWIGPYTHON)
+  SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
+#elif defined(SWIGPERL)
+  SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
+#elif defined(SWIGTCL)
+  SWIG_ConvertPtr(objv[1], &argp1, SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0);
+#else
+#warning disown_helper not implemented for this language, this is likely going to leak memory
+#endif
+
+#ifdef SWIGTCL
+  Tcl_SetObjResult(interp, SWIG_From_int((int)(0)));
+#else
+  $result = SWIG_From_int((int)(0));
+#endif
+}
+
+
+/**
+ ** misc stuff
+ **/
+
+%include "typemaps.i"
+
+%typemap(in,numinputs=0,noblock=1) XRule **OUTPUT ($*1_ltype temp) {
+  $1 = &temp;
+}
+%typemap(argout,noblock=1) XRule **OUTPUT {
+  %append_output(SWIG_NewPointerObj((void*)(*$1), SWIGTYPE_p_XRule, SWIG_POINTER_OWN | %newpointer_flags));
+}
+
+%typemaps_asval(%checkcode(POINTER), SWIG_AsValSolvFpPtr, "SWIG_AsValSolvFpPtr", FILE*);
+%typemaps_asval(%checkcode(INT32), SWIG_AsValDepId, "SWIG_AsValDepId", DepId);
+
+
+/**
+ ** the C declarations
+ **/
+
+%{
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* argh, swig undefs bool for perl */
+#ifndef bool
+typedef int bool;
+#endif
+
+#include "pool.h"
+#include "poolarch.h"
+#include "evr.h"
+#include "solver.h"
+#include "policy.h"
+#include "solverdebug.h"
+#include "repo_solv.h"
+#include "chksum.h"
+#include "selection.h"
+
+#include "repo_write.h"
+#if defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG)
+#include "repo_rpmdb.h"
+#endif
+#ifdef ENABLE_PUBKEY
+#include "repo_pubkey.h"
+#endif
+#ifdef ENABLE_DEBIAN
+#include "repo_deb.h"
+#endif
+#ifdef ENABLE_RPMMD
+#include "repo_rpmmd.h"
+#include "repo_updateinfoxml.h"
+#include "repo_deltainfoxml.h"
+#include "repo_repomdxml.h"
+#endif
+#ifdef ENABLE_SUSEREPO
+#include "repo_products.h"
+#include "repo_susetags.h"
+#include "repo_content.h"
+#endif
+#ifdef ENABLE_MDKREPO
+#include "repo_mdk.h"
+#endif
+#ifdef ENABLE_ARCHREPO
+#include "repo_arch.h"
+#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#if defined(ENABLE_COMPLEX_DEPS) && (defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG))
+#include "pool_parserpmrichdep.h"
+#endif
+#include "solv_xfopen.h"
+#include "testcase.h"
+
+/* for old ruby versions */
+#ifndef RARRAY_PTR
+#define RARRAY_PTR(ary) (RARRAY(ary)->ptr)
+#endif
+#ifndef RARRAY_LEN
+#define RARRAY_LEN(ary) (RARRAY(ary)->len)
+#endif
+
+#define SOLVER_SOLUTION_ERASE                   -100
+#define SOLVER_SOLUTION_REPLACE                 -101
+#define SOLVER_SOLUTION_REPLACE_DOWNGRADE       -102
+#define SOLVER_SOLUTION_REPLACE_ARCHCHANGE      -103
+#define SOLVER_SOLUTION_REPLACE_VENDORCHANGE    -104
+#define SOLVER_SOLUTION_REPLACE_NAMECHANGE      -105
+
+typedef void *AppObjectPtr;
+typedef Id DepId;
+
+typedef struct {
+  Pool *pool;
+  Id id;
+} Dep;
+
+typedef struct {
+  Pool *pool;
+  Id id;
+} XSolvable;
+
+typedef struct {
+  Solver *solv;
+  Id id;
+} XRule;
+
+typedef struct {
+  Repo *repo;
+  Id id;
+} XRepodata;
+
+typedef struct {
+  Pool *pool;
+  Id id;
+} Pool_solvable_iterator;
+
+typedef struct {
+  Pool *pool;
+  Id id;
+} Pool_repo_iterator;
+
+typedef struct {
+  Repo *repo;
+  Id id;
+} Repo_solvable_iterator;
+
+typedef struct {
+  Pool *pool;
+  int how;
+  Id what;
+} Job;
+
+typedef struct {
+  Solver *solv;
+  Id id;
+} Problem;
+
+typedef struct {
+  Solver *solv;
+  Id problemid;
+  Id id;
+} Solution;
+
+typedef struct {
+  Solver *solv;
+  Id problemid;
+  Id solutionid;
+  Id id;
+
+  Id type;
+  Id p;
+  Id rp;
+} Solutionelement;
+
+typedef struct {
+  Solver *solv;
+  Id rid;
+  Id type;
+  Id source;
+  Id target;
+  Id dep_id;
+} Ruleinfo;
+
+typedef struct {
+  Solver *solv;
+  Id type;
+  Id rid;
+  Id from_id;
+  Id dep_id;
+  Id chosen_id;
+  Queue choices;
+  int level;
+} Alternative;
+
+typedef struct {
+  Transaction *transaction;
+  int mode;
+  Id type;
+  int count;
+  Id fromid;
+  Id toid;
+} TransactionClass;
+
+typedef struct {
+  Pool *pool;
+  Queue q;
+  int flags;
+} Selection;
+
+typedef struct {
+  FILE *fp;
+} SolvFp;
+
+typedef Dataiterator Datamatch;
+
+typedef int disown_helper;
+
+struct myappdata {
+  void *appdata;
+  int disowned;
+};
+
+
+%}
+
+/**
+ ** appdata helpers
+ **/
+
+#ifdef SWIGRUBY
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  *appdatap = 0;
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  *appdatap = appdata;
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  return appdata;
+}
+%}
+
+#elif defined(SWIGTCL)
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  if (*appdatap)
+    Tcl_DecrRefCount((Tcl_Obj *)(*appdatap));
+  *appdatap = 0;
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  appdata_clr_helper(appdatap);
+  *appdatap = appdata;
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  return appdata;
+}
+%}
+
+#elif defined(SWIGPYTHON)
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+  struct myappdata *myappdata = appdata;
+  if (!myappdata || !myappdata->appdata || myappdata->disowned)
+    return;
+  myappdata->disowned = 1;
+  Py_DECREF((PyObject *)myappdata->appdata);
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  struct myappdata *myappdata = *(struct myappdata **)appdatap;
+  if (myappdata && myappdata->appdata && !myappdata->disowned) {
+    Py_DECREF((PyObject *)myappdata->appdata);
+  }
+  *appdatap = solv_free(myappdata);
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  appdata_clr_helper(appdatap);
+  if (appdata) {
+    struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1);
+    myappdata->appdata = appdata;
+  }
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  return appdata ? ((struct myappdata *)appdata)->appdata : 0;
+}
+
+%}
+
+#elif defined(SWIGPERL)
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+  struct myappdata *myappdata = appdata;
+  SV *rsv;
+  if (!myappdata || !myappdata->appdata || myappdata->disowned)
+    return;
+  rsv = myappdata->appdata;
+  if (!SvROK(rsv))
+    return;
+  myappdata->appdata = SvRV(rsv);
+  myappdata->disowned = 1;
+  SvREFCNT_dec(rsv);
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  struct myappdata *myappdata = *(struct myappdata **)appdatap;
+  if (myappdata && myappdata->appdata && !myappdata->disowned) {
+    SvREFCNT_dec((SV *)myappdata->appdata);
+  }
+  *appdatap = solv_free(myappdata);
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  appdata_clr_helper(appdatap);
+  if (appdata) {
+    struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1);
+    myappdata->appdata = appdata;
+  }
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  struct myappdata *myappdata = appdata;
+  if (!myappdata || !myappdata->appdata)
+    return 0;
+  return myappdata->disowned ? newRV_noinc((SV *)myappdata->appdata) : myappdata->appdata;
+}
+
+%}
+
+#else
+#warning appdata helpers not implemented for this language
+#endif
+
+
+/**
+ ** the SWIG declarations defining the API
+ **/
+
+#ifdef SWIGRUBY
+%mixin Dataiterator "Enumerable";
+%mixin Pool_solvable_iterator "Enumerable";
+%mixin Pool_repo_iterator "Enumerable";
+%mixin Repo_solvable_iterator "Enumerable";
+#endif
+
+typedef int Id;
+
+%include "knownid.h"
+
+/* from repodata.h */
+%constant Id SOLVID_META;
+%constant Id SOLVID_POS;
+
+%constant int REL_EQ;
+%constant int REL_GT;
+%constant int REL_LT;
+%constant int REL_AND;
+%constant int REL_OR;
+%constant int REL_WITH;
+%constant int REL_NAMESPACE;
+%constant int REL_ARCH;
+%constant int REL_FILECONFLICT;
+%constant int REL_COND;
+%constant int REL_COMPAT;
+%constant int REL_KIND;
+%constant int REL_MULTIARCH;
+%constant int REL_ELSE;
+%constant int REL_ERROR;
+%constant int REL_WITHOUT;
+%constant int REL_UNLESS;
+
+typedef struct {
+  Pool* const pool;
+  int const flags;
+} Selection;
+
+typedef struct {
+  Pool* const pool;
+  Id const id;
+} Dep;
+
+/* put before pool/repo so we can access the constructor */
+%nodefaultdtor Dataiterator;
+typedef struct {} Dataiterator;
+
+typedef struct {
+  Pool* const pool;
+  Id const id;
+} XSolvable;
+
+typedef struct {
+  Solver* const solv;
+  Id const type;
+  Id const dep_id;
+} Ruleinfo;
+
+typedef struct {
+  Solver* const solv;
+  Id const id;
+} XRule;
+
+typedef struct {
+  Repo* const repo;
+  Id const id;
+} XRepodata;
+
+typedef struct {} Pool_solvable_iterator;
+typedef struct {} Pool_repo_iterator;
+typedef struct {} Repo_solvable_iterator;
+
+%nodefaultctor Datamatch;
+%nodefaultdtor Datamatch;
+typedef struct {
+  Pool * const pool;
+  Repo * const repo;
+  Id const solvid;
+} Datamatch;
+
+%nodefaultctor Datapos;
+typedef struct {
+  Repo * const repo;
+} Datapos;
+
+typedef struct {
+  Pool * const pool;
+  int how;
+  Id what;
+} Job;
+
+%nodefaultctor Pool;
+%nodefaultdtor Pool;
+typedef struct {
+} Pool;
+
+%nodefaultctor Repo;
+%nodefaultdtor Repo;
+typedef struct {
+  Pool * const pool;
+  const char * const name;
+  int priority;
+  int subpriority;
+  int const nsolvables;
+} Repo;
+
+%nodefaultctor Solver;
+%nodefaultdtor Solver;
+typedef struct {
+  Pool * const pool;
+} Solver;
+
+typedef struct {
+} Chksum;
+
+#ifdef ENABLE_PUBKEY
+typedef struct {
+  Id const htype;
+  unsigned int const created;
+  unsigned int const expires;
+  const char * const keyid;
+} Solvsig;
+#endif
+
+%rename(xfopen) solvfp_xfopen;
+%rename(xfopen_fd) solvfp_xfopen_fd;
+
+%nodefaultctor SolvFp;
+typedef struct {
+} SolvFp;
+
+%newobject solvfp_xfopen;
+%newobject solvfp_xfopen_fd;
+
+SolvFp *solvfp_xfopen(const char *fn, const char *mode = 0);
+SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode = 0);
+
+%{
+  SWIGINTERN SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode) {
+    SolvFp *sfp;
+    FILE *fp;
+    fd = dup(fd);
+    if (fd == -1)
+      return 0;
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+    fp = solv_xfopen_fd(fn, fd, mode);
+    if (!fp) {
+      close(fd);
+      return 0;
+    }
+    sfp = solv_calloc(1, sizeof(SolvFp));
+    sfp->fp = fp;
+    return sfp;
+  }
+  SWIGINTERN SolvFp *solvfp_xfopen(const char *fn, const char *mode) {
+    SolvFp *sfp;
+    FILE *fp;
+    fp = solv_xfopen(fn, mode);
+    if (!fp)
+      return 0;
+    if (fileno(fp) != -1)
+      fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
+    sfp = solv_calloc(1, sizeof(SolvFp));
+    sfp->fp = fp;
+    return sfp;
+  }
+%}
+
+typedef struct {
+  Solver * const solv;
+  Id const id;
+} Problem;
+
+typedef struct {
+  Solver * const solv;
+  Id const problemid;
+  Id const id;
+} Solution;
+
+typedef struct {
+  Solver *const solv;
+  Id const problemid;
+  Id const solutionid;
+  Id const id;
+  Id const type;
+} Solutionelement;
+
+%nodefaultctor Alternative;
+typedef struct {
+  Solver *const solv;
+  Id const type;
+  Id const rid;
+  Id const from_id;
+  Id const dep_id;
+  Id const chosen_id;
+  int level;
+} Alternative;
+
+%nodefaultctor Transaction;
+%nodefaultdtor Transaction;
+typedef struct {
+  Pool * const pool;
+} Transaction;
+
+typedef struct {
+  Transaction * const transaction;
+  Id const type;
+  Id const fromid;
+  Id const toid;
+  int const count;
+} TransactionClass;
+
+%extend SolvFp {
+  ~SolvFp() {
+    if ($self->fp)
+      fclose($self->fp);
+    free($self);
+  }
+  int fileno() {
+    return $self->fp ? fileno($self->fp) : -1;
+  }
+  int dup() {
+    return $self->fp ? dup(fileno($self->fp)) : -1;
+  }
+  bool write(const unsigned char *str, size_t len) {
+    return fwrite(str, len, 1, $self->fp) == 1;
+  }
+  bool flush() {
+    if (!$self->fp)
+      return 1;
+    return fflush($self->fp) == 0;
+  }
+  bool close() {
+    bool ret;
+    if (!$self->fp)
+      return 1;
+    ret = fclose($self->fp) == 0;
+    $self->fp = 0;
+    return ret;
+  }
+  void cloexec(bool state) {
+    if (!$self->fp || fileno($self->fp) == -1)
+      return;
+    fcntl(fileno($self->fp), F_SETFD, state ? FD_CLOEXEC : 0);
+  }
+}
+
+%extend Job {
+  static const Id SOLVER_SOLVABLE = SOLVER_SOLVABLE;
+  static const Id SOLVER_SOLVABLE_NAME = SOLVER_SOLVABLE_NAME;
+  static const Id SOLVER_SOLVABLE_PROVIDES = SOLVER_SOLVABLE_PROVIDES;
+  static const Id SOLVER_SOLVABLE_ONE_OF = SOLVER_SOLVABLE_ONE_OF;
+  static const Id SOLVER_SOLVABLE_REPO = SOLVER_SOLVABLE_REPO;
+  static const Id SOLVER_SOLVABLE_ALL = SOLVER_SOLVABLE_ALL;
+  static const Id SOLVER_SELECTMASK = SOLVER_SELECTMASK;
+  static const Id SOLVER_NOOP = SOLVER_NOOP;
+  static const Id SOLVER_INSTALL = SOLVER_INSTALL;
+  static const Id SOLVER_ERASE = SOLVER_ERASE;
+  static const Id SOLVER_UPDATE = SOLVER_UPDATE;
+  static const Id SOLVER_WEAKENDEPS = SOLVER_WEAKENDEPS;
+  static const Id SOLVER_MULTIVERSION = SOLVER_MULTIVERSION;
+  static const Id SOLVER_LOCK = SOLVER_LOCK;
+  static const Id SOLVER_DISTUPGRADE = SOLVER_DISTUPGRADE;
+  static const Id SOLVER_VERIFY = SOLVER_VERIFY;
+  static const Id SOLVER_DROP_ORPHANED = SOLVER_DROP_ORPHANED;
+  static const Id SOLVER_USERINSTALLED = SOLVER_USERINSTALLED;
+  static const Id SOLVER_ALLOWUNINSTALL = SOLVER_ALLOWUNINSTALL;
+  static const Id SOLVER_FAVOR = SOLVER_FAVOR;
+  static const Id SOLVER_DISFAVOR = SOLVER_DISFAVOR;
+  static const Id SOLVER_JOBMASK = SOLVER_JOBMASK;
+  static const Id SOLVER_WEAK = SOLVER_WEAK;
+  static const Id SOLVER_ESSENTIAL = SOLVER_ESSENTIAL;
+  static const Id SOLVER_CLEANDEPS = SOLVER_CLEANDEPS;
+  static const Id SOLVER_FORCEBEST = SOLVER_FORCEBEST;
+  static const Id SOLVER_TARGETED = SOLVER_TARGETED;
+  static const Id SOLVER_NOTBYUSER = SOLVER_NOTBYUSER;
+  static const Id SOLVER_SETEV = SOLVER_SETEV;
+  static const Id SOLVER_SETEVR = SOLVER_SETEVR;
+  static const Id SOLVER_SETARCH = SOLVER_SETARCH;
+  static const Id SOLVER_SETVENDOR = SOLVER_SETVENDOR;
+  static const Id SOLVER_SETREPO = SOLVER_SETREPO;
+  static const Id SOLVER_SETNAME = SOLVER_SETNAME;
+  static const Id SOLVER_NOAUTOSET = SOLVER_NOAUTOSET;
+  static const Id SOLVER_SETMASK = SOLVER_SETMASK;
+
+  Job(Pool *pool, int how, Id what) {
+    Job *job = solv_calloc(1, sizeof(*job));
+    job->pool = pool;
+    job->how = how;
+    job->what = what;
+    return job;
+  }
+
+  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject solvables;
+  Queue solvables() {
+    Queue q;
+    queue_init(&q);
+    pool_job2solvables($self->pool, &q, $self->how, $self->what);
+    return q;
+  }
+#ifdef SWIGRUBY
+  %rename("isemptyupdate?") isemptyupdate;
+#endif
+  bool isemptyupdate() {
+    return pool_isemptyupdatejob($self->pool, $self->how, $self->what);
+  }
+
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(Job *j) {
+    return $self->pool == j->pool && $self->how == j->how && $self->what == j->what;
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(Job *j) {
+    return !Job___eq__($self, j);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return pool_job2str($self->pool, $self->how, $self->what, 0);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  const char *__repr__() {
+    const char *str = pool_job2str($self->pool, $self->how, $self->what, ~0);
+    return pool_tmpjoin($self->pool, "<Job ", str, ">");
+  }
+}
+
+%extend Selection {
+  static const Id SELECTION_NAME = SELECTION_NAME;
+  static const Id SELECTION_PROVIDES = SELECTION_PROVIDES;
+  static const Id SELECTION_FILELIST = SELECTION_FILELIST;
+  static const Id SELECTION_CANON = SELECTION_CANON;
+  static const Id SELECTION_DOTARCH = SELECTION_DOTARCH;
+  static const Id SELECTION_REL = SELECTION_REL;
+  static const Id SELECTION_INSTALLED_ONLY = SELECTION_INSTALLED_ONLY;
+  static const Id SELECTION_GLOB = SELECTION_GLOB;
+  static const Id SELECTION_FLAT = SELECTION_FLAT;
+  static const Id SELECTION_NOCASE = SELECTION_NOCASE;
+  static const Id SELECTION_SKIP_KIND = SELECTION_SKIP_KIND;
+  static const Id SELECTION_MATCH_DEPSTR = SELECTION_MATCH_DEPSTR;
+  static const Id SELECTION_SOURCE_ONLY = SELECTION_SOURCE_ONLY;
+  static const Id SELECTION_WITH_SOURCE = SELECTION_WITH_SOURCE;
+  static const Id SELECTION_WITH_DISABLED = SELECTION_WITH_DISABLED;
+  static const Id SELECTION_WITH_BADARCH = SELECTION_WITH_BADARCH;
+  static const Id SELECTION_WITH_ALL = SELECTION_WITH_ALL;
+  static const Id SELECTION_ADD = SELECTION_ADD;
+  static const Id SELECTION_SUBTRACT = SELECTION_SUBTRACT;
+  static const Id SELECTION_FILTER = SELECTION_FILTER;
+  static const Id SELECTION_FILTER_KEEP_IFEMPTY = SELECTION_FILTER_KEEP_IFEMPTY;
+  static const Id SELECTION_FILTER_SWAPPED = SELECTION_FILTER_SWAPPED;
+
+  Selection(Pool *pool) {
+    Selection *s;
+    s = solv_calloc(1, sizeof(*s));
+    s->pool = pool;
+    return s;
+  }
+
+  ~Selection() {
+    queue_free(&$self->q);
+    solv_free($self);
+  }
+#ifdef SWIGRUBY
+  %rename("isempty?") isempty;
+#endif
+  bool isempty() {
+    return $self->q.count == 0;
+  }
+  %newobject clone;
+  Selection *clone(int flags = 0) {
+    Selection *s = new_Selection($self->pool);
+    queue_init_clone(&s->q, &$self->q);
+    s->flags = $self->flags;
+    return s;
+  }
+  void filter(Selection *lsel) {
+    if ($self->pool != lsel->pool)
+      queue_empty(&$self->q);
+    else
+      selection_filter($self->pool, &$self->q, &lsel->q);
+  }
+  void add(Selection *lsel) {
+    if ($self->pool == lsel->pool)
+      {
+        selection_add($self->pool, &$self->q, &lsel->q);
+        $self->flags |= lsel->flags;
+      }
+  }
+  void add_raw(Id how, Id what) {
+    queue_push2(&$self->q, how, what);
+  }
+  void subtract(Selection *lsel) {
+    if ($self->pool == lsel->pool)
+      selection_subtract($self->pool, &$self->q, &lsel->q);
+  }
+  
+  void select(const char *name, int flags) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make($self->pool, &$self->q, name, flags);
+  }
+  void matchdeps(const char *name, int flags, Id keyname, Id marker = -1) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make_matchdeps($self->pool, &$self->q, name, flags, keyname, marker);
+  }
+  void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make_matchdepid($self->pool, &$self->q, dep, flags, keyname, marker);
+  }
+
+  %typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1]));
+  %newobject jobs;
+  Queue jobs(int flags) {
+    Queue q;
+    int i;
+    queue_init_clone(&q, &$self->q);
+    for (i = 0; i < q.count; i += 2)
+      q.elements[i] |= flags;
+    return q;
+  }
+
+  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject solvables;
+  Queue solvables() {
+    Queue q;
+    queue_init(&q);
+    selection_solvables($self->pool, &$self->q, &q);
+    return q;
+  }
+
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return pool_selection2str($self->pool, &$self->q, 0);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  const char *__repr__() {
+    const char *str = pool_selection2str($self->pool, &$self->q, ~0);
+    return pool_tmpjoin($self->pool, "<Selection ", str, ">");
+  }
+}
+
+%extend Chksum {
+  Chksum(Id type) {
+    return solv_chksum_create(type);
+  }
+  Chksum(Id type, const char *hex) {
+    unsigned char buf[64];
+    int l = solv_chksum_len(type);
+    if (!l)
+      return 0;
+    if (solv_hex2bin(&hex, buf, sizeof(buf)) != l || hex[0])
+      return 0;
+    return solv_chksum_create_from_bin(type, buf);
+  }
+  %newobject from_bin;
+  static Chksum *from_bin(Id type, const unsigned char *str, size_t len) {
+    return len == solv_chksum_len(type) ? solv_chksum_create_from_bin(type, str) : 0;
+  }
+#if defined(SWIGPERL)
+  %perlcode {
+    undef *solv::Chksum::from_bin;
+    *solv::Chksum::from_bin = sub {
+      my $pkg = shift;
+      my $self = solvc::Chksum_from_bin(@_);
+      bless $self, $pkg if defined $self;
+    };
+  }
+#endif
+  ~Chksum() {
+    solv_chksum_free($self, 0);
+  }
+  Id const type;
+  %{
+  SWIGINTERN Id Chksum_type_get(Chksum *chk) {
+    return solv_chksum_get_type(chk);
+  }
+  %}
+  void add(const unsigned char *str, size_t len) {
+    solv_chksum_add($self, str, (int)len);
+  }
+  void add_fp(FILE *fp) {
+    char buf[4096];
+    int l;
+    while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
+      solv_chksum_add($self, buf, l);
+    rewind(fp);         /* convenience */
+  }
+  void add_fd(int fd) {
+    char buf[4096];
+    int l;
+    while ((l = read(fd, buf, sizeof(buf))) > 0)
+      solv_chksum_add($self, buf, l);
+    lseek(fd, 0, 0);    /* convenience */
+  }
+  void add_stat(const char *filename) {
+    struct stat stb;
+    if (stat(filename, &stb))
+      memset(&stb, 0, sizeof(stb));
+    solv_chksum_add($self, &stb.st_dev, sizeof(stb.st_dev));
+    solv_chksum_add($self, &stb.st_ino, sizeof(stb.st_ino));
+    solv_chksum_add($self, &stb.st_size, sizeof(stb.st_size));
+    solv_chksum_add($self, &stb.st_mtime, sizeof(stb.st_mtime));
+  }
+  void add_fstat(int fd) {
+    struct stat stb;
+    if (fstat(fd, &stb))
+      memset(&stb, 0, sizeof(stb));
+    solv_chksum_add($self, &stb.st_dev, sizeof(stb.st_dev));
+    solv_chksum_add($self, &stb.st_ino, sizeof(stb.st_ino));
+    solv_chksum_add($self, &stb.st_size, sizeof(stb.st_size));
+    solv_chksum_add($self, &stb.st_mtime, sizeof(stb.st_mtime));
+  }
+  BinaryBlob raw() {
+    BinaryBlob bl;
+    int l;
+    const unsigned char *b;
+    b = solv_chksum_get($self, &l);
+    bl.data = b;
+    bl.len = l;
+    return bl;
+  }
+  %newobject hex;
+  char *hex() {
+    int l;
+    const unsigned char *b;
+    char *ret;
+
+    b = solv_chksum_get($self, &l);
+    ret = solv_malloc(2 * l + 1);
+    solv_bin2hex(b, l, ret);
+    return ret;
+  }
+  const char *typestr() {
+    return solv_chksum_type2str(solv_chksum_get_type($self));
+  }
+
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(Chksum *chk) {
+    return solv_chksum_cmp($self, chk);
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(Chksum *chk) {
+    return !solv_chksum_cmp($self, chk);
+  }
+#if defined(SWIGRUBY)
+  %rename("to_s") __str__;
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  %newobject __str__;
+  const char *__str__() {
+    const char *str;
+    const char *h = 0;
+    if (solv_chksum_isfinished($self))
+      h = Chksum_hex($self);
+    str = solv_dupjoin(solv_chksum_type2str(solv_chksum_get_type($self)), ":", h ? h : "unfinished");
+    solv_free((void *)h);
+    return str;
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  %newobject __repr__;
+  const char *__repr__() {
+    const char *h = Chksum___str__($self);
+    const char *str = solv_dupjoin("<Chksum ", h, ">");
+    solv_free((void *)h);
+    return str;
+  }
+}
+
+%extend Pool {
+  static const int POOL_FLAG_PROMOTEEPOCH = POOL_FLAG_PROMOTEEPOCH;
+  static const int POOL_FLAG_FORBIDSELFCONFLICTS = POOL_FLAG_FORBIDSELFCONFLICTS;
+  static const int POOL_FLAG_OBSOLETEUSESPROVIDES = POOL_FLAG_OBSOLETEUSESPROVIDES;
+  static const int POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES = POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES;
+  static const int POOL_FLAG_OBSOLETEUSESCOLORS = POOL_FLAG_OBSOLETEUSESCOLORS;
+  static const int POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS = POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS;
+  static const int POOL_FLAG_NOINSTALLEDOBSOLETES = POOL_FLAG_NOINSTALLEDOBSOLETES;
+  static const int POOL_FLAG_HAVEDISTEPOCH = POOL_FLAG_HAVEDISTEPOCH;
+  static const int POOL_FLAG_NOOBSOLETESMULTIVERSION = POOL_FLAG_NOOBSOLETESMULTIVERSION;
+  static const int DISTTYPE_RPM = DISTTYPE_RPM;
+  static const int DISTTYPE_DEB = DISTTYPE_DEB;
+  static const int DISTTYPE_ARCH = DISTTYPE_ARCH;
+  static const int DISTTYPE_HAIKU = DISTTYPE_HAIKU;
+
+  Pool() {
+    Pool *pool = pool_create();
+    return pool;
+  }
+  int setdisttype(int disttype) {
+    return pool_setdisttype($self, disttype);
+  }
+  void set_debuglevel(int level) {
+    pool_setdebuglevel($self, level);
+  }
+  int set_flag(int flag, int value) {
+    return pool_set_flag($self, flag, value);
+  }
+  int get_flag(int flag) {
+    return pool_get_flag($self, flag);
+  }
+  void set_rootdir(const char *rootdir) {
+    pool_set_rootdir($self, rootdir);
+  }
+  const char *get_rootdir(int flag) {
+    return pool_get_rootdir($self);
+  }
+#if defined(SWIGPYTHON)
+  %{
+  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
+    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
+    PyObject *args = Py_BuildValue("(O)", SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0));
+    PyObject *result = PyEval_CallObject((PyObject *)d, args);
+    int ecode = 0;
+    int vresult = 0;
+    Py_DECREF(args);
+    if (!result)
+      return 0; /* exception */
+    ecode = SWIG_AsVal_int(result, &vresult);
+    Py_DECREF(result);
+    return SWIG_IsOK(ecode) ? vresult : 0;
+  }
+  %}
+  void clr_loadcallback() {
+    if ($self->loadcallback == loadcallback) {
+      PyObject *obj = $self->loadcallbackdata;
+      Py_DECREF(obj);
+      pool_setloadcallback($self, 0, 0);
+    }
+  }
+  void set_loadcallback(PyObject *callable) {
+    Pool_clr_loadcallback($self);
+    if (callable) {
+      Py_INCREF(callable);
+      pool_setloadcallback($self, loadcallback, callable);
+    }
+  }
+#elif defined(SWIGPERL)
+%{
+  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
+    int count;
+    int ret = 0;
+    dSP;
+    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
+
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    XPUSHs(SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_OWNER | SWIG_SHADOW));
+    PUTBACK;
+    count = perl_call_sv((SV *)d, G_EVAL|G_SCALAR);
+    SPAGAIN;
+    if (count)
+      ret = POPi;
+    PUTBACK;
+    FREETMPS;
+    LEAVE;
+    return ret;
+  }
+%}
+  void clr_loadcallback() {
+    if ($self->loadcallback == loadcallback) {
+      SvREFCNT_dec($self->loadcallbackdata);
+      pool_setloadcallback($self, 0, 0);
+    }
+  }
+  void set_loadcallback(SV *callable) {
+    Pool_clr_loadcallback($self);
+    if (callable) {
+      SvREFCNT_inc(callable);
+      pool_setloadcallback($self, loadcallback, callable);
+    }
+  }
+#elif defined(SWIGRUBY)
+%{
+  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
+    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
+    VALUE callable = (VALUE)d;
+    VALUE rd = SWIG_NewPointerObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, SWIG_POINTER_OWN | 0);
+    VALUE res = rb_funcall(callable, rb_intern("call"), 1, rd);
+    return res == Qtrue;
+  }
+  SWIGINTERN void mark_Pool(void *ptr) {
+    Pool *pool = ptr;
+    if (pool->loadcallback == loadcallback && pool->loadcallbackdata) {
+      VALUE callable = (VALUE)pool->loadcallbackdata;
+      rb_gc_mark(callable);
+    }
+  }
+%}
+  void clr_loadcallback() {
+    pool_setloadcallback($self, 0, 0);
+  }
+  %typemap(in, numinputs=0) VALUE callable {
+    $1 = rb_block_given_p() ? rb_block_proc() : 0;
+  }
+  void set_loadcallback(VALUE callable) {
+    pool_setloadcallback($self, callable ? loadcallback : 0, (void *)callable);
+  }
+#elif defined(SWIGTCL)
+  %{
+  typedef struct {
+    Tcl_Interp *interp;
+    Tcl_Obj *obj;
+  } tcl_callback_t;
+  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
+    tcl_callback_t *callback_var = (tcl_callback_t *)d;
+    Tcl_Interp *interp = callback_var->interp;
+    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
+    int result, ecode = 0, vresult = 0;
+    Tcl_Obj *objvx[2];
+    objvx[0] = callback_var->obj;
+    objvx[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, 0); 
+    Tcl_IncrRefCount(objvx[1]);
+    result = Tcl_EvalObjv(interp, sizeof(objvx)/sizeof(*objvx), objvx, TCL_EVAL_GLOBAL);
+    Tcl_DecrRefCount(objvx[1]);
+    if (result != TCL_OK)
+      return 0; /* exception */
+    ecode = SWIG_AsVal_int(interp, Tcl_GetObjResult(interp), &vresult);
+    return SWIG_IsOK(ecode) ? vresult : 0;
+  }
+  %}
+  void clr_loadcallback() {
+    if ($self->loadcallback == loadcallback) {
+      tcl_callback_t *callback_var = $self->loadcallbackdata;
+      Tcl_DecrRefCount(callback_var->obj);
+      solv_free(callback_var);
+      pool_setloadcallback($self, 0, 0);
+    }
+  }
+  void set_loadcallback(Tcl_Obj *callable, Tcl_Interp *interp) {
+    Pool_clr_loadcallback($self);
+    if (callable) {
+      tcl_callback_t *callback_var = solv_malloc(sizeof(tcl_callback_t));
+      Tcl_IncrRefCount(callable);
+      callback_var->interp = interp;
+      callback_var->obj = callable;
+      pool_setloadcallback($self, loadcallback, callback_var);
+    }
+  }
+#else
+#warning loadcallback not implemented for this language
+#endif
+
+  ~Pool() {
+    Pool *pool = $self;
+    Id repoid;
+    Repo *repo;
+    FOR_REPOS(repoid, repo)
+      appdata_clr_helper(&repo->appdata);
+    Pool_clr_loadcallback(pool);
+    appdata_clr_helper(&pool->appdata);
+    pool_free(pool);
+  }
+  disown_helper free() {
+    Pool *pool = $self;
+    Id repoid;
+    Repo *repo;
+    FOR_REPOS(repoid, repo)
+      appdata_clr_helper(&repo->appdata);
+    Pool_clr_loadcallback(pool);
+    appdata_clr_helper(&pool->appdata);
+    pool_free(pool);
+    return 0;
+  }
+  disown_helper disown() {
+    return 0;
+  }
+  AppObjectPtr appdata;
+  %{
+  SWIGINTERN void Pool_appdata_set(Pool *pool, AppObjectPtr appdata) {
+    appdata_set_helper(&pool->appdata, appdata);
+  }
+  SWIGINTERN AppObjectPtr Pool_appdata_get(Pool *pool) {
+    return appdata_get_helper(pool->appdata);
+  }
+  %}
+  void appdata_disown() {
+    appdata_disown_helper($self->appdata);
+  }
+
+  Id str2id(const char *str, bool create=1) {
+    return pool_str2id($self, str, create);
+  }
+  %newobject Dep;
+  Dep *Dep(const char *str, bool create=1) {
+    Id id = pool_str2id($self, str, create);
+    return new_Dep($self, id);
+  }
+#if defined(ENABLE_COMPLEX_DEPS) && (defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG))
+  %newobject Dep;
+  Dep *parserpmrichdep(const char *str) {
+    Id id = pool_parserpmrichdep($self, str);
+    return new_Dep($self, id);
+  }
+#endif
+  const char *id2str(Id id) {
+    return pool_id2str($self, id);
+  }
+  const char *dep2str(Id id) {
+    return pool_dep2str($self, id);
+  }
+  Id rel2id(Id name, Id evr, int flags, bool create=1) {
+    return pool_rel2id($self, name, evr, flags, create);
+  }
+  Id id2langid(Id id, const char *lang, bool create=1) {
+    return pool_id2langid($self, id, lang, create);
+  }
+  void setarch(const char *arch = 0) {
+    struct utsname un;
+    if (!arch) {
+      if (uname(&un)) {
+        perror("uname");
+        return;
+      }
+      arch = un.machine;
+    }
+    pool_setarch($self, arch);
+  }
+  Repo *add_repo(const char *name) {
+    return repo_create($self, name);
+  }
+  const char *lookup_str(Id entry, Id keyname) {
+    return pool_lookup_str($self, entry, keyname);
+  }
+  Id lookup_id(Id entry, Id keyname) {
+    return pool_lookup_id($self, entry, keyname);
+  }
+  unsigned long long lookup_num(Id entry, Id keyname, unsigned long long notfound = 0) {
+    return pool_lookup_num($self, entry, keyname, notfound);
+  }
+  bool lookup_void(Id entry, Id keyname) {
+    return pool_lookup_void($self, entry, keyname);
+  }
+  %newobject lookup_checksum;
+  Chksum *lookup_checksum(Id entry, Id keyname) {
+    Id type = 0;
+    const unsigned char *b = pool_lookup_bin_checksum($self, entry, keyname, &type);
+    return solv_chksum_create_from_bin(type, b);
+  }
+
+  %newobject Dataiterator;
+  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
+    return new_Dataiterator($self, 0, 0, key, match, flags);
+  }
+  %newobject Dataiterator_solvid;
+  Dataiterator *Dataiterator_solvid(Id p, Id key, const char *match = 0, int flags = 0) {
+    return new_Dataiterator($self, 0, p, key, match, flags);
+  }
+  const char *solvid2str(Id solvid) {
+    return pool_solvid2str($self, solvid);
+  }
+  void addfileprovides() {
+    pool_addfileprovides($self);
+  }
+  Queue addfileprovides_queue() {
+    Queue r;
+    queue_init(&r);
+    pool_addfileprovides_queue($self, &r, 0);
+    return r;
+  }
+  void createwhatprovides() {
+    pool_createwhatprovides($self);
+  }
+
+  %newobject id2solvable;
+  XSolvable *id2solvable(Id id) {
+    return new_XSolvable($self, id);
+  }
+  %newobject solvables;
+  Pool_solvable_iterator * const solvables;
+  %{
+  SWIGINTERN Pool_solvable_iterator * Pool_solvables_get(Pool *pool) {
+    return new_Pool_solvable_iterator(pool);
+  }
+  %}
+  %newobject solvables_iter;
+  Pool_solvable_iterator * solvables_iter() {
+    return new_Pool_solvable_iterator($self);
+  }
+
+  Repo *id2repo(Id id) {
+    if (id < 1 || id >= $self->nrepos)
+      return 0;
+    return pool_id2repo($self, id);
+  }
+
+  %newobject repos;
+  Pool_repo_iterator * const repos;
+  %{
+  SWIGINTERN Pool_repo_iterator * Pool_repos_get(Pool *pool) {
+    return new_Pool_repo_iterator(pool);
+  }
+  %}
+  %newobject repos_iter;
+  Pool_repo_iterator * repos_iter() {
+    return new_Pool_repo_iterator($self);
+  }
+
+  Repo *installed;
+  const char * const errstr;
+  %{
+  SWIGINTERN void Pool_installed_set(Pool *pool, Repo *installed) {
+    pool_set_installed(pool, installed);
+  }
+  SWIGINTERN Repo *Pool_installed_get(Pool *pool) {
+    return pool->installed;
+  }
+  SWIGINTERN const char *Pool_errstr_get(Pool *pool) {
+    return pool_errstr(pool);
+  }
+  %}
+
+  Queue matchprovidingids(const char *match, int flags) {
+    Pool *pool = $self;
+    Queue q;
+    Id id;
+    queue_init(&q);
+    if (!flags) {
+      for (id = 1; id < pool->ss.nstrings; id++)
+        if (pool->whatprovides[id])
+          queue_push(&q, id);
+    } else {
+      Datamatcher ma;
+      if (!datamatcher_init(&ma, match, flags)) {
+        for (id = 1; id < pool->ss.nstrings; id++)
+          if (pool->whatprovides[id] && datamatcher_match(&ma, pool_id2str(pool, id)))
+            queue_push(&q, id);
+        datamatcher_free(&ma);
+      }
+    }
+    return q;
+  }
+
+  %newobject Job;
+  Job *Job(int how, Id what) {
+    return new_Job($self, how, what);
+  }
+
+  %typemap(out) Queue whatprovides Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+  %newobject whatprovides;
+  Queue whatprovides(DepId dep) {
+    Pool *pool = $self;
+    Queue q;
+    Id p, pp;
+    queue_init(&q);
+    FOR_PROVIDES(p, pp, dep)
+      queue_push(&q, p);
+    return q;
+  }
+
+  Id towhatprovides(Queue q) {
+    return pool_queuetowhatprovides($self, &q);
+  }
+
+  void set_namespaceproviders(DepId ns, DepId evr, bool value=1) {
+    Id dep = pool_rel2id($self, ns, evr, REL_NAMESPACE, 1);
+    pool_set_whatprovides($self, dep, value ? 2 : 1);
+  }
+
+  void flush_namespaceproviders(DepId ns, DepId evr) {
+    pool_flush_namespaceproviders($self, ns, evr);
+  }
+
+
+  %typemap(out) Queue whatmatchesdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+  %newobject whatmatchesdep;
+  Queue whatmatchesdep(Id keyname, DepId dep, Id marker = -1) {
+    Queue q;
+    queue_init(&q);
+    pool_whatmatchesdep($self, keyname, dep, &q, marker);
+    return q;
+  }
+
+#ifdef SWIGRUBY
+  %rename("isknownarch?") isknownarch;
+#endif
+  bool isknownarch(DepId id) {
+    Pool *pool = $self;
+    if (!id || id == ID_EMPTY)
+      return 0;
+    if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
+      return 1;
+    if (pool->id2arch && pool_arch2score(pool, id) == 0)
+      return 0;
+    return 1;
+  }
+
+  %newobject Solver;
+  Solver *Solver() {
+    return solver_create($self);
+  }
+
+  %newobject Selection;
+  Selection *Selection() {
+    return new_Selection($self);
+  }
+  %newobject Selection_all;
+  Selection *Selection_all(int setflags=0) {
+    Selection *sel = new_Selection($self);
+    queue_push2(&sel->q, SOLVER_SOLVABLE_ALL | setflags, 0);
+    return sel;
+  }
+  %newobject select;
+  Selection *select(const char *name, int flags) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make($self, &sel->q, name, flags);
+    return sel;
+  }
+
+  %newobject matchdeps;
+  Selection *matchdeps(const char *name, int flags, Id keyname, Id marker = -1) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make_matchdeps($self, &sel->q, name, flags, keyname, marker);
+    return sel;
+  }
+
+  %newobject matchdepid;
+  Selection *matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make_matchdepid($self, &sel->q, dep, flags, keyname, marker);
+    return sel;
+  }
+
+  Queue get_considered_list() {
+    Queue q;
+    queue_init(&q);
+    int i;
+    for (i = 2; i < $self->nsolvables; i++) {
+      if (!$self->solvables[i].repo)
+        continue;
+      if (!$self->considered || MAPTST($self->considered, i))
+        queue_push(&q, i);
+    }
+    return q;
+  }
+
+  void set_considered_list(Queue q) {
+    int i;
+    Id p;
+    if (!$self->considered) {
+      $self->considered = solv_calloc(1, sizeof(Map));
+      map_init($self->considered, $self->nsolvables);
+    }
+    map_empty($self->considered);
+    MAPSET($self->considered, 1);
+    for (i = 0; i < q.count; i++) {
+      p = q.elements[i];
+      if (p > 0 && p < $self->nsolvables)
+        MAPSET($self->considered, p);
+    }
+  }
+
+  void setpooljobs(Queue solvejobs) {
+    queue_free(&$self->pooljobs);
+    queue_init_clone(&$self->pooljobs, &solvejobs);
+  }
+  %typemap(out) Queue getpooljobs Queue2Array(Job *, 2, new_Job(arg1, id, idp[1]));
+  %newobject getpooljobs;
+  Queue getpooljobs() {
+    Queue q;
+    queue_init_clone(&q, &$self->pooljobs);
+    return q;
+  }
+
+}
+
+%extend Repo {
+  static const int REPO_REUSE_REPODATA = REPO_REUSE_REPODATA;
+  static const int REPO_NO_INTERNALIZE = REPO_NO_INTERNALIZE;
+  static const int REPO_LOCALPOOL = REPO_LOCALPOOL;
+  static const int REPO_USE_LOADING = REPO_USE_LOADING;
+  static const int REPO_EXTEND_SOLVABLES = REPO_EXTEND_SOLVABLES;
+  static const int REPO_USE_ROOTDIR = REPO_USE_ROOTDIR;
+  static const int REPO_NO_LOCATION = REPO_NO_LOCATION;
+  static const int SOLV_ADD_NO_STUBS = SOLV_ADD_NO_STUBS;       /* repo_solv */
+#ifdef ENABLE_SUSEREPO
+  static const int SUSETAGS_RECORD_SHARES = SUSETAGS_RECORD_SHARES;     /* repo_susetags */
+#endif
+
+  void free(bool reuseids = 0) {
+    appdata_clr_helper(&$self->appdata);
+    repo_free($self, reuseids);
+  }
+  void empty(bool reuseids = 0) {
+    repo_empty($self, reuseids);
+  }
+#ifdef SWIGRUBY
+  %rename("isempty?") isempty;
+#endif
+  bool isempty() {
+    return !$self->nsolvables;
+  }
+
+  AppObjectPtr appdata;
+  %{
+  SWIGINTERN void Repo_appdata_set(Repo *repo, AppObjectPtr appdata) {
+    appdata_set_helper(&repo->appdata, appdata);
+  }
+  SWIGINTERN AppObjectPtr Repo_appdata_get(Repo *repo) {
+    return appdata_get_helper(repo->appdata);
+  }
+  %}
+
+  bool add_solv(const char *name, int flags = 0) {
+    FILE *fp = fopen(name, "r");
+    int r;
+    if (!fp)
+      return 0;
+    r = repo_add_solv($self, fp, flags);
+    fclose(fp);
+    return r == 0;
+  }
+  bool add_solv(FILE *fp, int flags = 0) {
+    return repo_add_solv($self, fp, flags) == 0;
+  }
+
+  %newobject add_solvable;
+  XSolvable *add_solvable() {
+    Id solvid = repo_add_solvable($self);
+    return new_XSolvable($self->pool, solvid);
+  }
+
+#ifdef ENABLE_RPMDB
+  bool add_rpmdb(int flags = 0) {
+    return repo_add_rpmdb($self, 0, flags) == 0;
+  }
+  bool add_rpmdb_reffp(FILE *reffp, int flags = 0) {
+    return repo_add_rpmdb_reffp($self, reffp, flags) == 0;
+  }
+#endif
+#ifdef ENABLE_RPMPKG
+  %newobject add_rpm;
+  XSolvable *add_rpm(const char *name, int flags = 0) {
+    return new_XSolvable($self->pool, repo_add_rpm($self, name, flags));
+  }
+#endif
+#ifdef ENABLE_PUBKEY
+#ifdef ENABLE_RPMDB
+  bool add_rpmdb_pubkeys(int flags = 0) {
+    return repo_add_rpmdb_pubkeys($self, flags) == 0;
+  }
+#endif
+  %newobject add_pubkey;
+  XSolvable *add_pubkey(const char *keyfile, int flags = 0) {
+    return new_XSolvable($self->pool, repo_add_pubkey($self, keyfile, flags));
+  }
+  bool add_keyring(FILE *fp, int flags = 0) {
+    return repo_add_keyring($self, fp, flags);
+  }
+  bool add_keydir(const char *keydir, const char *suffix, int flags = 0) {
+    return repo_add_keydir($self, keydir, suffix, flags);
+  }
+#endif
+#ifdef ENABLE_RPMMD
+  bool add_rpmmd(FILE *fp, const char *language, int flags = 0) {
+    return repo_add_rpmmd($self, fp, language, flags) == 0;
+  }
+  bool add_repomdxml(FILE *fp, int flags = 0) {
+    return repo_add_repomdxml($self, fp, flags) == 0;
+  }
+  bool add_updateinfoxml(FILE *fp, int flags = 0) {
+    return repo_add_updateinfoxml($self, fp, flags) == 0;
+  }
+  bool add_deltainfoxml(FILE *fp, int flags = 0) {
+    return repo_add_deltainfoxml($self, fp, flags) == 0;
+  }
+#endif
+#ifdef ENABLE_DEBIAN
+  bool add_debdb(int flags = 0) {
+    return repo_add_debdb($self, flags) == 0;
+  }
+  bool add_debpackages(FILE *fp, int flags = 0) {
+    return repo_add_debpackages($self, fp, flags) == 0;
+  }
+  %newobject add_deb;
+  XSolvable *add_deb(const char *name, int flags = 0) {
+    return new_XSolvable($self->pool, repo_add_deb($self, name, flags));
+  }
+#endif
+#ifdef ENABLE_SUSEREPO
+  bool add_susetags(FILE *fp, Id defvendor, const char *language, int flags = 0) {
+    return repo_add_susetags($self, fp, defvendor, language, flags) == 0;
+  }
+  bool add_content(FILE *fp, int flags = 0) {
+    return repo_add_content($self, fp, flags) == 0;
+  }
+  bool add_products(const char *proddir, int flags = 0) {
+    return repo_add_products($self, proddir, flags) == 0;
+  }
+#endif
+#ifdef ENABLE_MDKREPO
+  bool add_mdk(FILE *fp, int flags = 0) {
+    return repo_add_mdk($self, fp, flags) == 0;
+  }
+  bool add_mdk_info(FILE *fp, int flags = 0) {
+    return repo_add_mdk_info($self, fp, flags) == 0;
+  }
+#endif
+#ifdef ENABLE_ARCHREPO
+  bool add_arch_repo(FILE *fp, int flags = 0) {
+    return repo_add_arch_repo($self, fp, flags) == 0;
+  }
+  bool add_arch_local(const char *dir, int flags = 0) {
+    return repo_add_arch_local($self, dir, flags) == 0;
+  }
+  %newobject add_arch_pkg;
+  XSolvable *add_arch_pkg(const char *name, int flags = 0) {
+    return new_XSolvable($self->pool, repo_add_arch_pkg($self, name, flags));
+  }
+#endif
+#ifdef SUSE
+  bool add_autopattern(int flags = 0) {
+    return repo_add_autopattern($self, flags) == 0;
+  }
+#endif
+  void internalize() {
+    repo_internalize($self);
+  }
+  bool write(FILE *fp) {
+    return repo_write($self, fp) == 0;
+  }
+  /* HACK, remove if no longer needed! */
+  bool write_first_repodata(FILE *fp) {
+    int oldnrepodata = $self->nrepodata;
+    int res;
+    $self->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata;
+    res = repo_write($self, fp);
+    $self->nrepodata = oldnrepodata;
+    return res == 0;
+  }
+
+  %newobject Dataiterator;
+  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
+    return new_Dataiterator($self->pool, $self, 0, key, match, flags);
+  }
+  %newobject Dataiterator_meta;
+  Dataiterator *Dataiterator_meta(Id key, const char *match = 0, int flags = 0) {
+    return new_Dataiterator($self->pool, $self, SOLVID_META, key, match, flags);
+  }
+
+  Id const id;
+  %{
+  SWIGINTERN Id Repo_id_get(Repo *repo) {
+    return repo->repoid;
+  }
+  %}
+  %newobject solvables;
+  Repo_solvable_iterator * const solvables;
+  %{
+  SWIGINTERN Repo_solvable_iterator * Repo_solvables_get(Repo *repo) {
+    return new_Repo_solvable_iterator(repo);
+  }
+  %}
+  %newobject meta;
+  Datapos * const meta;
+  %{
+  SWIGINTERN Datapos * Repo_meta_get(Repo *repo) {
+    Datapos *pos = solv_calloc(1, sizeof(*pos));
+    pos->solvid = SOLVID_META;
+    pos->repo = repo;
+    return pos;
+  }
+  %}
+
+  %newobject solvables_iter;
+  Repo_solvable_iterator *solvables_iter() {
+    return new_Repo_solvable_iterator($self);
+  }
+
+  %newobject add_repodata;
+  XRepodata *add_repodata(int flags = 0) {
+    Repodata *rd = repo_add_repodata($self, flags);
+    return new_XRepodata($self, rd->repodataid);
+  }
+
+  void create_stubs() {
+    Repodata *data;
+    if (!$self->nrepodata)
+      return;
+    data = repo_id2repodata($self, $self->nrepodata - 1);
+    if (data->state != REPODATA_STUB)
+      (void)repodata_create_stubs(data);
+  }
+#ifdef SWIGRUBY
+  %rename("iscontiguous?") iscontiguous;
+#endif
+  bool iscontiguous() {
+    int i;
+    for (i = $self->start; i < $self->end; i++)
+      if ($self->pool->solvables[i].repo != $self)
+        return 0;
+    return 1;
+  }
+  %newobject first_repodata;
+  XRepodata *first_repodata() {
+    Repodata *data;
+    int i;
+    if ($self->nrepodata < 2)
+      return 0;
+    /* make sure all repodatas but the first are extensions */
+    data = repo_id2repodata($self, 1);
+    if (data->loadcallback)
+       return 0;
+    for (i = 2; i < $self->nrepodata; i++)
+      {
+        data = repo_id2repodata($self, i);
+        if (!data->loadcallback)
+          return 0;       /* oops, not an extension */
+      }
+    return new_XRepodata($self, 1);
+  }
+
+  %newobject Selection;
+  Selection *Selection(int setflags=0) {
+    Selection *sel = new_Selection($self->pool);
+    setflags |= SOLVER_SETREPO;
+    queue_push2(&sel->q, SOLVER_SOLVABLE_REPO | setflags, $self->repoid);
+    return sel;
+  }
+
+#ifdef ENABLE_PUBKEY
+  %newobject find_pubkey;
+  XSolvable *find_pubkey(const char *keyid) {
+    return new_XSolvable($self->pool, repo_find_pubkey($self, keyid));
+  }
+#endif
+
+  Repo *createshadow(const char *name) {
+    Repo *repo = repo_create($self->pool, name);
+    if ($self->idarraysize) {
+      repo_reserve_ids(repo, 0, $self->idarraysize);
+      memcpy(repo->idarraydata, $self->idarraydata, sizeof(Id) * $self->idarraysize);
+      repo->idarraysize = $self->idarraysize;
+    }
+    repo->start = $self->start;
+    repo->end = $self->end;
+    repo->nsolvables = $self->nsolvables;
+    return repo;
+  }
+
+  void moveshadow(Queue q) {
+    Pool *pool = $self->pool;
+    int i;
+    for (i = 0; i < q.count; i++) {
+      Solvable *s;
+      Id p = q.elements[i];
+      if (p < $self->start || p >= $self->end)
+        continue;
+      s = pool->solvables + p;
+      if ($self->idarraysize != s->repo->idarraysize)
+        continue;
+      s->repo = $self;
+    }
+  }
+
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(Repo *repo) {
+    return $self == repo;
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(Repo *repo) {
+    return $self != repo;
+  }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->repoid;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  %newobject __str__;
+  const char *__str__() {
+    char buf[20];
+    if ($self->name)
+      return solv_strdup($self->name);
+    sprintf(buf, "Repo#%d", $self->repoid);
+    return solv_strdup(buf);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  %newobject __repr__;
+  const char *__repr__() {
+    char buf[20];
+    if ($self->name)
+      {
+        sprintf(buf, "<Repo #%d ", $self->repoid);
+        return solv_dupjoin(buf, $self->name, ">");
+      }
+    sprintf(buf, "<Repo #%d>", $self->repoid);
+    return solv_strdup(buf);
+  }
+}
+
+%extend Dataiterator {
+  static const int SEARCH_STRING = SEARCH_STRING;
+  static const int SEARCH_STRINGSTART = SEARCH_STRINGSTART;
+  static const int SEARCH_STRINGEND = SEARCH_STRINGEND;
+  static const int SEARCH_SUBSTRING = SEARCH_SUBSTRING;
+  static const int SEARCH_GLOB = SEARCH_GLOB;
+  static const int SEARCH_REGEX = SEARCH_REGEX;
+  static const int SEARCH_NOCASE = SEARCH_NOCASE;
+  static const int SEARCH_FILES = SEARCH_FILES;
+  static const int SEARCH_COMPLETE_FILELIST = SEARCH_COMPLETE_FILELIST;
+  static const int SEARCH_CHECKSUMS = SEARCH_CHECKSUMS;
+
+  Dataiterator(Pool *pool, Repo *repo, Id p, Id key, const char *match, int flags) {
+    Dataiterator *di = solv_calloc(1, sizeof(*di));
+    dataiterator_init(di, pool, repo, p, key, match, flags);
+    return di;
+  }
+  ~Dataiterator() {
+    dataiterator_free($self);
+    solv_free($self);
+  }
+#if defined(SWIGPYTHON)
+  %pythoncode {
+    def __iter__(self): return self
+  }
+#ifndef PYTHON3
+  %rename("next") __next__();
+#endif
+  %exception __next__ {
+    $action
+    if (!result) {
+      PyErr_SetString(PyExc_StopIteration,"no more matches");
+      return NULL;
+    }
+  }
+#endif
+#ifdef SWIGPERL
+  perliter(solv::Dataiterator)
+#endif
+  %newobject __next__;
+  Datamatch *__next__() {
+    Dataiterator *ndi;
+    if (!dataiterator_step($self)) {
+      return 0;
+    }
+    ndi = solv_calloc(1, sizeof(*ndi));
+    dataiterator_init_clone(ndi, $self);
+    dataiterator_strdup(ndi);
+    return ndi;
+  }
+#ifdef SWIGRUBY
+  void each() {
+    Datamatch *d;
+    while ((d = Dataiterator___next__($self)) != 0) {
+      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(d), SWIGTYPE_p_Datamatch, SWIG_POINTER_OWN | 0));
+    }
+  }
+#endif
+  void prepend_keyname(Id key) {
+    dataiterator_prepend_keyname($self, key);
+  }
+  void skip_solvable() {
+    dataiterator_skip_solvable($self);
+  }
+}
+
+%extend Datapos {
+  Id lookup_id(Id keyname) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    Id r;
+    pool->pos = *$self;
+    r = pool_lookup_id(pool, SOLVID_POS, keyname);
+    pool->pos = oldpos;
+    return r;
+  }
+  const char *lookup_str(Id keyname) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    const char *r;
+    pool->pos = *$self;
+    r = pool_lookup_str(pool, SOLVID_POS, keyname);
+    pool->pos = oldpos;
+    return r;
+  }
+  unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    unsigned long long r;
+    pool->pos = *$self;
+    r = pool_lookup_num(pool, SOLVID_POS, keyname, notfound);
+    pool->pos = oldpos;
+    return r;
+  }
+  bool lookup_void(Id keyname) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    int r;
+    pool->pos = *$self;
+    r = pool_lookup_void(pool, SOLVID_POS, keyname);
+    pool->pos = oldpos;
+    return r;
+  }
+  %newobject lookup_checksum;
+  Chksum *lookup_checksum(Id keyname) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    Id type = 0;
+    const unsigned char *b;
+    pool->pos = *$self;
+    b = pool_lookup_bin_checksum(pool, SOLVID_POS, keyname, &type);
+    pool->pos = oldpos;
+    return solv_chksum_create_from_bin(type, b);
+  }
+  const char *lookup_deltaseq() {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    const char *seq;
+    pool->pos = *$self;
+    seq = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME);
+    if (seq) {
+      seq = pool_tmpjoin(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR));
+      seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM));
+    }
+    pool->pos = oldpos;
+    return seq;
+  }
+  const char *lookup_deltalocation(unsigned int *OUTPUT) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    const char *loc;
+    pool->pos = *$self;
+    loc = pool_lookup_deltalocation(pool, SOLVID_POS, OUTPUT);
+    pool->pos = oldpos;
+    return loc;
+  }
+  Queue lookup_idarray(Id keyname) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    Queue r;
+    queue_init(&r);
+    pool->pos = *$self;
+    pool_lookup_idarray(pool, SOLVID_POS, keyname, &r);
+    pool->pos = oldpos;
+    return r;
+  }
+  %newobject Dataiterator;
+  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
+    Pool *pool = $self->repo->pool;
+    Datapos oldpos = pool->pos;
+    Dataiterator *di;
+    pool->pos = *$self;
+    di = new_Dataiterator(pool, 0, SOLVID_POS, key, match, flags);
+    pool->pos = oldpos;
+    return di;
+  }
+}
+
+%extend Datamatch {
+  ~Datamatch() {
+    dataiterator_free($self);
+    solv_free($self);
+  }
+  %newobject solvable;
+  XSolvable * const solvable;
+  Id const key_id;
+  const char * const key_idstr;
+  Id const type_id;
+  const char * const type_idstr;
+  Id const id;
+  const char * const idstr;
+  const char * const str;
+  BinaryBlob const binary;
+  unsigned long long const num;
+  unsigned int const num2;
+  %{
+  SWIGINTERN XSolvable *Datamatch_solvable_get(Dataiterator *di) {
+    return new_XSolvable(di->pool, di->solvid);
+  }
+  SWIGINTERN Id Datamatch_key_id_get(Dataiterator *di) {
+    return di->key->name;
+  }
+  SWIGINTERN const char *Datamatch_key_idstr_get(Dataiterator *di) {
+    return pool_id2str(di->pool, di->key->name);
+  }
+  SWIGINTERN Id Datamatch_type_id_get(Dataiterator *di) {
+    return di->key->type;
+  }
+  SWIGINTERN const char *Datamatch_type_idstr_get(Dataiterator *di) {
+    return pool_id2str(di->pool, di->key->type);
+  }
+  SWIGINTERN Id Datamatch_id_get(Dataiterator *di) {
+    return di->kv.id;
+  }
+  SWIGINTERN const char *Datamatch_idstr_get(Dataiterator *di) {
+   if (di->data && (di->key->type == REPOKEY_TYPE_DIR || di->key->type == REPOKEY_TYPE_DIRSTRARRAY || di->key->type == REPOKEY_TYPE_DIRNUMNUMARRAY))
+      return repodata_dir2str(di->data,  di->kv.id, 0);
+    if (di->data && di->data->localpool)
+      return stringpool_id2str(&di->data->spool, di->kv.id);
+    return pool_id2str(di->pool, di->kv.id);
+  }
+  SWIGINTERN const char * const Datamatch_str_get(Dataiterator *di) {
+    return di->kv.str;
+  }
+  SWIGINTERN BinaryBlob Datamatch_binary_get(Dataiterator *di) {
+    BinaryBlob bl;
+    bl.data = 0;
+    bl.len = 0;
+    if (di->key->type == REPOKEY_TYPE_BINARY)
+      {
+        bl.data = di->kv.str;
+        bl.len = di->kv.num;
+      }
+    else if ((bl.len = solv_chksum_len(di->key->type)) != 0)
+      bl.data = di->kv.str;
+    return bl;
+  }
+  SWIGINTERN unsigned long long Datamatch_num_get(Dataiterator *di) {
+   if (di->key->type == REPOKEY_TYPE_NUM)
+     return SOLV_KV_NUM64(&di->kv);
+   return di->kv.num;
+  }
+  SWIGINTERN unsigned int Datamatch_num2_get(Dataiterator *di) {
+    return di->kv.num2;
+  }
+  %}
+  %newobject pos;
+  Datapos *pos() {
+    Pool *pool = $self->pool;
+    Datapos *pos, oldpos = pool->pos;
+    dataiterator_setpos($self);
+    pos = solv_calloc(1, sizeof(*pos));
+    *pos = pool->pos;
+    pool->pos = oldpos;
+    return pos;
+  }
+  %newobject parentpos;
+  Datapos *parentpos() {
+    Pool *pool = $self->pool;
+    Datapos *pos, oldpos = pool->pos;
+    dataiterator_setpos_parent($self);
+    pos = solv_calloc(1, sizeof(*pos));
+    *pos = pool->pos;
+    pool->pos = oldpos;
+    return pos;
+  }
+#if defined(SWIGPERL)
+  /* cannot use str here because swig reports a bogus conflict... */
+  %rename("stringify") __str__;
+  %perlcode {
+    *solv::Datamatch::str = *solvc::Datamatch_stringify;
+  }
+#endif
+#if defined(SWIGTCL)
+  %rename("stringify") __str__;
+#endif
+  const char *__str__() {
+    KeyValue kv = $self->kv;
+    const char *str = repodata_stringify($self->pool, $self->data, $self->key, &kv, SEARCH_FILES | SEARCH_CHECKSUMS);
+    return str ? str : "";
+  }
+}
+
+%extend Pool_solvable_iterator {
+  Pool_solvable_iterator(Pool *pool) {
+    Pool_solvable_iterator *s;
+    s = solv_calloc(1, sizeof(*s));
+    s->pool = pool;
+    return s;
+  }
+#if defined(SWIGPYTHON)
+  %pythoncode {
+    def __iter__(self): return self
+  }
+#ifndef PYTHON3
+  %rename("next") __next__();
+#endif
+  %exception __next__ {
+    $action
+    if (!result) {
+      PyErr_SetString(PyExc_StopIteration,"no more matches");
+      return NULL;
+    }
+  }
+#endif
+#ifdef SWIGPERL
+  perliter(solv::Pool_solvable_iterator)
+#endif
+  %newobject __next__;
+  XSolvable *__next__() {
+    Pool *pool = $self->pool;
+    if ($self->id >= pool->nsolvables)
+      return 0;
+    while (++$self->id < pool->nsolvables)
+      if (pool->solvables[$self->id].repo)
+        return new_XSolvable(pool, $self->id);
+    return 0;
+  }
+#ifdef SWIGRUBY
+  void each() {
+    XSolvable *n;
+    while ((n = Pool_solvable_iterator___next__($self)) != 0) {
+      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_XSolvable, SWIG_POINTER_OWN | 0));
+    }
+  }
+#endif
+  %newobject __getitem__;
+  XSolvable *__getitem__(Id key) {
+    Pool *pool = $self->pool;
+    if (key > 0 && key < pool->nsolvables && pool->solvables[key].repo)
+      return new_XSolvable(pool, key);
+    return 0;
+  }
+  int __len__() {
+    return $self->pool->nsolvables;
+  }
+}
+
+%extend Pool_repo_iterator {
+  Pool_repo_iterator(Pool *pool) {
+    Pool_repo_iterator *s;
+    s = solv_calloc(1, sizeof(*s));
+    s->pool = pool;
+    return s;
+  }
+#if defined(SWIGPYTHON)
+  %pythoncode {
+    def __iter__(self): return self
+  }
+#ifndef PYTHON3
+  %rename("next") __next__();
+#endif
+  %exception __next__ {
+    $action
+    if (!result) {
+      PyErr_SetString(PyExc_StopIteration,"no more matches");
+      return NULL;
+    }
+  }
+#endif
+#ifdef SWIGPERL
+  perliter(solv::Pool_repo_iterator)
+#endif
+  Repo *__next__() {
+    Pool *pool = $self->pool;
+    if ($self->id >= pool->nrepos)
+      return 0;
+    while (++$self->id < pool->nrepos) {
+      Repo *r = pool_id2repo(pool, $self->id);
+      if (r)
+        return r;
+    }
+    return 0;
+  }
+#ifdef SWIGRUBY
+  void each() {
+    Repo *n;
+    while ((n = Pool_repo_iterator___next__($self)) != 0) {
+      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, 0 | 0));
+    }
+  }
+#endif
+  Repo *__getitem__(Id key) {
+    Pool *pool = $self->pool;
+    if (key > 0 && key < pool->nrepos)
+      return pool_id2repo(pool, key);
+    return 0;
+  }
+  int __len__() {
+    return $self->pool->nrepos;
+  }
+}
+
+%extend Repo_solvable_iterator {
+  Repo_solvable_iterator(Repo *repo) {
+    Repo_solvable_iterator *s;
+    s = solv_calloc(1, sizeof(*s));
+    s->repo = repo;
+    return s;
+  }
+#if defined(SWIGPYTHON)
+  %pythoncode {
+    def __iter__(self): return self
+  }
+#ifndef PYTHON3
+  %rename("next") __next__();
+#endif
+  %exception __next__ {
+    $action
+    if (!result) {
+      PyErr_SetString(PyExc_StopIteration,"no more matches");
+      return NULL;
+    }
+  }
+#endif
+#ifdef SWIGPERL
+  perliter(solv::Repo_solvable_iterator)
+#endif
+  %newobject __next__;
+  XSolvable *__next__() {
+    Repo *repo = $self->repo;
+    Pool *pool = repo->pool;
+    if (repo->start > 0 && $self->id < repo->start)
+      $self->id = repo->start - 1;
+    if ($self->id >= repo->end)
+      return 0;
+    while (++$self->id < repo->end)
+      if (pool->solvables[$self->id].repo == repo)
+        return new_XSolvable(pool, $self->id);
+    return 0;
+  }
+#ifdef SWIGRUBY
+  void each() {
+    XSolvable *n;
+    while ((n = Repo_solvable_iterator___next__($self)) != 0) {
+      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_XSolvable, SWIG_POINTER_OWN | 0));
+    }
+  }
+#endif
+  %newobject __getitem__;
+  XSolvable *__getitem__(Id key) {
+    Repo *repo = $self->repo;
+    Pool *pool = repo->pool;
+    if (key > 0 && key < pool->nsolvables && pool->solvables[key].repo == repo)
+      return new_XSolvable(pool, key);
+    return 0;
+  }
+  int __len__() {
+    return $self->repo->pool->nsolvables;
+  }
+}
+
+%extend Dep {
+  Dep(Pool *pool, Id id) {
+    Dep *s;
+    if (!id)
+      return 0;
+    s = solv_calloc(1, sizeof(*s));
+    s->pool = pool;
+    s->id = id;
+    return s;
+  }
+  %newobject Rel;
+  Dep *Rel(int flags, DepId evrid, bool create=1) {
+    Id id = pool_rel2id($self->pool, $self->id, evrid, flags, create);
+    if (!id)
+      return 0;
+    return new_Dep($self->pool, id);
+  }
+  %newobject Selection_name;
+  Selection *Selection_name(int setflags=0) {
+    Selection *sel = new_Selection($self->pool);
+    if (ISRELDEP($self->id)) {
+      Reldep *rd = GETRELDEP($self->pool, $self->id);
+      if (rd->flags == REL_EQ) {
+        setflags |= $self->pool->disttype == DISTTYPE_DEB || strchr(pool_id2str($self->pool, rd->evr), '-') != 0 ? SOLVER_SETEVR : SOLVER_SETEV;
+        if (ISRELDEP(rd->name))
+          rd = GETRELDEP($self->pool, rd->name);
+      }
+      if (rd->flags == REL_ARCH)
+        setflags |= SOLVER_SETARCH;
+    }
+    queue_push2(&sel->q, SOLVER_SOLVABLE_NAME | setflags, $self->id);
+    return sel;
+  }
+  %newobject Selection_provides;
+  Selection *Selection_provides(int setflags=0) {
+    Selection *sel = new_Selection($self->pool);
+    if (ISRELDEP($self->id)) {
+      Reldep *rd = GETRELDEP($self->pool, $self->id);
+      if (rd->flags == REL_ARCH)
+        setflags |= SOLVER_SETARCH;
+    }
+    queue_push2(&sel->q, SOLVER_SOLVABLE_PROVIDES | setflags, $self->id);
+    return sel;
+  }
+  const char *str() {
+    return pool_dep2str($self->pool, $self->id);
+  }
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(Dep *s) {
+    return $self->pool == s->pool && $self->id == s->id;
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(Dep *s) {
+    return !Dep___eq__($self, s);
+  }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return pool_dep2str($self->pool, $self->id);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  %newobject __repr__;
+  const char *__repr__() {
+    char buf[20];
+    sprintf(buf, "<Id #%d ", $self->id);
+    return solv_dupjoin(buf, pool_dep2str($self->pool, $self->id), ">");
+  }
+}
+
+%extend XSolvable {
+  XSolvable(Pool *pool, Id id) {
+    XSolvable *s;
+    if (!id || id >= pool->nsolvables)
+      return 0;
+    s = solv_calloc(1, sizeof(*s));
+    s->pool = pool;
+    s->id = id;
+    return s;
+  }
+  const char *str() {
+    return pool_solvid2str($self->pool, $self->id);
+  }
+  const char *lookup_str(Id keyname) {
+    return pool_lookup_str($self->pool, $self->id, keyname);
+  }
+  Id lookup_id(Id keyname) {
+    return pool_lookup_id($self->pool, $self->id, keyname);
+  }
+  unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0) {
+    return pool_lookup_num($self->pool, $self->id, keyname, notfound);
+  }
+  bool lookup_void(Id keyname) {
+    return pool_lookup_void($self->pool, $self->id, keyname);
+  }
+  %newobject lookup_checksum;
+  Chksum *lookup_checksum(Id keyname) {
+    Id type = 0;
+    const unsigned char *b = pool_lookup_bin_checksum($self->pool, $self->id, keyname, &type);
+    return solv_chksum_create_from_bin(type, b);
+  }
+  Queue lookup_idarray(Id keyname, Id marker = -1) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    Queue r;
+    queue_init(&r);
+    solvable_lookup_deparray(s, keyname, &r, marker);
+    return r;
+  }
+  %typemap(out) Queue lookup_deparray Queue2Array(Dep *, 1, new_Dep(arg1->pool, id));
+  %newobject lookup_deparray;
+  Queue lookup_deparray(Id keyname, Id marker = -1) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    Queue r;
+    queue_init(&r);
+    solvable_lookup_deparray(s, keyname, &r, marker);
+    return r;
+  }
+  const char *lookup_location(unsigned int *OUTPUT) {
+    return solvable_lookup_location($self->pool->solvables + $self->id, OUTPUT);
+  }
+  const char *lookup_sourcepkg() {
+    return solvable_lookup_sourcepkg($self->pool->solvables + $self->id);
+  }
+  %newobject Dataiterator;
+  Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
+    return new_Dataiterator($self->pool, 0, $self->id, key, match, flags);
+  }
+#ifdef SWIGRUBY
+  %rename("installable?") installable;
+#endif
+  bool installable() {
+    return pool_installable($self->pool, pool_id2solvable($self->pool, $self->id));
+  }
+#ifdef SWIGRUBY
+  %rename("isinstalled?") isinstalled;
+#endif
+  bool isinstalled() {
+    Pool *pool = $self->pool;
+    return pool->installed && pool_id2solvable(pool, $self->id)->repo == pool->installed;
+  }
+
+  const char *name;
+  %{
+    SWIGINTERN void XSolvable_name_set(XSolvable *xs, const char *name) {
+      Pool *pool = xs->pool;
+      pool->solvables[xs->id].name = pool_str2id(pool, name, 1);
+    }
+    SWIGINTERN const char *XSolvable_name_get(XSolvable *xs) {
+      Pool *pool = xs->pool;
+      return pool_id2str(pool, pool->solvables[xs->id].name);
+    }
+  %}
+  Id nameid;
+  %{
+    SWIGINTERN void XSolvable_nameid_set(XSolvable *xs, Id nameid) {
+      xs->pool->solvables[xs->id].name = nameid;
+    }
+    SWIGINTERN Id XSolvable_nameid_get(XSolvable *xs) {
+      return xs->pool->solvables[xs->id].name;
+    }
+  %}
+  const char *evr;
+  %{
+    SWIGINTERN void XSolvable_evr_set(XSolvable *xs, const char *evr) {
+      Pool *pool = xs->pool;
+      pool->solvables[xs->id].evr = pool_str2id(pool, evr, 1);
+    }
+    SWIGINTERN const char *XSolvable_evr_get(XSolvable *xs) {
+      Pool *pool = xs->pool;
+      return pool_id2str(pool, pool->solvables[xs->id].evr);
+    }
+  %}
+  Id evrid;
+  %{
+    SWIGINTERN void XSolvable_evrid_set(XSolvable *xs, Id evrid) {
+      xs->pool->solvables[xs->id].evr = evrid;
+    }
+    SWIGINTERN Id XSolvable_evrid_get(XSolvable *xs) {
+      return xs->pool->solvables[xs->id].evr;
+    }
+  %}
+  const char *arch;
+  %{
+    SWIGINTERN void XSolvable_arch_set(XSolvable *xs, const char *arch) {
+      Pool *pool = xs->pool;
+      pool->solvables[xs->id].arch = pool_str2id(pool, arch, 1);
+    }
+    SWIGINTERN const char *XSolvable_arch_get(XSolvable *xs) {
+      Pool *pool = xs->pool;
+      return pool_id2str(pool, pool->solvables[xs->id].arch);
+    }
+  %}
+  Id archid;
+  %{
+    SWIGINTERN void XSolvable_archid_set(XSolvable *xs, Id archid) {
+      xs->pool->solvables[xs->id].arch = archid;
+    }
+    SWIGINTERN Id XSolvable_archid_get(XSolvable *xs) {
+      return xs->pool->solvables[xs->id].arch;
+    }
+  %}
+  const char *vendor;
+  %{
+    SWIGINTERN void XSolvable_vendor_set(XSolvable *xs, const char *vendor) {
+      Pool *pool = xs->pool;
+      pool->solvables[xs->id].vendor = pool_str2id(pool, vendor, 1);
+    }
+    SWIGINTERN const char *XSolvable_vendor_get(XSolvable *xs) {
+      Pool *pool = xs->pool;
+      return pool_id2str(pool, pool->solvables[xs->id].vendor);
+    }
+  %}
+  Id vendorid;
+  %{
+    SWIGINTERN void XSolvable_vendorid_set(XSolvable *xs, Id vendorid) {
+      xs->pool->solvables[xs->id].vendor = vendorid;
+    }
+    SWIGINTERN Id XSolvable_vendorid_get(XSolvable *xs) {
+      return xs->pool->solvables[xs->id].vendor;
+    }
+  %}
+  Repo * const repo;
+  %{
+    SWIGINTERN Repo *XSolvable_repo_get(XSolvable *xs) {
+      return xs->pool->solvables[xs->id].repo;
+    }
+  %}
+
+  /* old interface, please use the generic add_deparray instead */
+  void add_provides(DepId id, Id marker = -1) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    marker = solv_depmarker(SOLVABLE_PROVIDES, marker);
+    s->provides = repo_addid_dep(s->repo, s->provides, id, marker);
+  }
+  void add_obsoletes(DepId id) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    s->obsoletes = repo_addid_dep(s->repo, s->obsoletes, id, 0);
+  }
+  void add_conflicts(DepId id) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
+  }
+  void add_requires(DepId id, Id marker = -1) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    marker = solv_depmarker(SOLVABLE_REQUIRES, marker);
+    s->requires = repo_addid_dep(s->repo, s->requires, id, marker);
+  }
+  void add_recommends(DepId id) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    s->recommends = repo_addid_dep(s->repo, s->recommends, id, 0);
+  }
+  void add_suggests(DepId id) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    s->suggests = repo_addid_dep(s->repo, s->suggests, id, 0);
+  }
+  void add_supplements(DepId id) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    s->supplements = repo_addid_dep(s->repo, s->supplements, id, 0);
+  }
+  void add_enhances(DepId id) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    s->enhances = repo_addid_dep(s->repo, s->enhances, id, 0);
+  }
+
+  void unset(Id keyname) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    repo_unset(s->repo, $self->id, keyname);
+  }
+
+  void add_deparray(Id keyname, DepId id, Id marker = -1) {
+    Solvable *s = $self->pool->solvables + $self->id;
+    solvable_add_deparray(s, keyname, id, marker);
+  }
+
+  %newobject Selection;
+  Selection *Selection(int setflags=0) {
+    Selection *sel = new_Selection($self->pool);
+    queue_push2(&sel->q, SOLVER_SOLVABLE | setflags, $self->id);
+    return sel;
+  }
+
+#ifdef SWIGRUBY
+  %rename("identical?") identical;
+#endif
+  bool identical(XSolvable *s2) {
+    return solvable_identical($self->pool->solvables + $self->id, s2->pool->solvables + s2->id);
+  }
+  int evrcmp(XSolvable *s2) {
+    return pool_evrcmp($self->pool, $self->pool->solvables[$self->id].evr, s2->pool->solvables[s2->id].evr, EVRCMP_COMPARE);
+  }
+#ifdef SWIGRUBY
+  %rename("matchesdep?") matchesdep;
+#endif
+  bool matchesdep(Id keyname, DepId id, Id marker = -1) {
+    return solvable_matchesdep($self->pool->solvables + $self->id, keyname, id, marker);
+  }
+
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(XSolvable *s) {
+    return $self->pool == s->pool && $self->id == s->id;
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(XSolvable *s) {
+    return !XSolvable___eq__($self, s);
+  }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return pool_solvid2str($self->pool, $self->id);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  %newobject __repr__;
+  const char *__repr__() {
+    char buf[20];
+    sprintf(buf, "<Solvable #%d ", $self->id);
+    return solv_dupjoin(buf, pool_solvid2str($self->pool, $self->id), ">");
+  }
+}
+
+%extend Problem {
+  Problem(Solver *solv, Id id) {
+    Problem *p;
+    p = solv_calloc(1, sizeof(*p));
+    p->solv = solv;
+    p->id = id;
+    return p;
+  }
+  %newobject findproblemrule;
+  XRule *findproblemrule() {
+    Id r = solver_findproblemrule($self->solv, $self->id);
+    return new_XRule($self->solv, r);
+  }
+  %newobject findallproblemrules;
+  %typemap(out) Queue findallproblemrules Queue2Array(XRule *, 1, new_XRule(arg1->solv, id));
+  Queue findallproblemrules(int unfiltered=0) {
+    Solver *solv = $self->solv;
+    Id probr;
+    int i, j;
+    Queue q;
+    queue_init(&q);
+    solver_findallproblemrules(solv, $self->id, &q);
+    if (!unfiltered)
+      {
+        for (i = j = 0; i < q.count; i++)
+          {
+            SolverRuleinfo rclass;
+            probr = q.elements[i];
+            rclass = solver_ruleclass(solv, probr);
+            if (rclass == SOLVER_RULE_UPDATE || rclass == SOLVER_RULE_JOB)
+              continue;
+            q.elements[j++] = probr;
+          }
+        if (j)
+          queue_truncate(&q, j);
+      }
+    return q;
+  }
+  int solution_count() {
+    return solver_solution_count($self->solv, $self->id);
+  }
+  %typemap(out) Queue solutions Queue2Array(Solution *, 1, new_Solution(arg1, id));
+  %newobject solutions;
+  Queue solutions() {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
+    cnt = solver_solution_count($self->solv, $self->id);
+    for (i = 1; i <= cnt; i++)
+      queue_push(&q, i);
+    return q;
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return solver_problem2str($self->solv, $self->id);
+  }
+}
+
+%extend Solution {
+  Solution(Problem *p, Id id) {
+    Solution *s;
+    s = solv_calloc(1, sizeof(*s));
+    s->solv = p->solv;
+    s->problemid = p->id;
+    s->id = id;
+    return s;
+  }
+  int element_count() {
+    return solver_solutionelement_count($self->solv, $self->problemid, $self->id);
+  }
+
+  %typemap(out) Queue elements Queue2Array(Solutionelement *, 4, new_Solutionelement(arg1->solv, arg1->problemid, arg1->id, id, idp[1], idp[2], idp[3]));
+  %newobject elements;
+  Queue elements(bool expandreplaces=0) {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
+    cnt = solver_solutionelement_count($self->solv, $self->problemid, $self->id);
+    for (i = 1; i <= cnt; i++)
+      {
+        Id p, rp, type;
+        solver_next_solutionelement($self->solv, $self->problemid, $self->id, i - 1, &p, &rp);
+        if (p > 0) {
+          type = rp ? SOLVER_SOLUTION_REPLACE : SOLVER_SOLUTION_ERASE;
+        } else {
+          type = p;
+          p = rp;
+          rp = 0;
+        }
+        if (type == SOLVER_SOLUTION_REPLACE && expandreplaces) {
+          int illegal = policy_is_illegal(self->solv, self->solv->pool->solvables + p, self->solv->pool->solvables + rp, 0);
+          if (illegal) {
+            if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0) {
+              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_DOWNGRADE);
+              queue_push2(&q, p, rp);
+            }
+            if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0) {
+              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_ARCHCHANGE);
+              queue_push2(&q, p, rp);
+            }
+            if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0) {
+              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_VENDORCHANGE);
+              queue_push2(&q, p, rp);
+            }
+            if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0) {
+              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_NAMECHANGE);
+              queue_push2(&q, p, rp);
+            }
+            continue;
+          }
+        }
+        queue_push2(&q, i, type);
+        queue_push2(&q, p, rp);
+      }
+    return q;
+  }
+}
+
+%extend Solutionelement {
+  Solutionelement(Solver *solv, Id problemid, Id solutionid, Id id, Id type, Id p, Id rp) {
+    Solutionelement *e;
+    e = solv_calloc(1, sizeof(*e));
+    e->solv = solv;
+    e->problemid = problemid;
+    e->solutionid = id;
+    e->id = id;
+    e->type = type;
+    e->p = p;
+    e->rp = rp;
+    return e;
+  }
+  const char *str() {
+    Id p = $self->type;
+    Id rp = $self->p;
+    int illegal = 0;
+    if (p == SOLVER_SOLUTION_ERASE)
+      {
+        p = rp;
+        rp = 0;
+      }
+    else if (p == SOLVER_SOLUTION_REPLACE)
+      {
+        p = rp;
+        rp = $self->rp;
+      }
+    else if (p == SOLVER_SOLUTION_REPLACE_DOWNGRADE)
+      illegal = POLICY_ILLEGAL_DOWNGRADE;
+    else if (p == SOLVER_SOLUTION_REPLACE_ARCHCHANGE)
+      illegal = POLICY_ILLEGAL_ARCHCHANGE;
+    else if (p == SOLVER_SOLUTION_REPLACE_VENDORCHANGE)
+      illegal = POLICY_ILLEGAL_VENDORCHANGE;
+    else if (p == SOLVER_SOLUTION_REPLACE_NAMECHANGE)
+      illegal = POLICY_ILLEGAL_NAMECHANGE;
+    if (illegal)
+      return pool_tmpjoin($self->solv->pool, "allow ", policy_illegal2str($self->solv, illegal, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp), 0);
+    return solver_solutionelement2str($self->solv, p, rp);
+  }
+  %typemap(out) Queue replaceelements Queue2Array(Solutionelement *, 1, new_Solutionelement(arg1->solv, arg1->problemid, arg1->solutionid, arg1->id, id, arg1->p, arg1->rp));
+  %newobject replaceelements;
+  Queue replaceelements() {
+    Queue q;
+    int illegal;
+
+    queue_init(&q);
+    if ($self->type != SOLVER_SOLUTION_REPLACE || $self->p <= 0 || $self->rp <= 0)
+      illegal = 0;
+    else
+      illegal = policy_is_illegal($self->solv, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp, 0);
+    if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0)
+      queue_push(&q, SOLVER_SOLUTION_REPLACE_DOWNGRADE);
+    if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0)
+      queue_push(&q, SOLVER_SOLUTION_REPLACE_ARCHCHANGE);
+    if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0)
+      queue_push(&q, SOLVER_SOLUTION_REPLACE_VENDORCHANGE);
+    if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0)
+      queue_push(&q, SOLVER_SOLUTION_REPLACE_NAMECHANGE);
+    if (!q.count)
+      queue_push(&q, $self->type);
+    return q;
+  }
+  int illegalreplace() {
+    if ($self->type != SOLVER_SOLUTION_REPLACE || $self->p <= 0 || $self->rp <= 0)
+      return 0;
+    return policy_is_illegal($self->solv, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp, 0);
+  }
+  %newobject solvable;
+  XSolvable * const solvable;
+  %newobject replacement;
+  XSolvable * const replacement;
+  int const jobidx;
+  %{
+    SWIGINTERN XSolvable *Solutionelement_solvable_get(Solutionelement *e) {
+      return new_XSolvable(e->solv->pool, e->p);
+    }
+    SWIGINTERN XSolvable *Solutionelement_replacement_get(Solutionelement *e) {
+      return new_XSolvable(e->solv->pool, e->rp);
+    }
+    SWIGINTERN int Solutionelement_jobidx_get(Solutionelement *e) {
+      if (e->type != SOLVER_SOLUTION_JOB && e->type != SOLVER_SOLUTION_POOLJOB)
+        return -1;
+      return (e->p - 1) / 2;
+    }
+  %}
+  %newobject Job;
+  Job *Job() {
+    Id extraflags = solver_solutionelement_extrajobflags($self->solv, $self->problemid, $self->solutionid);
+    if ($self->type == SOLVER_SOLUTION_JOB || $self->type == SOLVER_SOLUTION_POOLJOB)
+      return new_Job($self->solv->pool, SOLVER_NOOP, 0);
+    if ($self->type == SOLVER_SOLUTION_INFARCH || $self->type == SOLVER_SOLUTION_DISTUPGRADE || $self->type == SOLVER_SOLUTION_BEST)
+      return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->p);
+    if ($self->type == SOLVER_SOLUTION_REPLACE || $self->type == SOLVER_SOLUTION_REPLACE_DOWNGRADE || $self->type == SOLVER_SOLUTION_REPLACE_ARCHCHANGE || $self->type == SOLVER_SOLUTION_REPLACE_VENDORCHANGE || $self->type == SOLVER_SOLUTION_REPLACE_NAMECHANGE)
+      return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->rp);
+    if ($self->type == SOLVER_SOLUTION_ERASE)
+      return new_Job($self->solv->pool, SOLVER_ERASE|SOLVER_SOLVABLE|extraflags, $self->p);
+    return 0;
+  }
+}
+
+%extend Solver {
+  static const int SOLVER_RULE_UNKNOWN = SOLVER_RULE_UNKNOWN;
+  static const int SOLVER_RULE_PKG = SOLVER_RULE_PKG;
+  static const int SOLVER_RULE_PKG_NOT_INSTALLABLE = SOLVER_RULE_PKG_NOT_INSTALLABLE;
+  static const int SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP = SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP;
+  static const int SOLVER_RULE_PKG_REQUIRES = SOLVER_RULE_PKG_REQUIRES;
+  static const int SOLVER_RULE_PKG_SELF_CONFLICT = SOLVER_RULE_PKG_SELF_CONFLICT;
+  static const int SOLVER_RULE_PKG_CONFLICTS = SOLVER_RULE_PKG_CONFLICTS;
+  static const int SOLVER_RULE_PKG_SAME_NAME = SOLVER_RULE_PKG_SAME_NAME;
+  static const int SOLVER_RULE_PKG_OBSOLETES = SOLVER_RULE_PKG_OBSOLETES;
+  static const int SOLVER_RULE_PKG_IMPLICIT_OBSOLETES = SOLVER_RULE_PKG_IMPLICIT_OBSOLETES;
+  static const int SOLVER_RULE_PKG_INSTALLED_OBSOLETES = SOLVER_RULE_PKG_INSTALLED_OBSOLETES;
+  static const int SOLVER_RULE_UPDATE = SOLVER_RULE_UPDATE;
+  static const int SOLVER_RULE_FEATURE = SOLVER_RULE_FEATURE;
+  static const int SOLVER_RULE_JOB = SOLVER_RULE_JOB;
+  static const int SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP = SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
+  static const int SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM = SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
+  static const int SOLVER_RULE_JOB_UNKNOWN_PACKAGE = SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
+  static const int SOLVER_RULE_JOB_UNSUPPORTED = SOLVER_RULE_JOB_UNSUPPORTED;
+  static const int SOLVER_RULE_DISTUPGRADE = SOLVER_RULE_DISTUPGRADE;
+  static const int SOLVER_RULE_INFARCH = SOLVER_RULE_INFARCH;
+  static const int SOLVER_RULE_CHOICE = SOLVER_RULE_CHOICE;
+  static const int SOLVER_RULE_LEARNT = SOLVER_RULE_LEARNT;
+
+  static const int SOLVER_SOLUTION_JOB = SOLVER_SOLUTION_JOB;
+  static const int SOLVER_SOLUTION_POOLJOB = SOLVER_SOLUTION_POOLJOB;
+  static const int SOLVER_SOLUTION_INFARCH = SOLVER_SOLUTION_INFARCH;
+  static const int SOLVER_SOLUTION_DISTUPGRADE = SOLVER_SOLUTION_DISTUPGRADE;
+  static const int SOLVER_SOLUTION_BEST = SOLVER_SOLUTION_BEST;
+  static const int SOLVER_SOLUTION_ERASE = SOLVER_SOLUTION_ERASE;
+  static const int SOLVER_SOLUTION_REPLACE = SOLVER_SOLUTION_REPLACE;
+  static const int SOLVER_SOLUTION_REPLACE_DOWNGRADE = SOLVER_SOLUTION_REPLACE_DOWNGRADE;
+  static const int SOLVER_SOLUTION_REPLACE_ARCHCHANGE = SOLVER_SOLUTION_REPLACE_ARCHCHANGE;
+  static const int SOLVER_SOLUTION_REPLACE_VENDORCHANGE = SOLVER_SOLUTION_REPLACE_VENDORCHANGE;
+  static const int SOLVER_SOLUTION_REPLACE_NAMECHANGE = SOLVER_SOLUTION_REPLACE_NAMECHANGE;
+
+  static const int POLICY_ILLEGAL_DOWNGRADE = POLICY_ILLEGAL_DOWNGRADE;
+  static const int POLICY_ILLEGAL_ARCHCHANGE = POLICY_ILLEGAL_ARCHCHANGE;
+  static const int POLICY_ILLEGAL_VENDORCHANGE = POLICY_ILLEGAL_VENDORCHANGE;
+  static const int POLICY_ILLEGAL_NAMECHANGE = POLICY_ILLEGAL_NAMECHANGE;
+
+  static const int SOLVER_FLAG_ALLOW_DOWNGRADE = SOLVER_FLAG_ALLOW_DOWNGRADE;
+  static const int SOLVER_FLAG_ALLOW_ARCHCHANGE = SOLVER_FLAG_ALLOW_ARCHCHANGE;
+  static const int SOLVER_FLAG_ALLOW_VENDORCHANGE = SOLVER_FLAG_ALLOW_VENDORCHANGE;
+  static const int SOLVER_FLAG_ALLOW_NAMECHANGE = SOLVER_FLAG_ALLOW_NAMECHANGE;
+  static const int SOLVER_FLAG_ALLOW_UNINSTALL = SOLVER_FLAG_ALLOW_UNINSTALL;
+  static const int SOLVER_FLAG_NO_UPDATEPROVIDE = SOLVER_FLAG_NO_UPDATEPROVIDE;
+  static const int SOLVER_FLAG_SPLITPROVIDES = SOLVER_FLAG_SPLITPROVIDES;
+  static const int SOLVER_FLAG_IGNORE_RECOMMENDED = SOLVER_FLAG_IGNORE_RECOMMENDED;
+  static const int SOLVER_FLAG_ADD_ALREADY_RECOMMENDED = SOLVER_FLAG_ADD_ALREADY_RECOMMENDED;
+  static const int SOLVER_FLAG_NO_INFARCHCHECK = SOLVER_FLAG_NO_INFARCHCHECK;
+  static const int SOLVER_FLAG_BEST_OBEY_POLICY = SOLVER_FLAG_BEST_OBEY_POLICY;
+  static const int SOLVER_FLAG_NO_AUTOTARGET = SOLVER_FLAG_NO_AUTOTARGET;
+  static const int SOLVER_FLAG_DUP_ALLOW_DOWNGRADE = SOLVER_FLAG_DUP_ALLOW_DOWNGRADE;
+  static const int SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE = SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE;
+  static const int SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE = SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE;
+  static const int SOLVER_FLAG_DUP_ALLOW_NAMECHANGE = SOLVER_FLAG_DUP_ALLOW_NAMECHANGE;
+  static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS;
+  static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS;
+  static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED;
+  static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES;
+  static const int SOLVER_FLAG_NEED_UPDATEPROVIDE = SOLVER_FLAG_NEED_UPDATEPROVIDE;
+  static const int SOLVER_FLAG_FOCUS_BEST = SOLVER_FLAG_FOCUS_BEST;
+  static const int SOLVER_FLAG_STRONG_RECOMMENDS = SOLVER_FLAG_STRONG_RECOMMENDS;
+  static const int SOLVER_FLAG_INSTALL_ALSO_UPDATES = SOLVER_FLAG_INSTALL_ALSO_UPDATES;
+
+  static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
+  static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
+  static const int SOLVER_REASON_KEEP_INSTALLED = SOLVER_REASON_KEEP_INSTALLED;
+  static const int SOLVER_REASON_RESOLVE_JOB = SOLVER_REASON_RESOLVE_JOB;
+  static const int SOLVER_REASON_UPDATE_INSTALLED = SOLVER_REASON_UPDATE_INSTALLED;
+  static const int SOLVER_REASON_CLEANDEPS_ERASE = SOLVER_REASON_CLEANDEPS_ERASE;
+  static const int SOLVER_REASON_RESOLVE = SOLVER_REASON_RESOLVE;
+  static const int SOLVER_REASON_WEAKDEP = SOLVER_REASON_WEAKDEP;
+  static const int SOLVER_REASON_RESOLVE_ORPHAN = SOLVER_REASON_RESOLVE_ORPHAN;
+  static const int SOLVER_REASON_RECOMMENDED = SOLVER_REASON_RECOMMENDED;
+  static const int SOLVER_REASON_SUPPLEMENTED = SOLVER_REASON_SUPPLEMENTED;
+
+  /* legacy */
+  static const int SOLVER_RULE_RPM = SOLVER_RULE_RPM;
+
+  ~Solver() {
+    solver_free($self);
+  }
+
+  int set_flag(int flag, int value) {
+    return solver_set_flag($self, flag, value);
+  }
+  int get_flag(int flag) {
+    return solver_get_flag($self, flag);
+  }
+
+  %typemap(out) Queue solve Queue2Array(Problem *, 1, new_Problem(arg1, id));
+  %newobject solve;
+  Queue solve(Queue solvejobs) {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
+    solver_solve($self, &solvejobs);
+    cnt = solver_problem_count($self);
+    for (i = 1; i <= cnt; i++)
+      queue_push(&q, i);
+    return q;
+  }
+
+  %newobject transaction;
+  Transaction *transaction() {
+    return solver_create_transaction($self);
+  }
+
+  int describe_decision(XSolvable *s, XRule **OUTPUT) {
+    int ruleid;
+    int reason = solver_describe_decision($self, s->id, &ruleid);
+    *OUTPUT = new_XRule($self, ruleid);
+    return reason;
+  }
+
+  %newobject describe_weakdep_decision_raw;
+  Queue describe_weakdep_decision_raw(XSolvable *s) {
+    Queue q;
+    queue_init(&q);
+    solver_describe_weakdep_decision($self, s->id, &q);
+    return q;
+  }
+#if defined(SWIGPYTHON)
+  %pythoncode {
+    def describe_weakdep_decision(self, s):
+      d = iter(self.describe_weakdep_decision_raw(s))
+      return [ (t, XSolvable(self.pool, sid), Dep(self.pool, id)) for t, sid, id in zip(d, d, d) ]
+  }
+#endif
+#if defined(SWIGPERL)
+  %perlcode {
+    sub solv::Solver::describe_weakdep_decision {
+      my ($self, $s) = @_;
+      my $pool = $self->{'pool'};
+      my @res;
+      my @d = $self->describe_weakdep_decision_raw($s);
+      push @res, [ splice(@d, 0, 3) ] while @d;
+      return map { [ $_->[0], solv::XSolvable->new($pool, $_->[1]), solv::Dep->new($pool, $_->[2]) ] } @res;
+    }
+  }
+#endif
+#if defined(SWIGRUBY)
+%init %{
+rb_eval_string(
+    "class Solv::Solver\n"
+    "  def describe_weakdep_decision(s)\n"
+    "    self.describe_weakdep_decision_raw(s).each_slice(3).map { |t, sid, id| [ t, Solv::XSolvable.new(self.pool, sid), Solv::Dep.new(self.pool, id)] }\n"
+    "  end\n"
+    "end\n"
+  );
+%}
+#endif
+
+  int alternatives_count() {
+    return solver_alternatives_count($self);
+  }
+
+  %newobject alternative;
+  Alternative *alternative(Id aid) {
+    Alternative *a = solv_calloc(1, sizeof(*a));
+    a->solv = $self;
+    queue_init(&a->choices);
+    a->type = solver_get_alternative($self, aid, &a->dep_id, &a->from_id, &a->chosen_id, &a->choices, &a->level);
+    if (!a->type) {
+      queue_free(&a->choices);
+      solv_free(a);
+      return 0;
+    }
+    if (a->type == SOLVER_ALTERNATIVE_TYPE_RULE) {
+      a->rid = a->dep_id;
+      a->dep_id = 0;
+    }
+    return a;
+  }
+
+  %typemap(out) Queue all_alternatives Queue2Array(Alternative *, 1, Solver_alternative(arg1, id));
+  %newobject all_alternatives;
+  Queue all_alternatives() {
+    Queue q;
+    int i, cnt;
+    queue_init(&q);
+    cnt = solver_alternatives_count($self);
+    for (i = 1; i <= cnt; i++)
+      queue_push(&q, i);
+    return q;
+  }
+
+  bool write_testcase(const char *dir) {
+    return testcase_write($self, dir, TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, 0, 0);
+  }
+
+  Queue raw_decisions(int filter=0) {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionqueue($self, &q);
+    if (filter) {
+      int i, j;
+      for (i = j = 0; i < q.count; i++)
+        if ((filter > 0 && q.elements[i] > 1) ||
+            (filter < 0 && q.elements[i] < 0))
+          q.elements[j++] = q.elements[i];
+      queue_truncate(&q, j);
+    }
+    return q;
+  }
+
+  %typemap(out) Queue get_recommended Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject get_recommended;
+  Queue get_recommended(bool noselected=0) {
+    Queue q;
+    queue_init(&q);
+    solver_get_recommendations($self, &q, NULL, noselected);
+    return q;
+  }
+  %typemap(out) Queue get_suggested Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject get_suggested;
+  Queue get_suggested(bool noselected=0) {
+    Queue q;
+    queue_init(&q);
+    solver_get_recommendations($self, NULL, &q, noselected);
+    return q;
+  }
+}
+
+%extend Transaction {
+  static const int SOLVER_TRANSACTION_IGNORE = SOLVER_TRANSACTION_IGNORE;
+  static const int SOLVER_TRANSACTION_ERASE = SOLVER_TRANSACTION_ERASE;
+  static const int SOLVER_TRANSACTION_REINSTALLED = SOLVER_TRANSACTION_REINSTALLED;
+  static const int SOLVER_TRANSACTION_DOWNGRADED = SOLVER_TRANSACTION_DOWNGRADED;
+  static const int SOLVER_TRANSACTION_CHANGED = SOLVER_TRANSACTION_CHANGED;
+  static const int SOLVER_TRANSACTION_UPGRADED = SOLVER_TRANSACTION_UPGRADED;
+  static const int SOLVER_TRANSACTION_OBSOLETED = SOLVER_TRANSACTION_OBSOLETED;
+  static const int SOLVER_TRANSACTION_INSTALL = SOLVER_TRANSACTION_INSTALL;
+  static const int SOLVER_TRANSACTION_REINSTALL = SOLVER_TRANSACTION_REINSTALL;
+  static const int SOLVER_TRANSACTION_DOWNGRADE = SOLVER_TRANSACTION_DOWNGRADE;
+  static const int SOLVER_TRANSACTION_CHANGE = SOLVER_TRANSACTION_CHANGE;
+  static const int SOLVER_TRANSACTION_UPGRADE = SOLVER_TRANSACTION_UPGRADE;
+  static const int SOLVER_TRANSACTION_OBSOLETES = SOLVER_TRANSACTION_OBSOLETES;
+  static const int SOLVER_TRANSACTION_MULTIINSTALL = SOLVER_TRANSACTION_MULTIINSTALL;
+  static const int SOLVER_TRANSACTION_MULTIREINSTALL = SOLVER_TRANSACTION_MULTIREINSTALL;
+  static const int SOLVER_TRANSACTION_MAXTYPE = SOLVER_TRANSACTION_MAXTYPE;
+  static const int SOLVER_TRANSACTION_SHOW_ACTIVE = SOLVER_TRANSACTION_SHOW_ACTIVE;
+  static const int SOLVER_TRANSACTION_SHOW_ALL = SOLVER_TRANSACTION_SHOW_ALL;
+  static const int SOLVER_TRANSACTION_SHOW_OBSOLETES = SOLVER_TRANSACTION_SHOW_OBSOLETES;
+  static const int SOLVER_TRANSACTION_SHOW_MULTIINSTALL = SOLVER_TRANSACTION_SHOW_MULTIINSTALL;
+  static const int SOLVER_TRANSACTION_CHANGE_IS_REINSTALL = SOLVER_TRANSACTION_CHANGE_IS_REINSTALL;
+  static const int SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE = SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
+  static const int SOLVER_TRANSACTION_MERGE_VENDORCHANGES = SOLVER_TRANSACTION_MERGE_VENDORCHANGES;
+  static const int SOLVER_TRANSACTION_MERGE_ARCHCHANGES = SOLVER_TRANSACTION_MERGE_ARCHCHANGES;
+  static const int SOLVER_TRANSACTION_RPM_ONLY = SOLVER_TRANSACTION_RPM_ONLY;
+  static const int SOLVER_TRANSACTION_ARCHCHANGE = SOLVER_TRANSACTION_ARCHCHANGE;
+  static const int SOLVER_TRANSACTION_VENDORCHANGE = SOLVER_TRANSACTION_VENDORCHANGE;
+  static const int SOLVER_TRANSACTION_KEEP_ORDERDATA = SOLVER_TRANSACTION_KEEP_ORDERDATA;
+  ~Transaction() {
+    transaction_free($self);
+  }
+#ifdef SWIGRUBY
+  %rename("isempty?") isempty;
+#endif
+  bool isempty() {
+    return $self->steps.count == 0;
+  }
+
+  %newobject othersolvable;
+  XSolvable *othersolvable(XSolvable *s) {
+    Id op = transaction_obs_pkg($self, s->id);
+    return new_XSolvable($self->pool, op);
+  }
+
+  %typemap(out) Queue allothersolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject allothersolvables;
+  Queue allothersolvables(XSolvable *s) {
+    Queue q;
+    queue_init(&q);
+    transaction_all_obs_pkgs($self, s->id, &q);
+    return q;
+  }
+
+  %typemap(out) Queue classify Queue2Array(TransactionClass *, 4, new_TransactionClass(arg1, arg2, id, idp[1], idp[2], idp[3]));
+  %newobject classify;
+  Queue classify(int mode = 0) {
+    Queue q;
+    queue_init(&q);
+    transaction_classify($self, mode, &q);
+    return q;
+  }
+
+  /* deprecated, use newsolvables instead */
+  %typemap(out) Queue newpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject newpackages;
+  Queue newpackages() {
+    Queue q;
+    int cut;
+    queue_init(&q);
+    cut = transaction_installedresult(self, &q);
+    queue_truncate(&q, cut);
+    return q;
+  }
+
+  /* deprecated, use keptsolvables instead */
+  %typemap(out) Queue keptpackages Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject keptpackages;
+  Queue keptpackages() {
+    Queue q;
+    int cut;
+    queue_init(&q);
+    cut = transaction_installedresult(self, &q);
+    if (cut)
+      queue_deleten(&q, 0, cut);
+    return q;
+  }
+
+  %typemap(out) Queue newsolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject newsolvables;
+  Queue newsolvables() {
+    Queue q;
+    int cut;
+    queue_init(&q);
+    cut = transaction_installedresult(self, &q);
+    queue_truncate(&q, cut);
+    return q;
+  }
+
+  %typemap(out) Queue keptsolvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject keptsolvables;
+  Queue keptsolvables() {
+    Queue q;
+    int cut;
+    queue_init(&q);
+    cut = transaction_installedresult(self, &q);
+    if (cut)
+      queue_deleten(&q, 0, cut);
+    return q;
+  }
+
+  %typemap(out) Queue steps Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject steps;
+  Queue steps() {
+    Queue q;
+    queue_init_clone(&q, &$self->steps);
+    return q;
+  }
+
+  int steptype(XSolvable *s, int mode) {
+    return transaction_type($self, s->id, mode);
+  }
+  long long calc_installsizechange() {
+    return transaction_calc_installsizechange($self);
+  }
+  void order(int flags=0) {
+    transaction_order($self, flags);
+  }
+}
+
+%extend TransactionClass {
+  TransactionClass(Transaction *trans, int mode, Id type, int count, Id fromid, Id toid) {
+    TransactionClass *cl = solv_calloc(1, sizeof(*cl));
+    cl->transaction = trans;
+    cl->mode = mode;
+    cl->type = type;
+    cl->count = count;
+    cl->fromid = fromid;
+    cl->toid = toid;
+    return cl;
+  }
+  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->transaction->pool, id));
+  %newobject solvables;
+  Queue solvables() {
+    Queue q;
+    queue_init(&q);
+    transaction_classify_pkgs($self->transaction, $self->mode, $self->type, $self->fromid, $self->toid, &q);
+    return q;
+  }
+  const char * const fromstr;
+  const char * const tostr;
+  %{
+    SWIGINTERN const char *TransactionClass_fromstr_get(TransactionClass *cl) {
+      return pool_id2str(cl->transaction->pool, cl->fromid);
+    }
+    SWIGINTERN const char *TransactionClass_tostr_get(TransactionClass *cl) {
+      return pool_id2str(cl->transaction->pool, cl->toid);
+    }
+  %}
+}
+
+%extend XRule {
+  XRule(Solver *solv, Id id) {
+    if (!id)
+      return 0;
+    XRule *xr = solv_calloc(1, sizeof(*xr));
+    xr->solv = solv;
+    xr->id = id;
+    return xr;
+  }
+  int const type;
+  %{
+    SWIGINTERN int XRule_type_get(XRule *xr) {
+      return solver_ruleclass(xr->solv, xr->id);
+    }
+  %}
+  %newobject info;
+  Ruleinfo *info() {
+    Id type, source, target, dep;
+    type = solver_ruleinfo($self->solv, $self->id, &source, &target, &dep);
+    return new_Ruleinfo($self, type, source, target, dep);
+  }
+  %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1, id, idp[1], idp[2], idp[3]));
+  %newobject allinfos;
+  Queue allinfos() {
+    Queue q;
+    queue_init(&q);
+    solver_allruleinfos($self->solv, $self->id, &q);
+    return q;
+  }
+
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(XRule *xr) {
+    return $self->solv == xr->solv && $self->id == xr->id;
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(XRule *xr) {
+    return !XRule___eq__($self, xr);
+  }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  %newobject __repr__;
+  const char *__repr__() {
+    char buf[20];
+    sprintf(buf, "<Rule #%d>", $self->id);
+    return solv_strdup(buf);
+  }
+}
+
+%extend Ruleinfo {
+  Ruleinfo(XRule *r, Id type, Id source, Id target, Id dep_id) {
+    Ruleinfo *ri = solv_calloc(1, sizeof(*ri));
+    ri->solv = r->solv;
+    ri->rid = r->id;
+    ri->type = type;
+    ri->source = source;
+    ri->target = target;
+    ri->dep_id = dep_id;
+    return ri;
+  }
+  %newobject solvable;
+  XSolvable * const solvable;
+  %newobject othersolvable;
+  XSolvable * const othersolvable;
+  %newobject dep;
+  Dep * const dep;
+  %{
+    SWIGINTERN XSolvable *Ruleinfo_solvable_get(Ruleinfo *ri) {
+      return new_XSolvable(ri->solv->pool, ri->source);
+    }
+    SWIGINTERN XSolvable *Ruleinfo_othersolvable_get(Ruleinfo *ri) {
+      return new_XSolvable(ri->solv->pool, ri->target);
+    }
+    SWIGINTERN Dep *Ruleinfo_dep_get(Ruleinfo *ri) {
+      return new_Dep(ri->solv->pool, ri->dep_id);
+    }
+  %}
+  const char *problemstr() {
+    return solver_problemruleinfo2str($self->solv, $self->type, $self->source, $self->target, $self->dep_id);
+  }
+}
+
+%extend XRepodata {
+  XRepodata(Repo *repo, Id id) {
+    XRepodata *xr = solv_calloc(1, sizeof(*xr));
+    xr->repo = repo;
+    xr->id = id;
+    return xr;
+  }
+  Id new_handle() {
+    return repodata_new_handle(repo_id2repodata($self->repo, $self->id));
+  }
+  void set_id(Id solvid, Id keyname, DepId id) {
+    repodata_set_id(repo_id2repodata($self->repo, $self->id), solvid, keyname, id);
+  }
+  void set_num(Id solvid, Id keyname, unsigned long long num) {
+    repodata_set_num(repo_id2repodata($self->repo, $self->id), solvid, keyname, num);
+  }
+  void set_str(Id solvid, Id keyname, const char *str) {
+    repodata_set_str(repo_id2repodata($self->repo, $self->id), solvid, keyname, str);
+  }
+  void set_void(Id solvid, Id keyname) {
+    repodata_set_void(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
+  void set_poolstr(Id solvid, Id keyname, const char *str) {
+    repodata_set_poolstr(repo_id2repodata($self->repo, $self->id), solvid, keyname, str);
+  }
+  void add_idarray(Id solvid, Id keyname, DepId id) {
+    repodata_add_idarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, id);
+  }
+  void add_flexarray(Id solvid, Id keyname, Id handle) {
+    repodata_add_flexarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, handle);
+  }
+  void set_checksum(Id solvid, Id keyname, Chksum *chksum) {
+    const unsigned char *buf = solv_chksum_get(chksum, 0);
+    if (buf)
+      repodata_set_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, solv_chksum_get_type(chksum), buf);
+  }
+  void set_sourcepkg(Id solvid, const char *sourcepkg) {
+    repodata_set_sourcepkg(repo_id2repodata($self->repo, $self->id), solvid, sourcepkg);
+  }
+  void set_location(Id solvid, unsigned int mediano, const char *location) {
+    repodata_set_location(repo_id2repodata($self->repo, $self->id), solvid, mediano, 0, location);
+  }
+  void unset(Id solvid, Id keyname) {
+    repodata_unset(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
+  const char *lookup_str(Id solvid, Id keyname) {
+    return repodata_lookup_str(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
+  Id lookup_id(Id solvid, Id keyname) {
+    return repodata_lookup_id(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
+  unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0) {
+    return repodata_lookup_num(repo_id2repodata($self->repo, $self->id), solvid, keyname, notfound);
+  }
+  bool lookup_void(Id solvid, Id keyname) {
+    return repodata_lookup_void(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
+  Queue lookup_idarray(Id solvid, Id keyname) {
+    Queue r;
+    queue_init(&r);
+    repodata_lookup_idarray(repo_id2repodata($self->repo, $self->id), solvid, keyname, &r);
+    return r;
+  }
+  %newobject lookup_checksum;
+  Chksum *lookup_checksum(Id solvid, Id keyname) {
+    Id type = 0;
+    const unsigned char *b = repodata_lookup_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, &type);
+    return solv_chksum_create_from_bin(type, b);
+  }
+  void internalize() {
+    repodata_internalize(repo_id2repodata($self->repo, $self->id));
+  }
+  void create_stubs() {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    data = repodata_create_stubs(data);
+    $self->id = data->repodataid;
+  }
+  bool write(FILE *fp) {
+    return repodata_write(repo_id2repodata($self->repo, $self->id), fp) == 0;
+  }
+  Id str2dir(const char *dir, bool create=1) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    return repodata_str2dir(data, dir, create);
+  }
+  const char *dir2str(Id did, const char *suf = 0) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    return repodata_dir2str(data, did, suf);
+  }
+  void add_dirstr(Id solvid, Id keyname, Id dir, const char *str) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    repodata_add_dirstr(data, solvid, keyname, dir, str);
+  }
+  bool add_solv(FILE *fp, int flags = 0) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    int r, oldstate = data->state;
+    data->state = REPODATA_LOADING;
+    r = repo_add_solv(data->repo, fp, flags | REPO_USE_LOADING);
+    if (r || data->state == REPODATA_LOADING)
+      data->state = oldstate;
+    return r;
+  }
+  void extend_to_repo() {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    repodata_extend_block(data, data->repo->start, data->repo->end - data->repo->start);
+  }
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
+  bool __eq__(XRepodata *xr) {
+    return $self->repo == xr->repo && $self->id == xr->id;
+  }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
+  bool __ne__(XRepodata *xr) {
+    return !XRepodata___eq__($self, xr);
+  }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
+  %newobject __repr__;
+  const char *__repr__() {
+    char buf[20];
+    sprintf(buf, "<Repodata #%d>", $self->id);
+    return solv_strdup(buf);
+  }
+}
+
+#ifdef ENABLE_PUBKEY
+%extend Solvsig {
+  Solvsig(FILE *fp) {
+    return solvsig_create(fp);
+  }
+  ~Solvsig() {
+    solvsig_free($self);
+  }
+  %newobject Chksum;
+  Chksum *Chksum() {
+    return $self->htype ? (Chksum *)solv_chksum_create($self->htype) : 0;
+  }
+#ifdef ENABLE_PGPVRFY
+  %newobject verify;
+  XSolvable *verify(Repo *repo, Chksum *chksum) {
+    Id p = solvsig_verify($self, repo, chksum);
+    return new_XSolvable(repo->pool, p);
+  }
+#endif
+}
+#endif
+
+%extend Alternative {
+  static const int SOLVER_ALTERNATIVE_TYPE_RULE = SOLVER_ALTERNATIVE_TYPE_RULE;
+  static const int SOLVER_ALTERNATIVE_TYPE_RECOMMENDS = SOLVER_ALTERNATIVE_TYPE_RECOMMENDS;
+  static const int SOLVER_ALTERNATIVE_TYPE_SUGGESTS = SOLVER_ALTERNATIVE_TYPE_SUGGESTS;
+
+  ~Alternative() {
+    queue_free(&$self->choices);
+    solv_free($self);
+  }
+  %newobject chosen;
+  XSolvable * const chosen;
+  %newobject rule;
+  XRule * const rule;
+  %newobject depsolvable;
+  XSolvable * const depsolvable;
+  %newobject dep;
+  Dep * const dep;
+  %{
+    SWIGINTERN XSolvable *Alternative_chosen_get(Alternative *a) {
+      return new_XSolvable(a->solv->pool, a->chosen_id);
+    }
+    SWIGINTERN XRule *Alternative_rule_get(Alternative *a) {
+      return new_XRule(a->solv, a->rid);
+    }
+    SWIGINTERN XSolvable *Alternative_depsolvable_get(Alternative *a) {
+      return new_XSolvable(a->solv->pool, a->from_id);
+    }
+    SWIGINTERN Dep *Alternative_dep_get(Alternative *a) {
+      return new_Dep(a->solv->pool, a->dep_id);
+    }
+  %}
+
+  Queue choices_raw() {
+    Queue r;
+    queue_init_clone(&r, &$self->choices);
+    return r;
+  }
+
+  %typemap(out) Queue choices Queue2Array(XSolvable *, 1, new_XSolvable(arg1->solv->pool, id));
+  Queue choices() {
+    int i;
+    Queue r;
+    queue_init_clone(&r, &$self->choices);
+    for (i = 0; i < r.count; i++)
+      if (r.elements[i] < 0)
+        r.elements[i] = -r.elements[i];
+    return r;
+  }
+
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return solver_alternative2str($self->solv, $self->type, $self->type == SOLVER_ALTERNATIVE_TYPE_RULE ? $self->rid : $self->dep_id, $self->from_id);
+  }
+}
+
+#if defined(SWIGTCL)
+%init %{
+  Tcl_Eval(interp,
+"proc solv::iter {varname iter body} {\n"\
+"  while 1 {\n"\
+"    set value [$iter __next__]\n"\
+"    if {$value eq \"NULL\"} { break }\n"\
+"    uplevel [list set $varname $value]\n"\
+"    set code [catch {uplevel $body} result]\n"\
+"    switch -exact -- $code {\n"\
+"      0 {}\n"\
+"      3 { return }\n"\
+"      4 {}\n"\
+"      default { return -code $code $result }\n"\
+"    }\n"\
+"  }\n"\
+"}\n"
+  );
+%}
+#endif
+
diff --git a/libsolv-0.7.2/bindings/tcl/CMakeLists.txt b/libsolv-0.7.2/bindings/tcl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f78de9f
--- /dev/null
@@ -0,0 +1,38 @@
+FIND_PACKAGE (TCL)
+
+SET (SWIG_TCL_FLAGS -namespace -pkgversion ${VERSION})
+
+EXECUTE_PROCESS (
+    COMMAND echo "puts -nonewline [lindex [::tcl::tm::list] end]"
+    COMMAND ${TCL_TCLSH}
+    OUTPUT_VARIABLE TCL_INSTALL_DIR
+)
+
+MESSAGE (STATUS "Tclsh executable: ${TCL_TCLSH}")
+MESSAGE (STATUS "Tcl installation dir: ${TCL_INSTALL_DIR}")
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv_tcl.c
+    COMMAND ${SWIG_EXECUTABLE} ${SWIG_FLAGS} -tcl ${SWIG_TCL_FLAGS} -I${CMAKE_SOURCE_DIR}/src -o solv_tcl.c ${CMAKE_SOURCE_DIR}/bindings/solv.i
+    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/solv.i
+)
+
+ADD_DEFINITIONS(-Wno-unused)
+INCLUDE_DIRECTORIES (${TCL_INCLUDE_PATH})
+
+ADD_LIBRARY (bindings_tcl SHARED solv_tcl.c)
+SET_TARGET_PROPERTIES (bindings_tcl PROPERTIES PREFIX "" OUTPUT_NAME "solv-${VERSION}" INSTALL_NAME_DIR "${TCL_INSTALL_DIR}")
+TARGET_LINK_LIBRARIES (bindings_tcl libsolvext libsolv ${TCL_LIBRARY} ${SYSTEM_LIBRARIES})
+INSTALL (TARGETS bindings_tcl LIBRARY DESTINATION ${TCL_INSTALL_DIR})
+
+ADD_CUSTOM_COMMAND (
+    OUTPUT solv.tm
+       COMMAND sed -e "s/__VERSION__/${VERSION}/" ${CMAKE_SOURCE_DIR}/bindings/tcl/solv.tm.in >${CMAKE_CURRENT_BINARY_DIR}/solv.tm
+    DEPENDS ${CMAKE_SOURCE_DIR}/bindings/tcl/solv.tm.in
+    COMMENT "Creating Tcl module to load libsolv"
+)
+ADD_CUSTOM_TARGET (solv_tm ALL DEPENDS solv.tm)
+SET_SOURCE_FILES_PROPERTIES (solv.tm PROPERTIES GENERATED TRUE)
+
+INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/solv.tm DESTINATION ${TCL_INSTALL_DIR} RENAME solv-${VERSION}.tm)
diff --git a/libsolv-0.7.2/bindings/tcl/solv.tm.in b/libsolv-0.7.2/bindings/tcl/solv.tm.in
new file mode 100644 (file)
index 0000000..3b94771
--- /dev/null
@@ -0,0 +1,4 @@
+package require Tcl
+
+#package provide solv __VERSION__
+load [::file join [::file dirname [::info script]] "solv-__VERSION__[::info sharedlibextension]"]
diff --git a/libsolv-0.7.2/cmake/modules/FindCheck.cmake b/libsolv-0.7.2/cmake/modules/FindCheck.cmake
new file mode 100644 (file)
index 0000000..8ed3739
--- /dev/null
@@ -0,0 +1,27 @@
+
+IF (CHECK_INCLUDE_DIR)
+  # Already in cache, be silent
+  SET(CHECK_FIND_QUIETLY TRUE)
+ENDIF (CHECK_INCLUDE_DIR)
+
+FIND_PATH(CHECK_INCLUDE_DIR NAMES check.h)
+
+# Look for the library.
+FIND_LIBRARY(CHECK_LIBRARY NAMES check)
+
+IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4)
+  # handle the QUIETLY and REQUIRED arguments and set CHECK_FOUND to TRUE if
+  # all listed variables are TRUE
+  INCLUDE(FindPackageHandleStandardArgs)
+
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(Check "Please install 'check' and 'check-devel' packages" CHECK_LIBRARY CHECK_INCLUDE_DIR)
+ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4)
+
+IF(CHECK_FOUND)
+  SET( CHECK_LIBRARIES ${CHECK_LIBRARY} )
+ELSE(CHECK_FOUND)
+  SET( CHECK_LIBRARIES )
+ENDIF(CHECK_FOUND)
+
+MARK_AS_ADVANCED(CHECK_INCLUDE_DIR)
+MARK_AS_ADVANCED(CHECK_LIBRARY)
diff --git a/libsolv-0.7.2/cmake/modules/FindEXPAT.cmake b/libsolv-0.7.2/cmake/modules/FindEXPAT.cmake
new file mode 100644 (file)
index 0000000..d48eef3
--- /dev/null
@@ -0,0 +1,38 @@
+# - Find expat
+# Find the native EXPAT headers and libraries.
+#
+#  EXPAT_INCLUDE_DIRS - where to find expat.h, etc.
+#  EXPAT_LIBRARIES    - List of libraries when using expat.
+#  EXPAT_FOUND        - True if expat found.
+
+# Look for the header file.
+FIND_PATH(EXPAT_INCLUDE_DIR NAMES expat.h)
+MARK_AS_ADVANCED(EXPAT_INCLUDE_DIR)
+
+# Look for the library.
+FIND_LIBRARY(EXPAT_LIBRARY NAMES expat)
+MARK_AS_ADVANCED(EXPAT_LIBRARY)
+
+# Copy the results to the output variables.
+IF(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY)
+  SET(EXPAT_FOUND 1)
+  SET(EXPAT_LIBRARIES ${EXPAT_LIBRARY})
+  SET(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIR})
+ELSE(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY)
+  SET(EXPAT_FOUND 0)
+  SET(EXPAT_LIBRARIES)
+  SET(EXPAT_INCLUDE_DIRS)
+ENDIF(EXPAT_INCLUDE_DIR AND EXPAT_LIBRARY)
+
+# Report the results.
+IF(NOT EXPAT_FOUND)
+  SET(EXPAT_DIR_MESSAGE
+    "EXPAT was not found. Make sure EXPAT_LIBRARY and EXPAT_INCLUDE_DIR are set.")
+  IF(NOT EXPAT_FIND_QUIETLY)
+    MESSAGE(STATUS "${EXPAT_DIR_MESSAGE}")
+  ELSE(NOT EXPAT_FIND_QUIETLY)
+    IF(EXPAT_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "${EXPAT_DIR_MESSAGE}")
+    ENDIF(EXPAT_FIND_REQUIRED)
+  ENDIF(NOT EXPAT_FIND_QUIETLY)
+ENDIF(NOT EXPAT_FOUND)
diff --git a/libsolv-0.7.2/cmake/modules/FindLZMA.cmake b/libsolv-0.7.2/cmake/modules/FindLZMA.cmake
new file mode 100644 (file)
index 0000000..eb112df
--- /dev/null
@@ -0,0 +1,25 @@
+# - Find lzma
+# Find the native LZMA headers and library
+#
+#  LZMA_INCLUDE_DIR    - where to find lzma.h, etc.
+#  LZMA_LIBRARIES      - List of libraries when using liblzma.
+#  LZMA_FOUND          - True if liblzma found.
+
+IF (LZMA_INCLUDE_DIR)
+  # Already in cache, be silent
+  SET(LZMA_FIND_QUIETLY TRUE)
+ENDIF (LZMA_INCLUDE_DIR)
+
+FIND_PATH(LZMA_INCLUDE_DIR lzma.h)
+FIND_LIBRARY(LZMA_LIBRARY NAMES lzma liblzma)
+
+# handle the QUIETLY and REQUIRED arguments and set LZMA_FOUND to TRUE if 
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMA DEFAULT_MSG LZMA_LIBRARY LZMA_INCLUDE_DIR)
+
+IF(LZMA_FOUND)
+  SET( LZMA_LIBRARIES ${LZMA_LIBRARY} )
+ELSE(LZMA_FOUND)
+  SET( LZMA_LIBRARIES )
+ENDIF(LZMA_FOUND)
diff --git a/libsolv-0.7.2/cmake/modules/FindLibSolv.cmake b/libsolv-0.7.2/cmake/modules/FindLibSolv.cmake
new file mode 100644 (file)
index 0000000..166e79d
--- /dev/null
@@ -0,0 +1,95 @@
+# FindLibSolv - Find libsolv headers and libraries.
+#
+# Sample:
+#
+#   SET( LibSolv_USE_STATIC_LIBS OFF )
+#   FIND_PACKAGE( LibSolv REQUIRED ext )
+#   IF( LibSolv_FOUND )
+#      INCLUDE_DIRECTORIES( ${LibSolv_INCLUDE_DIRS} )
+#      TARGET_LINK_LIBRARIES( ... ${LibSolv_LIBRARIES} )
+#   ENDIF()
+#
+# Variables used by this module need to be set before calling find_package
+# (not that they are cmale cased like the modiulemane itself):
+#
+#   LibSolv_USE_STATIC_LIBS    Can be set to ON to force the use of the static
+#                              libsolv libraries. Defaults to OFF.
+#
+# Supported components:
+#
+#   ext                                Also include libsolvext
+#
+# Variables provided by this module:
+#
+#   LibSolv_FOUND              Include dir, libsolv and all extra libraries
+#                              specified in the COMPONENTS list were found.
+#
+#   LibSolv_LIBRARIES          Link to these to use all the libraries you specified.
+#
+#   LibSolv_INCLUDE_DIRS       Include directories.
+#
+# For each component you specify in find_package(), the following (UPPER-CASE)
+# variables are set to pick and choose components instead of just using LibSolv_LIBRARIES:
+#
+#   LIBSOLV_FOUND                      TRUE if libsolv was found
+#   LIBSOLV_LIBRARY                    libsolv libraries
+#
+#   LIBSOLV_${COMPONENT}_FOUND         TRUE if the library component was found
+#   LIBSOLV_${COMPONENT}_LIBRARY       The libraries for the specified component
+#
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+IF(LibSolv_USE_STATIC_LIBS)
+    SET( _ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+    SET(CMAKE_FIND_LIBRARY_SUFFIXES .a )
+ENDIF()
+
+# Look for the header files
+UNSET(LibSolv_INCLUDE_DIRS CACHE)
+FIND_PATH(LibSolv_INCLUDE_DIRS NAMES solv/solvable.h)
+
+# Look for the core library
+UNSET(LIBSOLV_LIBRARY CACHE)
+FIND_LIBRARY(LIBSOLV_LIBRARY NAMES solv)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSolv DEFAULT_MSG LIBSOLV_LIBRARY LibSolv_INCLUDE_DIRS)
+MARK_AS_ADVANCED(
+    LIBSOLV_FOUND
+    LIBSOLV_LIBRARY
+)
+
+# Prepare return values and collectiong more components
+SET(LibSolv_FOUND ${LIBSOLV_FOUND})
+SET(LibSolv_LIBRARIES ${LIBSOLV_LIBRARY})
+MARK_AS_ADVANCED(
+    LibSolv_FOUND
+    LibSolv_LIBRARIES
+    LibSolv_INCLUDE_DIRS
+)
+
+# Look for components
+FOREACH(COMPONENT ${LibSolv_FIND_COMPONENTS})
+    STRING(TOUPPER ${COMPONENT} _UPPERCOMPONENT)
+    UNSET(LIBSOLV_${_UPPERCOMPONENT}_LIBRARY CACHE)
+    FIND_LIBRARY(LIBSOLV_${_UPPERCOMPONENT}_LIBRARY NAMES solv${COMPONENT})
+    SET(LibSolv_${COMPONENT}_FIND_REQUIRED ${LibSolv_FIND_REQUIRED})
+    SET(LibSolv_${COMPONENT}_FIND_QUIETLY ${LibSolv_FIND_QUIETLY})
+    FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSolv_${COMPONENT} DEFAULT_MSG LIBSOLV_${_UPPERCOMPONENT}_LIBRARY)
+    MARK_AS_ADVANCED(
+       LIBSOLV_${_UPPERCOMPONENT}_FOUND
+       LIBSOLV_${_UPPERCOMPONENT}_LIBRARY
+    )
+    IF(LIBSOLV_${_UPPERCOMPONENT}_FOUND)
+       SET(LibSolv_LIBRARIES ${LibSolv_LIBRARIES} ${LIBSOLV_${_UPPERCOMPONENT}_LIBRARY})
+    ELSE()
+       SET(LibSolv_FOUND FALSE)
+    ENDIF()
+ENDFOREACH()
+
+# restore CMAKE_FIND_LIBRARY_SUFFIXES
+IF(Solv_USE_STATIC_LIBS)
+    SET(CMAKE_FIND_LIBRARY_SUFFIXES ${_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES} )
+ENDIF()
+
+IF(LibSolv_FOUND AND NOT LibSolv_FIND_QUIETLY)
+    MESSAGE(STATUS "Found LibSolv: ${LibSolv_INCLUDE_DIRS} ${LibSolv_LIBRARIES}")
+ENDIF()
diff --git a/libsolv-0.7.2/cmake/modules/FindPackageHandleStandardArgs.cmake b/libsolv-0.7.2/cmake/modules/FindPackageHandleStandardArgs.cmake
new file mode 100644 (file)
index 0000000..2fa8fbc
--- /dev/null
@@ -0,0 +1,316 @@
+# FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> ... )
+#
+# This function is intended to be used in FindXXX.cmake modules files.
+# It handles the REQUIRED, QUIET and version-related arguments to FIND_PACKAGE().
+# It also sets the <UPPERCASED_NAME>_FOUND variable.
+# The package is considered found if all variables <var1>... listed contain
+# valid results, e.g. valid filepaths.
+#
+# There are two modes of this function. The first argument in both modes is
+# the name of the Find-module where it is called (in original casing).
+#
+# The first simple mode looks like this:
+#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(<name> (DEFAULT_MSG|"Custom failure message") <var1>...<varN> )
+# If the variables <var1> to <varN> are all valid, then <UPPERCASED_NAME>_FOUND
+# will be set to TRUE.
+# If DEFAULT_MSG is given as second argument, then the function will generate
+# itself useful success and error messages. You can also supply a custom error message
+# for the failure case. This is not recommended.
+#
+# The second mode is more powerful and also supports version checking:
+#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME [REQUIRED_VARS <var1>...<varN>]
+#                                           [VERSION_VAR   <versionvar>]
+#                                           [HANDLE_COMPONENTS]
+#                                           [CONFIG_MODE]
+#                                           [FAIL_MESSAGE "Custom failure message"] )
+#
+# As above, if <var1> through <varN> are all valid, <UPPERCASED_NAME>_FOUND
+# will be set to TRUE.
+# After REQUIRED_VARS the variables which are required for this package are listed.
+# Following VERSION_VAR the name of the variable can be specified which holds
+# the version of the package which has been found. If this is done, this version
+# will be checked against the (potentially) specified required version used
+# in the find_package() call. The EXACT keyword is also handled. The default
+# messages include information about the required version and the version
+# which has been actually found, both if the version is ok or not.
+# If the package supports components, use the HANDLE_COMPONENTS option to enable
+# handling them. In this case, find_package_handle_standard_args() will report
+# which components have been found and which are missing, and the <NAME>_FOUND
+# variable will be set to FALSE if any of the required components (i.e. not the
+# ones listed after OPTIONAL_COMPONENTS) are missing.
+# Use the option CONFIG_MODE if your FindXXX.cmake module is a wrapper for
+# a find_package(... NO_MODULE) call.  In this case VERSION_VAR will be set
+# to <NAME>_VERSION and the macro will automatically check whether the
+# Config module was found.
+# Via FAIL_MESSAGE a custom failure message can be specified, if this is not
+# used, the default message will be displayed.
+#
+# Example for mode 1:
+#
+#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2  DEFAULT_MSG  LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
+#
+# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and
+# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE.
+# If it is not found and REQUIRED was used, it fails with FATAL_ERROR,
+# independent whether QUIET was used or not.
+# If it is found, success will be reported, including the content of <var1>.
+# On repeated Cmake runs, the same message won't be printed again.
+#
+# Example for mode 2:
+#
+#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(BISON  REQUIRED_VARS BISON_EXECUTABLE
+#                                             VERSION_VAR BISON_VERSION)
+# In this case, BISON is considered to be found if the variable(s) listed
+# after REQUIRED_VAR are all valid, i.e. BISON_EXECUTABLE in this case.
+# Also the version of BISON will be checked by using the version contained
+# in BISON_VERSION.
+# Since no FAIL_MESSAGE is given, the default messages will be printed.
+#
+# Another example for mode 2:
+#
+#    FIND_PACKAGE(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
+#    FIND_PACKAGE_HANDLE_STANDARD_ARGS(Automoc4  CONFIG_MODE)
+# In this case, FindAutmoc4.cmake wraps a call to FIND_PACKAGE(Automoc4 NO_MODULE)
+# and adds an additional search directory for automoc4.
+# The following FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper
+# success/error message.
+
+#=============================================================================
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+#   nor the names of their contributors may be used to endorse or promote
+#   products derived from this software without specific prior written
+#   permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+INCLUDE(FindPackageMessage)
+INCLUDE(_CMakeParseArguments)
+
+# internal helper macro
+MACRO(_FPHSA_FAILURE_MESSAGE _msg)
+  IF (${_NAME}_FIND_REQUIRED)
+    MESSAGE(FATAL_ERROR "${_msg}")
+  ELSE (${_NAME}_FIND_REQUIRED)
+    IF (NOT ${_NAME}_FIND_QUIETLY)
+      MESSAGE(STATUS "${_msg}")
+    ENDIF (NOT ${_NAME}_FIND_QUIETLY)
+  ENDIF (${_NAME}_FIND_REQUIRED)
+ENDMACRO(_FPHSA_FAILURE_MESSAGE _msg)
+
+
+# internal helper macro to generate the failure message when used in CONFIG_MODE:
+MACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
+  # <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
+  IF(${_NAME}_CONFIG)
+    _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
+  ELSE(${_NAME}_CONFIG)
+    # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
+    # List them all in the error message:
+    IF(${_NAME}_CONSIDERED_CONFIGS)
+      SET(configsText "")
+      LIST(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
+      MATH(EXPR configsCount "${configsCount} - 1")
+      FOREACH(currentConfigIndex RANGE ${configsCount})
+        LIST(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
+        LIST(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
+        SET(configsText "${configsText}    ${filename} (version ${version})\n")
+      ENDFOREACH(currentConfigIndex)
+      _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
+
+    ELSE(${_NAME}_CONSIDERED_CONFIGS)
+      # Simple case: No Config-file was found at all:
+      _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
+    ENDIF(${_NAME}_CONSIDERED_CONFIGS)
+  ENDIF(${_NAME}_CONFIG)
+ENDMACRO(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
+
+
+FUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
+
+# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
+# new extended or in the "old" mode:
+  SET(options CONFIG_MODE HANDLE_COMPONENTS)
+  SET(oneValueArgs FAIL_MESSAGE VERSION_VAR)
+  SET(multiValueArgs REQUIRED_VARS)
+  SET(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )
+  LIST(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
+
+  IF(${INDEX} EQUAL -1)
+    SET(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
+    SET(FPHSA_REQUIRED_VARS ${ARGN})
+    SET(FPHSA_VERSION_VAR)
+  ELSE(${INDEX} EQUAL -1)
+
+    CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${_FIRST_ARG} ${ARGN})
+
+    IF(FPHSA_UNPARSED_ARGUMENTS)
+      MESSAGE(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
+    ENDIF(FPHSA_UNPARSED_ARGUMENTS)
+
+    IF(NOT FPHSA_FAIL_MESSAGE)
+      SET(FPHSA_FAIL_MESSAGE  "DEFAULT_MSG")
+    ENDIF(NOT FPHSA_FAIL_MESSAGE)
+  ENDIF(${INDEX} EQUAL -1)
+
+# now that we collected all arguments, process them
+
+  IF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG")
+    SET(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
+  ENDIF("${FPHSA_FAIL_MESSAGE}" STREQUAL "DEFAULT_MSG")
+
+  # In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
+  # when it successfully found the config-file, including version checking:
+  IF(FPHSA_CONFIG_MODE)
+    LIST(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
+    LIST(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
+    SET(FPHSA_VERSION_VAR ${_NAME}_VERSION)
+  ENDIF(FPHSA_CONFIG_MODE)
+
+  IF(NOT FPHSA_REQUIRED_VARS)
+    MESSAGE(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
+  ENDIF(NOT FPHSA_REQUIRED_VARS)
+
+  LIST(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
+
+  STRING(TOUPPER ${_NAME} _NAME_UPPER)
+  STRING(TOLOWER ${_NAME} _NAME_LOWER)
+
+  # collect all variables which were not found, so they can be printed, so the
+  # user knows better what went wrong (#6375)
+  SET(MISSING_VARS "")
+  SET(DETAILS "")
+  SET(${_NAME_UPPER}_FOUND TRUE)
+  # check if all passed variables are valid
+  FOREACH(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
+    IF(NOT ${_CURRENT_VAR})
+      SET(${_NAME_UPPER}_FOUND FALSE)
+      SET(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
+    ELSE(NOT ${_CURRENT_VAR})
+      SET(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
+    ENDIF(NOT ${_CURRENT_VAR})
+  ENDFOREACH(_CURRENT_VAR)
+
+  # component handling
+  SET(FOUND_COMPONENTS_MSG "")
+  SET(MISSING_COMPONENTS_MSG "")
+
+  IF(FPHSA_HANDLE_COMPONENTS)
+    FOREACH(comp ${${_NAME}_FIND_COMPONENTS})
+      IF(${_NAME}_${comp}_FOUND)
+
+        IF(NOT FOUND_COMPONENTS_MSG)
+          SET(FOUND_COMPONENTS_MSG "found components: ")
+        ENDIF()
+        SET(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
+
+      ELSE()
+
+        IF(NOT MISSING_COMPONENTS_MSG)
+          SET(MISSING_COMPONENTS_MSG "missing components: ")
+        ENDIF()
+        SET(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
+
+        IF(${_NAME}_FIND_REQUIRED_${comp})
+          SET(${_NAME_UPPER}_FOUND FALSE)
+          SET(MISSING_VARS "${MISSING_VARS} ${comp}")
+        ENDIF()
+
+      ENDIF()
+    ENDFOREACH(comp)
+    SET(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
+    SET(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
+  ENDIF(FPHSA_HANDLE_COMPONENTS)
+
+  # version handling:
+  SET(VERSION_MSG "")
+  SET(VERSION_OK TRUE)
+  SET(VERSION ${${FPHSA_VERSION_VAR}} )
+  IF (${_NAME}_FIND_VERSION)
+
+    IF(VERSION)
+
+      IF(${_NAME}_FIND_VERSION_EXACT)       # exact version required
+        IF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
+          SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
+          SET(VERSION_OK FALSE)
+        ELSE (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
+          SET(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
+        ENDIF (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}")
+
+      ELSE(${_NAME}_FIND_VERSION_EXACT)     # minimum version specified:
+        IF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
+          SET(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
+          SET(VERSION_OK FALSE)
+        ELSE ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
+          SET(VERSION_MSG "(found suitable version \"${VERSION}\", required is \"${${_NAME}_FIND_VERSION}\")")
+        ENDIF ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}")
+      ENDIF(${_NAME}_FIND_VERSION_EXACT)
+
+    ELSE(VERSION)
+
+      # if the package was not found, but a version was given, add that to the output:
+      IF(${_NAME}_FIND_VERSION_EXACT)
+         SET(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
+      ELSE(${_NAME}_FIND_VERSION_EXACT)
+         SET(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
+      ENDIF(${_NAME}_FIND_VERSION_EXACT)
+
+    ENDIF(VERSION)
+  ELSE (${_NAME}_FIND_VERSION)
+    IF(VERSION)
+      SET(VERSION_MSG "(found version \"${VERSION}\")")
+    ENDIF(VERSION)
+  ENDIF (${_NAME}_FIND_VERSION)
+
+  IF(VERSION_OK)
+    SET(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
+  ELSE(VERSION_OK)
+    SET(${_NAME_UPPER}_FOUND FALSE)
+  ENDIF(VERSION_OK)
+
+
+  # print the result:
+  IF (${_NAME_UPPER}_FOUND)
+    FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
+  ELSE (${_NAME_UPPER}_FOUND)
+
+    IF(FPHSA_CONFIG_MODE)
+      _FPHSA_HANDLE_FAILURE_CONFIG_MODE()
+    ELSE(FPHSA_CONFIG_MODE)
+      IF(NOT VERSION_OK)
+        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
+      ELSE(NOT VERSION_OK)
+        _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
+      ENDIF(NOT VERSION_OK)
+    ENDIF(FPHSA_CONFIG_MODE)
+
+  ENDIF (${_NAME_UPPER}_FOUND)
+
+  SET(${_NAME_UPPER}_FOUND ${${_NAME_UPPER}_FOUND} PARENT_SCOPE)
+
+ENDFUNCTION(FIND_PACKAGE_HANDLE_STANDARD_ARGS _FIRST_ARG)
diff --git a/libsolv-0.7.2/cmake/modules/FindRuby.cmake b/libsolv-0.7.2/cmake/modules/FindRuby.cmake
new file mode 100644 (file)
index 0000000..827a7a6
--- /dev/null
@@ -0,0 +1,262 @@
+# - Find Ruby
+# This module finds if Ruby is installed and determines where the include files
+# and libraries are. Ruby 1.8 and 1.9 are supported.
+#
+# The minimum required version of Ruby can be specified using the
+# standard syntax, e.g. FIND_PACKAGE(Ruby 1.8)
+#
+# It also determines what the name of the library is. This
+# code sets the following variables:
+#
+#  RUBY_EXECUTABLE   = full path to the ruby binary
+#  RUBY_INCLUDE_DIRS = include dirs to be used when using the ruby library
+#  RUBY_LIBRARY      = full path to the ruby library
+#  RUBY_VERSION      = the version of ruby which was found, e.g. "1.8.7"
+#  RUBY_FOUND        = set to true if ruby ws found successfully
+#
+#  RUBY_INCLUDE_PATH = same as RUBY_INCLUDE_DIRS, only provided for compatibility reasons, don't use it
+
+#=============================================================================
+# Copyright 2004-2009 Kitware, Inc.
+# Copyright 2008-2009 Alexander Neundorf <neundorf@kde.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+#   nor the names of their contributors may be used to endorse or promote
+#   products derived from this software without specific prior written
+#   permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+#   RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'`
+#   RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'`
+#   RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'`
+#   RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'`
+#   RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'`
+
+# uncomment the following line to get debug output for this file
+# SET(_RUBY_DEBUG_OUTPUT TRUE)
+
+# Determine the list of possible names of the ruby executable depending
+# on which version of ruby is required
+SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ruby)
+
+# if 1.9 is required, don't look for ruby18 and ruby1.8, default to version 1.8
+IF(Ruby_FIND_VERSION_MAJOR  AND  Ruby_FIND_VERSION_MINOR)
+   SET(Ruby_FIND_VERSION_SHORT_NODOT "${Ruby_FIND_VERSION_MAJOR}${RUBY_FIND_VERSION_MINOR}")
+ELSE(Ruby_FIND_VERSION_MAJOR  AND  Ruby_FIND_VERSION_MINOR)
+   SET(Ruby_FIND_VERSION_SHORT_NODOT "18")
+ENDIF(Ruby_FIND_VERSION_MAJOR  AND  Ruby_FIND_VERSION_MINOR)
+
+SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES} ruby1.9 ruby19)
+
+# if we want a version below 1.9, also look for ruby 1.8
+IF("${Ruby_FIND_VERSION_SHORT_NODOT}" VERSION_LESS "19")
+   SET(_RUBY_POSSIBLE_EXECUTABLE_NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES} ruby1.8 ruby18)
+ENDIF("${Ruby_FIND_VERSION_SHORT_NODOT}" VERSION_LESS "19")
+
+FIND_PROGRAM(RUBY_EXECUTABLE NAMES ${_RUBY_POSSIBLE_EXECUTABLE_NAMES})
+
+
+IF(RUBY_EXECUTABLE  AND NOT  RUBY_VERSION_MAJOR)
+  FUNCTION(_RUBY_CONFIG_VAR RBVAR OUTVAR)
+    EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']"
+      RESULT_VARIABLE _RUBY_SUCCESS
+      OUTPUT_VARIABLE _RUBY_OUTPUT
+      ERROR_QUIET)
+    IF(_RUBY_SUCCESS OR NOT _RUBY_OUTPUT)
+      EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['${RBVAR}']"
+        RESULT_VARIABLE _RUBY_SUCCESS
+        OUTPUT_VARIABLE _RUBY_OUTPUT
+        ERROR_QUIET)
+    ENDIF(_RUBY_SUCCESS OR NOT _RUBY_OUTPUT)
+    SET(${OUTVAR} "${_RUBY_OUTPUT}" PARENT_SCOPE)
+  ENDFUNCTION(_RUBY_CONFIG_VAR)
+
+
+  # query the ruby version
+   _RUBY_CONFIG_VAR("MAJOR" RUBY_VERSION_MAJOR)
+   _RUBY_CONFIG_VAR("MINOR" RUBY_VERSION_MINOR)
+   _RUBY_CONFIG_VAR("TEENY" RUBY_VERSION_PATCH)
+
+   # query the different directories
+   _RUBY_CONFIG_VAR("archdir" RUBY_ARCH_DIR)
+   _RUBY_CONFIG_VAR("arch" RUBY_ARCH)
+   _RUBY_CONFIG_VAR("rubyhdrdir" RUBY_HDR_DIR)
+   _RUBY_CONFIG_VAR("libdir" RUBY_POSSIBLE_LIB_DIR)
+   _RUBY_CONFIG_VAR("rubylibdir" RUBY_RUBY_LIB_DIR)
+
+   # site_ruby
+   _RUBY_CONFIG_VAR("sitearchdir" RUBY_SITEARCH_DIR)
+   _RUBY_CONFIG_VAR("sitelibdir" RUBY_SITELIB_DIR)
+
+   # vendor_ruby available ?
+   EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print 'true' unless RbConfig::CONFIG['vendorarchdir'].nil?"
+      OUTPUT_VARIABLE RUBY_HAS_VENDOR_RUBY  ERROR_QUIET)
+
+   IF(RUBY_HAS_VENDOR_RUBY)
+      _RUBY_CONFIG_VAR("vendorlibdir" RUBY_VENDORLIB_DIR)
+      _RUBY_CONFIG_VAR("vendorarchdir" RUBY_VENDORARCH_DIR)
+   ENDIF(RUBY_HAS_VENDOR_RUBY)
+
+   # save the results in the cache so we don't have to run ruby the next time again
+   SET(RUBY_VERSION_MAJOR    ${RUBY_VERSION_MAJOR}    CACHE PATH "The Ruby major version" FORCE)
+   SET(RUBY_VERSION_MINOR    ${RUBY_VERSION_MINOR}    CACHE PATH "The Ruby minor version" FORCE)
+   SET(RUBY_VERSION_PATCH    ${RUBY_VERSION_PATCH}    CACHE PATH "The Ruby patch version" FORCE)
+   SET(RUBY_ARCH_DIR         ${RUBY_ARCH_DIR}         CACHE PATH "The Ruby arch dir" FORCE)
+   SET(RUBY_HDR_DIR          ${RUBY_HDR_DIR}          CACHE PATH "The Ruby header dir (1.9)" FORCE)
+   SET(RUBY_POSSIBLE_LIB_DIR ${RUBY_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE)
+   SET(RUBY_RUBY_LIB_DIR     ${RUBY_RUBY_LIB_DIR}     CACHE PATH "The Ruby ruby-lib dir" FORCE)
+   SET(RUBY_SITEARCH_DIR     ${RUBY_SITEARCH_DIR}     CACHE PATH "The Ruby site arch dir" FORCE)
+   SET(RUBY_SITELIB_DIR      ${RUBY_SITELIB_DIR}      CACHE PATH "The Ruby site lib dir" FORCE)
+   SET(RUBY_HAS_VENDOR_RUBY  ${RUBY_HAS_VENDOR_RUBY}  CACHE BOOL "Vendor Ruby is available" FORCE)
+   SET(RUBY_VENDORARCH_DIR   ${RUBY_VENDORARCH_DIR}   CACHE PATH "The Ruby vendor arch dir" FORCE)
+   SET(RUBY_VENDORLIB_DIR    ${RUBY_VENDORLIB_DIR}    CACHE PATH "The Ruby vendor lib dir" FORCE)
+
+   MARK_AS_ADVANCED(
+     RUBY_ARCH_DIR
+     RUBY_ARCH
+     RUBY_HDR_DIR
+     RUBY_POSSIBLE_LIB_DIR
+     RUBY_RUBY_LIB_DIR
+     RUBY_SITEARCH_DIR
+     RUBY_SITELIB_DIR
+     RUBY_HAS_VENDOR_RUBY
+     RUBY_VENDORARCH_DIR
+     RUBY_VENDORLIB_DIR
+     RUBY_VERSION_MAJOR
+     RUBY_VERSION_MINOR
+     RUBY_VERSION_PATCH
+     )
+ENDIF(RUBY_EXECUTABLE  AND NOT  RUBY_VERSION_MAJOR)
+
+# In case RUBY_EXECUTABLE could not be executed (e.g. cross compiling)
+# try to detect which version we found. This is not too good.
+IF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR)
+   # by default assume 1.8.0
+   SET(RUBY_VERSION_MAJOR 1)
+   SET(RUBY_VERSION_MINOR 8)
+   SET(RUBY_VERSION_PATCH 0)
+   # check whether we found 1.9.x
+   IF(${RUBY_EXECUTABLE} MATCHES "ruby1.?9"  OR  RUBY_HDR_DIR)
+      SET(RUBY_VERSION_MAJOR 1)
+      SET(RUBY_VERSION_MINOR 9)
+   ENDIF(${RUBY_EXECUTABLE} MATCHES "ruby1.?9"  OR  RUBY_HDR_DIR)
+ENDIF(RUBY_EXECUTABLE AND NOT RUBY_VERSION_MAJOR)
+
+IF(RUBY_VERSION_MAJOR)
+   SET(RUBY_VERSION "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}.${RUBY_VERSION_PATCH}")
+   SET(_RUBY_VERSION_SHORT "${RUBY_VERSION_MAJOR}.${RUBY_VERSION_MINOR}")
+   SET(_RUBY_VERSION_SHORT_NODOT "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}")
+   SET(_RUBY_NODOT_VERSION "${RUBY_VERSION_MAJOR}${RUBY_VERSION_MINOR}${RUBY_VERSION_PATCH}")
+ENDIF(RUBY_VERSION_MAJOR)
+
+FIND_PATH(RUBY_INCLUDE_DIR
+   NAMES ruby.h
+   HINTS
+   ${RUBY_HDR_DIR}
+   ${RUBY_ARCH_DIR}
+   /usr/lib/ruby/${_RUBY_VERSION_SHORT}/i586-linux-gnu/ )
+
+SET(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIR} )
+
+# if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir
+IF( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18  OR  "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18  OR  RUBY_HDR_DIR)
+   FIND_PATH(RUBY_CONFIG_INCLUDE_DIR
+     NAMES ruby/config.h  config.h
+     HINTS
+     ${RUBY_HDR_DIR}/${RUBY_ARCH}
+     ${RUBY_ARCH_DIR}
+     )
+
+   SET(RUBY_INCLUDE_DIRS ${RUBY_INCLUDE_DIRS} ${RUBY_CONFIG_INCLUDE_DIR} )
+ENDIF( "${Ruby_FIND_VERSION_SHORT_NODOT}" GREATER 18  OR  "${_RUBY_VERSION_SHORT_NODOT}" GREATER 18  OR  RUBY_HDR_DIR)
+
+
+# Determine the list of possible names for the ruby library
+SET(_RUBY_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_RUBY_VERSION_SHORT} ruby${_RUBY_VERSION_SHORT_NODOT} ruby-${_RUBY_VERSION_SHORT} ruby-${RUBY_VERSION})
+
+IF(WIN32)
+   SET( _RUBY_MSVC_RUNTIME "" )
+   IF( MSVC60 )
+     SET( _RUBY_MSVC_RUNTIME "60" )
+   ENDIF( MSVC60 )
+   IF( MSVC70 )
+     SET( _RUBY_MSVC_RUNTIME "70" )
+   ENDIF( MSVC70 )
+   IF( MSVC71 )
+     SET( _RUBY_MSVC_RUNTIME "71" )
+   ENDIF( MSVC71 )
+   IF( MSVC80 )
+     SET( _RUBY_MSVC_RUNTIME "80" )
+   ENDIF( MSVC80 )
+   IF( MSVC90 )
+     SET( _RUBY_MSVC_RUNTIME "90" )
+   ENDIF( MSVC90 )
+
+   LIST(APPEND _RUBY_POSSIBLE_LIB_NAMES
+               "msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}"
+               "msvcr${_RUBY_MSVC_RUNTIME}-ruby${_RUBY_NODOT_VERSION}-static"
+               "msvcrt-ruby${_RUBY_NODOT_VERSION}"
+               "msvcrt-ruby${_RUBY_NODOT_VERSION}-static" )
+ENDIF(WIN32)
+
+FIND_LIBRARY(RUBY_LIBRARY NAMES ${_RUBY_POSSIBLE_LIB_NAMES} HINTS ${RUBY_POSSIBLE_LIB_DIR} )
+
+INCLUDE(FindPackageHandleStandardArgs)
+SET(_RUBY_REQUIRED_VARS RUBY_EXECUTABLE RUBY_INCLUDE_DIR RUBY_LIBRARY)
+IF(_RUBY_VERSION_SHORT_NODOT GREATER 18)
+   LIST(APPEND _RUBY_REQUIRED_VARS RUBY_CONFIG_INCLUDE_DIR)
+ENDIF(_RUBY_VERSION_SHORT_NODOT GREATER 18)
+
+IF(_RUBY_DEBUG_OUTPUT)
+   MESSAGE(STATUS "--------FindRuby.cmake debug------------")
+   MESSAGE(STATUS "_RUBY_POSSIBLE_EXECUTABLE_NAMES: ${_RUBY_POSSIBLE_EXECUTABLE_NAMES}")
+   MESSAGE(STATUS "_RUBY_POSSIBLE_LIB_NAMES: ${_RUBY_POSSIBLE_LIB_NAMES}")
+   MESSAGE(STATUS "RUBY_ARCH_DIR: ${RUBY_ARCH_DIR}")
+   MESSAGE(STATUS "RUBY_HDR_DIR: ${RUBY_HDR_DIR}")
+   MESSAGE(STATUS "RUBY_POSSIBLE_LIB_DIR: ${RUBY_POSSIBLE_LIB_DIR}")
+   MESSAGE(STATUS "Found RUBY_VERSION: \"${RUBY_VERSION}\" , short: \"${_RUBY_VERSION_SHORT}\", nodot: \"${_RUBY_VERSION_SHORT_NODOT}\"")
+   MESSAGE(STATUS "_RUBY_REQUIRED_VARS: ${_RUBY_REQUIRED_VARS}")
+   MESSAGE(STATUS "RUBY_EXECUTABLE: ${RUBY_EXECUTABLE}")
+   MESSAGE(STATUS "RUBY_LIBRARY: ${RUBY_LIBRARY}")
+   MESSAGE(STATUS "RUBY_INCLUDE_DIR: ${RUBY_INCLUDE_DIR}")
+   MESSAGE(STATUS "RUBY_CONFIG_INCLUDE_DIR: ${RUBY_CONFIG_INCLUDE_DIR}")
+   MESSAGE(STATUS "--------------------")
+ENDIF(_RUBY_DEBUG_OUTPUT)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ruby  REQUIRED_VARS  ${_RUBY_REQUIRED_VARS}
+                                        VERSION_VAR RUBY_VERSION )
+
+MARK_AS_ADVANCED(
+  RUBY_EXECUTABLE
+  RUBY_LIBRARY
+  RUBY_INCLUDE_DIR
+  RUBY_CONFIG_INCLUDE_DIR
+  )
+
+# Set some variables for compatibility with previous version of this file
+SET(RUBY_POSSIBLE_LIB_PATH ${RUBY_POSSIBLE_LIB_DIR})
+SET(RUBY_RUBY_LIB_PATH ${RUBY_RUBY_LIB_DIR})
+SET(RUBY_INCLUDE_PATH ${RUBY_INCLUDE_DIRS})
diff --git a/libsolv-0.7.2/cmake/modules/_CMakeParseArguments.cmake b/libsolv-0.7.2/cmake/modules/_CMakeParseArguments.cmake
new file mode 100644 (file)
index 0000000..7122094
--- /dev/null
@@ -0,0 +1,160 @@
+# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
+#
+# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for
+# parsing the arguments given to that macro or function.
+# It processes the arguments and defines a set of variables which hold the
+# values of the respective options.
+#
+# The <options> argument contains all options for the respective macro,
+# i.e. keywords which can be used when calling the macro without any value
+# following, like e.g. the OPTIONAL keyword of the install() command.
+#
+# The <one_value_keywords> argument contains all keywords for this macro
+# which are followed by one value, like e.g. DESTINATION keyword of the
+# install() command.
+#
+# The <multi_value_keywords> argument contains all keywords for this macro
+# which can be followed by more than one value, like e.g. the TARGETS or
+# FILES keywords of the install() command.
+#
+# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
+# keywords listed in <options>, <one_value_keywords> and
+# <multi_value_keywords> a variable composed of the given <prefix>
+# followed by "_" and the name of the respective keyword.
+# These variables will then hold the respective value from the argument list.
+# For the <options> keywords this will be TRUE or FALSE.
+#
+# All remaining arguments are collected in a variable
+# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see whether
+# your macro was called with unrecognized parameters.
+#
+# As an example here a my_install() macro, which takes similar arguments as the
+# real install() command:
+#
+#   function(MY_INSTALL)
+#     set(options OPTIONAL FAST)
+#     set(oneValueArgs DESTINATION RENAME)
+#     set(multiValueArgs TARGETS CONFIGURATIONS)
+#     cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+#     ...
+#
+# Assume my_install() has been called like this:
+#   my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
+#
+# After the cmake_parse_arguments() call the macro will have set the following
+# variables:
+#   MY_INSTALL_OPTIONAL = TRUE
+#   MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
+#   MY_INSTALL_DESTINATION = "bin"
+#   MY_INSTALL_RENAME = "" (was not used)
+#   MY_INSTALL_TARGETS = "foo;bar"
+#   MY_INSTALL_CONFIGURATIONS = "" (was not used)
+#   MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
+#
+# You can the continue and process these variables.
+#
+# Keywords terminate lists of values, e.g. if directly after a one_value_keyword
+# another recognized keyword follows, this is interpreted as the beginning of
+# the new option.
+# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
+# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
+# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
+
+#=============================================================================
+# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
+#
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+#
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+#   nor the names of their contributors may be used to endorse or promote
+#   products derived from this software without specific prior written
+#   permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+
+if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
+  return()
+endif()
+set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
+
+
+function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
+  # first set all result variables to empty/FALSE
+  foreach(arg_name ${_singleArgNames} ${_multiArgNames})
+    set(${prefix}_${arg_name})
+  endforeach(arg_name)
+
+  foreach(option ${_optionNames})
+    set(${prefix}_${option} FALSE)
+  endforeach(option)
+
+  set(${prefix}_UNPARSED_ARGUMENTS)
+
+  set(insideValues FALSE)
+  set(currentArgName)
+
+  # now iterate over all arguments and fill the result variables
+  foreach(currentArg ${ARGN})
+    list(FIND _optionNames "${currentArg}" optionIndex)  # ... then this marks the end of the arguments belonging to this keyword
+    list(FIND _singleArgNames "${currentArg}" singleArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
+    list(FIND _multiArgNames "${currentArg}" multiArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
+
+    if(${optionIndex} EQUAL -1  AND  ${singleArgIndex} EQUAL -1  AND  ${multiArgIndex} EQUAL -1)
+      if(insideValues)
+        if("${insideValues}" STREQUAL "SINGLE")
+          set(${prefix}_${currentArgName} ${currentArg})
+          set(insideValues FALSE)
+        elseif("${insideValues}" STREQUAL "MULTI")
+          list(APPEND ${prefix}_${currentArgName} ${currentArg})
+        endif()
+      else(insideValues)
+        list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
+      endif(insideValues)
+    else()
+      if(NOT ${optionIndex} EQUAL -1)
+        set(${prefix}_${currentArg} TRUE)
+        set(insideValues FALSE)
+      elseif(NOT ${singleArgIndex} EQUAL -1)
+        set(currentArgName ${currentArg})
+        set(${prefix}_${currentArgName})
+        set(insideValues "SINGLE")
+      elseif(NOT ${multiArgIndex} EQUAL -1)
+        set(currentArgName ${currentArg})
+        set(${prefix}_${currentArgName})
+        set(insideValues "MULTI")
+      endif()
+    endif()
+
+  endforeach(currentArg)
+
+  # propagate the result variables to the caller:
+  foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
+    set(${prefix}_${arg_name}  ${${prefix}_${arg_name}} PARENT_SCOPE)
+  endforeach(arg_name)
+  set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
+
+endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
diff --git a/libsolv-0.7.2/doc/CMakeLists.txt b/libsolv-0.7.2/doc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..66011b4
--- /dev/null
@@ -0,0 +1,55 @@
+
+SET (libsolv_MANPAGES3
+    libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3
+    libsolv-pool.3)
+
+SET (libsolv_MANPAGES1
+    mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 repo2solv.1 solv.1)
+
+IF (ENABLE_RPMDB)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} rpmdb2solv.1 rpms2solv.1)
+ENDIF (ENABLE_RPMDB)
+
+IF (ENABLE_RPMMD)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} repomdxml2solv.1 rpmmd2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1)
+ENDIF (ENABLE_RPMMD)
+
+IF (ENABLE_HELIXREPO)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} helix2solv.1)
+ENDIF (ENABLE_HELIXREPO)
+
+IF (ENABLE_SUSEREPO)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} susetags2solv.1)
+ENDIF (ENABLE_SUSEREPO)
+
+IF (ENABLE_COMPS)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} comps2solv.1)
+ENDIF (ENABLE_COMPS)
+
+IF (ENABLE_DEBIAN)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} deb2solv.1)
+ENDIF (ENABLE_DEBIAN)
+
+IF (ENABLE_MDKREPO)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} mdk2solv.1)
+ENDIF (ENABLE_MDKREPO)
+
+IF (ENABLE_ARCHREPO)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} archpkgs2solv.1 archrepo2solv.1)
+ENDIF (ENABLE_ARCHREPO)
+
+IF (ENABLE_APPDATA)
+SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} appdata2solv.1)
+ENDIF (ENABLE_APPDATA)
+
+# prepend gen directory
+STRING(REGEX REPLACE "([^;]+)" "gen/\\1" libsolv_MANPAGES1 "${libsolv_MANPAGES1}")
+STRING(REGEX REPLACE "([^;]+)" "gen/\\1" libsolv_MANPAGES3 "${libsolv_MANPAGES3}")
+
+INSTALL(FILES
+    ${libsolv_MANPAGES3}
+    DESTINATION "${MAN_INSTALL_DIR}/man3")
+
+INSTALL(FILES
+    ${libsolv_MANPAGES1}
+    DESTINATION "${MAN_INSTALL_DIR}/man1")
diff --git a/libsolv-0.7.2/doc/Makefile.gen b/libsolv-0.7.2/doc/Makefile.gen
new file mode 100644 (file)
index 0000000..e9f1b69
--- /dev/null
@@ -0,0 +1,24 @@
+
+VPATH = gen
+
+man:   man3 man1
+
+man3:  libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 libsolv-pool.3
+
+man1:  mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 rpmdb2solv.1 rpms2solv.1 \
+       rpmmd2solv.1 repomdxml2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1 \
+       helix2solv.1 susetags2solv.1 comps2solv.1 deb2solv.1 mdk2solv.1 \
+       archpkgs2solv.1 archrepo2solv.1 appdata2solv.1 repo2solv.1 solv.1
+
+html: libsolv.html libsolv-bindings.html libsolv-constantids.html libsolv-history.html libsolv-pool.html
+
+.SUFFIXES: .html .3 .1 .txt
+
+.txt.1:
+       a2x -f manpage -D gen $<
+
+.txt.3:
+       a2x -f manpage -D gen $<
+
+.txt.html:
+       a2x -f xhtml -D gen $<
diff --git a/libsolv-0.7.2/doc/appdata2solv.txt b/libsolv-0.7.2/doc/appdata2solv.txt
new file mode 100644 (file)
index 0000000..c31311a
--- /dev/null
@@ -0,0 +1,43 @@
+appdata2solv(1)
+===============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+appdata2solv - convert application meta data into a solv file
+
+Synopsis
+--------
+*appdata2solv* ['OPTIONS']
+
+Description
+-----------
+The appdata format contains metadata about application. It can
+be available both in repositories (for available applications)
+and in the installed system (for installed applications).
+The appdata2solv tool reads the metadata from stdin and
+writes the parsed data as solv file to standard output. The
+parser will create *application:* pseudo packages for each entry.
+
+*-d* 'APPDATADIR'::
+Do not read from standard input, instead scan the specified
+directory for appdata entries. 'APPDATADIR' is normally
+set to */usr/share/appdata*.
+
+*-r* 'ROOTDIR'::
+Use 'ROOTDIR' as root directory.
+
+
+See Also
+--------
+mergesolv(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/archpkgs2solv.txt b/libsolv-0.7.2/doc/archpkgs2solv.txt
new file mode 100644 (file)
index 0000000..4ce3155
--- /dev/null
@@ -0,0 +1,39 @@
+archpkgs2solv(1)
+================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+archpkgs2solv - convert one or more Arch package files into a solv file
+
+Synopsis
+--------
+*archpkgs2solv* ['OPTIONS'] 'PKG1.pkg.xz' ...
+
+Description
+-----------
+The archpkgs2solv tool converts the meta data from one or more
+Arch Linux packages into the solv file written to standard output.
+
+*-m* 'MANIFESTFILE'::
+Read the rpm file names from the specified 'MANIFESTFILE'. You can
+use *-* to read the manifest from standard input.
+
+*-0*::
+Use a null byte as line terminator for manifest files instead of
+a newline. This is useful if the file names can contain newlines.
+See also the *-print0* option in *find*.
+
+See Also
+--------
+pacman(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/archrepo2solv.txt b/libsolv-0.7.2/doc/archrepo2solv.txt
new file mode 100644 (file)
index 0000000..1a7791c
--- /dev/null
@@ -0,0 +1,35 @@
+archrepo2solv(1)
+================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+archrepo2solv - convert files in Arch repository format into a solv file
+
+Synopsis
+--------
+*archrepo2solv* ['OPTIONS']
+
+Description
+-----------
+The archrepo2solv tool reads Arch Linux repository data (*core.db*) from stdin,
+and writes it as solv file to standard output.
+
+*-l* 'DATABASEDIR'::
+Instead of reading from standard input, scan the specified directory for
+package meta files. Set 'DATABASEDIR' to */var/lib/pacman/local* to
+scan the installed packages.
+
+See Also
+--------
+pacman(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/comps2solv.txt b/libsolv-0.7.2/doc/comps2solv.txt
new file mode 100644 (file)
index 0000000..8d98708
--- /dev/null
@@ -0,0 +1,33 @@
+comps2solv(1)
+=============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+comps2solv - convert rpm-md comps.xml file into a solv file
+
+Synopsis
+--------
+*comps2solv* ['OPTIONS']
+
+Description
+-----------
+The comps.xml file is Fedora's way to implement package groups.
+The comps2solv tool reads the comps xml file from stdin and
+writes the parsed data as solv file to standard output. The
+parser will create *group:* and *category:* pseudo packages
+for each comps entry.
+
+See Also
+--------
+mergesolv(1), createrepo(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/deb2solv.txt b/libsolv-0.7.2/doc/deb2solv.txt
new file mode 100644 (file)
index 0000000..cb42ff7
--- /dev/null
@@ -0,0 +1,39 @@
+deb2solv(1)
+============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+deb2solv - convert one or more Debian package files into a solv file
+
+Synopsis
+--------
+*deb2solv* ['OPTIONS'] 'PKG1.deb' ...
+
+Description
+-----------
+The deb2solv tool converts the meta data from one or more
+Debian packages into the solv file written to standard output.
+
+*-m* 'MANIFESTFILE'::
+Read the rpm file names from the specified 'MANIFESTFILE'. You can
+use *-* to read the manifest from standard input.
+
+*-0*::
+Use a null byte as line terminator for manifest files instead of
+a newline. This is useful if the file names can contain newlines.
+See also the *-print0* option in *find*.
+
+See Also
+--------
+deb(5), dpkg-deb(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/deltainfoxml2solv.txt b/libsolv-0.7.2/doc/deltainfoxml2solv.txt
new file mode 100644 (file)
index 0000000..13c987d
--- /dev/null
@@ -0,0 +1,33 @@
+deltainfoxml2solv(1)
+====================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+deltainfoxml2solv - convert rpm-md's deltainfo format into a solv file
+
+Synopsis
+--------
+*deltainfoxml2solv* ['OPTIONS']
+
+Description
+-----------
+The deltainfoxml2solv tool reads rpm-md's *deltainfo.xml* data from stdin,
+and writes it as solv file to standard output. Some distributions name
+the input *prestodelta.xml* instead. Each delta rpm element is converted
+and added as *repository:deltainfo* element to the meta section of the
+solv file.
+
+See Also
+--------
+mergesolv(1), createrepo(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/dumpsolv.txt b/libsolv-0.7.2/doc/dumpsolv.txt
new file mode 100644 (file)
index 0000000..b09aa97
--- /dev/null
@@ -0,0 +1,30 @@
+dumpsolv(1)
+===========
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+dumpsolv - print a solv file into a human readable format
+
+Synopsis
+--------
+*dumpsolv* ['OPTIONS'] ['FILE.solv']
+
+Description
+-----------
+The dumpsolv tool reads a solv files and writes its contents
+to standard output. If no input file is given, it reads the
+solv file from standard input.
+
+*-j*::
+Write the contents in JSON format.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/filters/xcode.conf b/libsolv-0.7.2/doc/filters/xcode.conf
new file mode 100644 (file)
index 0000000..294f908
--- /dev/null
@@ -0,0 +1,12 @@
+[blockdef-listing]
+xcode-style=template="verseblock",presubs=(),postsubs=("callouts",),filter="filters/xcode.pl {basebackend}"
+
+[paradef-xcode]
+delimiter=(?s)^(?P<text>\s+.*)
+template=verseblock
+subs=verbatim
+filter=filters/xcode.pl {basebackend}
+
+[paradef-literal]
+delimiter=(?s)^(?P<text>\s{1,7}\S.*)
+
diff --git a/libsolv-0.7.2/doc/filters/xcode.pl b/libsolv-0.7.2/doc/filters/xcode.pl
new file mode 100755 (executable)
index 0000000..407641f
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/perl
+
+die("I only understand docbook\n") unless @ARGV && $ARGV[0] eq 'docbook';
+
+#my $ii = '//';
+#my $io = '//';
+
+#my $si = '**';
+#my $so = '**';
+
+my $ii = '<emphasis>';
+my $io = '</emphasis>';
+
+my $si = '<emphasis role="strong">';
+my $so = '</emphasis>';
+
+while(<STDIN>) {
+  chomp;
+  my $in = '';
+  my $out = '';
+  s/^\s+//;
+  s/\s+$//;
+  if (/^(.*)(\s*\/\*.*?\*\/\s*?)$/) {
+    $out = $2;
+    $_ = $1;
+  }
+  if (/^(my\s+)(.*?)$/) {
+    $in = $1;
+    $_ = $2;
+  }
+  if (/(?<!\&gt);$/) {
+    $out = ";$out";
+    chop $_;
+  }
+  if (!/^[a-zA-Z0-9_]+$/) {
+    $_ = " $_";
+    $_ = "$_ ";
+    if (s/^ TCL +/ /) {
+      s/(\$[a-zA-Z_][a-zA-Z0-9_:]*)/<-S><I>$1<-I><S>/g;
+    } else {
+      s/(?<=[^a-zA-Z_\&:\.\'\";])(?!solv\W|Solv\W|Pool\W)([\$\@a-zA-Z_][a-zA-Z0-9_]*)(?=[^a-zA-Z0-9_\(;\[])(?!::)(?! [^=])/<-S><I>$1<-I><S>/g;
+    }
+    # fixup for perl bare words
+    s/{<-S><I>([a-zA-Z_][a-zA-Z0-9]*)<-I><S>}/{$1}/g;
+    # fixup for callbackfunctions
+    s/\\(&amp;[a-zA-Z_]+)/\\<-S><I>$1<-I><S>/;
+    # fixup for stringification
+    s/\$<-S><I>/<-S><I>\$/g;
+    # fixup for %d
+    s/%<-S><I>d<-I><S>\"/%d\"/;
+    s/%<-S><I>d<-I><S>\\<-S><I>n<-I><S>/%d\\n/;
+    # iterators
+    s/^ //;
+    s/ $//;
+    s/^(for (?:my )?)(\S+) /$1<-S><I>$2<-I><S> /;
+  }
+  $_ = "<S>$_<-S>";
+  s/<S>(\s*)<-S>/$1/g;
+  s/<-S>(\s*)<S>/$1/g;
+  s/<I>(\s*)<-I>/$1/g;
+  s/<-I>(\s*)<I>/$1/g;
+  s/<S>(\s+)/$1<S>/g;
+  s/(\s+)<-S>/<-S>$1/g;
+  s/<I>(\s+)/$1<I>/g;
+  s/(\s+)<-I>/<-I>$1/g;
+  s/<S>/$si/g;
+  s/<-S>/$so/g;
+  s/<I>/$ii/g;
+  s/<-I>/$io/g;
+  print "$in$_$out\n";
+}
diff --git a/libsolv-0.7.2/doc/gen/appdata2solv.1 b/libsolv-0.7.2/doc/gen/appdata2solv.1
new file mode 100644 (file)
index 0000000..4fe217d
--- /dev/null
@@ -0,0 +1,58 @@
+'\" t
+.\"     Title: appdata2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "APPDATA2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+appdata2solv \- convert application meta data into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBappdata2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The appdata format contains metadata about application\&. It can be available both in repositories (for available applications) and in the installed system (for installed applications)\&. The appdata2solv tool reads the metadata from stdin and writes the parsed data as solv file to standard output\&. The parser will create \fBapplication:\fR pseudo packages for each entry\&.
+.PP
+\fB\-d\fR \fIAPPDATADIR\fR
+.RS 4
+Do not read from standard input, instead scan the specified directory for appdata entries\&.
+\fIAPPDATADIR\fR
+is normally set to
+\fB/usr/share/appdata\fR\&.
+.RE
+.PP
+\fB\-r\fR \fIROOTDIR\fR
+.RS 4
+Use
+\fIROOTDIR\fR
+as root directory\&.
+.RE
+.SH "SEE ALSO"
+.sp
+mergesolv(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/archpkgs2solv.1 b/libsolv-0.7.2/doc/gen/archpkgs2solv.1
new file mode 100644 (file)
index 0000000..bb47364
--- /dev/null
@@ -0,0 +1,59 @@
+'\" t
+.\"     Title: archpkgs2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "ARCHPKGS2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+archpkgs2solv \- convert one or more Arch package files into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBarchpkgs2solv\fR [\fIOPTIONS\fR] \fIPKG1\&.pkg\&.xz\fR \&...
+.SH "DESCRIPTION"
+.sp
+The archpkgs2solv tool converts the meta data from one or more Arch Linux packages into the solv file written to standard output\&.
+.PP
+\fB\-m\fR \fIMANIFESTFILE\fR
+.RS 4
+Read the rpm file names from the specified
+\fIMANIFESTFILE\fR\&. You can use
+\fB\-\fR
+to read the manifest from standard input\&.
+.RE
+.PP
+\fB\-0\fR
+.RS 4
+Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the
+\fB\-print0\fR
+option in
+\fBfind\fR\&.
+.RE
+.SH "SEE ALSO"
+.sp
+pacman(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/archrepo2solv.1 b/libsolv-0.7.2/doc/gen/archrepo2solv.1
new file mode 100644 (file)
index 0000000..9d7c868
--- /dev/null
@@ -0,0 +1,52 @@
+'\" t
+.\"     Title: archrepo2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "ARCHREPO2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+archrepo2solv \- convert files in Arch repository format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBarchrepo2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The archrepo2solv tool reads Arch Linux repository data (\fBcore\&.db\fR) from stdin, and writes it as solv file to standard output\&.
+.PP
+\fB\-l\fR \fIDATABASEDIR\fR
+.RS 4
+Instead of reading from standard input, scan the specified directory for package meta files\&. Set
+\fIDATABASEDIR\fR
+to
+\fB/var/lib/pacman/local\fR
+to scan the installed packages\&.
+.RE
+.SH "SEE ALSO"
+.sp
+pacman(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/comps2solv.1 b/libsolv-0.7.2/doc/gen/comps2solv.1
new file mode 100644 (file)
index 0000000..2be0bc9
--- /dev/null
@@ -0,0 +1,43 @@
+'\" t
+.\"     Title: comps2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "COMPS2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+comps2solv \- convert rpm\-md comps\&.xml file into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBcomps2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The comps\&.xml file is Fedora\(cqs way to implement package groups\&. The comps2solv tool reads the comps xml file from stdin and writes the parsed data as solv file to standard output\&. The parser will create \fBgroup:\fR and \fBcategory:\fR pseudo packages for each comps entry\&.
+.SH "SEE ALSO"
+.sp
+mergesolv(1), createrepo(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/deb2solv.1 b/libsolv-0.7.2/doc/gen/deb2solv.1
new file mode 100644 (file)
index 0000000..7da3828
--- /dev/null
@@ -0,0 +1,59 @@
+'\" t
+.\"     Title: deb2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "DEB2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+deb2solv \- convert one or more Debian package files into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBdeb2solv\fR [\fIOPTIONS\fR] \fIPKG1\&.deb\fR \&...
+.SH "DESCRIPTION"
+.sp
+The deb2solv tool converts the meta data from one or more Debian packages into the solv file written to standard output\&.
+.PP
+\fB\-m\fR \fIMANIFESTFILE\fR
+.RS 4
+Read the rpm file names from the specified
+\fIMANIFESTFILE\fR\&. You can use
+\fB\-\fR
+to read the manifest from standard input\&.
+.RE
+.PP
+\fB\-0\fR
+.RS 4
+Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the
+\fB\-print0\fR
+option in
+\fBfind\fR\&.
+.RE
+.SH "SEE ALSO"
+.sp
+deb(5), dpkg\-deb(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/deltainfoxml2solv.1 b/libsolv-0.7.2/doc/gen/deltainfoxml2solv.1
new file mode 100644 (file)
index 0000000..0ef0bb4
--- /dev/null
@@ -0,0 +1,43 @@
+'\" t
+.\"     Title: deltainfoxml2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "DELTAINFOXML2SOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+deltainfoxml2solv \- convert rpm\-md\*(Aqs deltainfo format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBdeltainfoxml2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The deltainfoxml2solv tool reads rpm\-md\(cqs \fBdeltainfo\&.xml\fR data from stdin, and writes it as solv file to standard output\&. Some distributions name the input \fBprestodelta\&.xml\fR instead\&. Each delta rpm element is converted and added as \fBrepository:deltainfo\fR element to the meta section of the solv file\&.
+.SH "SEE ALSO"
+.sp
+mergesolv(1), createrepo(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/dumpsolv.1 b/libsolv-0.7.2/doc/gen/dumpsolv.1
new file mode 100644 (file)
index 0000000..eed45fe
--- /dev/null
@@ -0,0 +1,45 @@
+'\" t
+.\"     Title: dumpsolv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2017
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "DUMPSOLV" "1" "07/25/2017" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+dumpsolv \- print a solv file into a human readable format
+.SH "SYNOPSIS"
+.sp
+\fBdumpsolv\fR [\fIOPTIONS\fR] [\fIFILE\&.solv\fR]
+.SH "DESCRIPTION"
+.sp
+The dumpsolv tool reads a solv files and writes its contents to standard output\&. If no input file is given, it reads the solv file from standard input\&.
+.PP
+\fB\-j\fR
+.RS 4
+Write the contents in JSON format\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/helix2solv.1 b/libsolv-0.7.2/doc/gen/helix2solv.1
new file mode 100644 (file)
index 0000000..1f37339
--- /dev/null
@@ -0,0 +1,40 @@
+'\" t
+.\"     Title: helix2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "HELIX2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+helix2solv \- convert legacy helixcode format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBhelix2solv\fR
+.SH "DESCRIPTION"
+.sp
+The helix format was a metadata format used in the RedCarpet package manager\&. It\(cqs still used in libzypp testcases\&. The helix2solv tool reads data in helix format from standard input and writes it in solv file format to standard output\&.
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/installcheck.1 b/libsolv-0.7.2/doc/gen/installcheck.1
new file mode 100644 (file)
index 0000000..492bd80
--- /dev/null
@@ -0,0 +1,42 @@
+'\" t
+.\"     Title: installcheck
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "INSTALLCHECK" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+installcheck \- find out which packages cannot be installed
+.SH "SYNOPSIS"
+.sp
+\fBinstallcheck\fR \fIARCH\fR \fIREPO1\fR \fIREPO2\fR\&... \fB\-\-nocheck\fR \fINREPO1\fR \fINREPO2\fR\&...
+.SH "DESCRIPTION"
+.sp
+The installcheck tool checks if all packages in \fIREPO1\fR\&...\fIREPON\fR are installable\&. A package is installable if there is a set of packages from the repositories that satisfies its dependencies\&. The repositories after the \fB\-\-nocheck\fR option are only used for dependency resolving, but the tool does not check if the packages in them are installable\&.
+.sp
+A Repository can be a solv file, a rpmmd \fBprimary\&.xml\&.gz\fR file, a SUSE \fBpackages\fR or \fBpackages\&.gz\fR file, or a Debian \fBPackages\fR or \fBPackages\&.gz\fR file\&.
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/libsolv-bindings.3 b/libsolv-0.7.2/doc/gen/libsolv-bindings.3
new file mode 100644 (file)
index 0000000..9f84c77
--- /dev/null
@@ -0,0 +1,6138 @@
+'\" t
+.\"     Title: Libsolv-Bindings
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 12/06/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "LIBSOLV\-BINDINGS" "3" "12/06/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libsolv-bindings \- access libsolv from perl/python/ruby
+.SH "DESCRIPTION"
+.sp
+Libsolv\(cqs language bindings offer an abstract, object orientated interface to the library\&. The supported languages are currently perl, python, and ruby\&. All example code (except in the specifics sections, of course) lists first the \(lqC\-ish\(rq interface, then the syntax for perl, python, and ruby (in that order)\&.
+.SH "PERL SPECIFICS"
+.sp
+Libsolv\(cqs perl bindings can be loaded with the following statement:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBuse solv\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Objects are either created by calling the new() method on a class or they are returned by calling methods on other objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+my \fI$pool\fR \fB= solv::Pool\->new()\fR;
+my \fI$repo\fR \fB=\fR \fI$pool\fR\fB\->add_repo("my_first_repo")\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Swig encapsulates all objects as tied hashes, thus the attributes can be accessed by treating the object as standard hash reference:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fI$pool\fR\fB\->{appdata} = 42\fR;
+\fBprintf "appdata is %d\en",\fR \fI$pool\fR\fB\->{appdata}\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A special exception to this are iterator objects, they are encapsulated as tied arrays so that it is possible to iterate with a for() statement:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+my \fI$iter\fR \fB=\fR \fI$pool\fR\fB\->solvables_iter()\fR;
+\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@$iter\fR\fB) { \&.\&.\&. }\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+As a downside of this approach, iterator objects cannot have attributes\&.
+.sp
+If an array needs to be passed to a method it is usually done by reference, if a method returns an array it returns it on the perl stack:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+my \fI@problems\fR \fB=\fR \fI$solver\fR\fB\->solve(\e\fR\fI@jobs\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Due to a bug in swig, stringification does not work for libsolv\(cqs objects\&. Instead, you have to call the object\(cqs str() method\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBprint\fR \fI$dep\fR\fB\->str() \&. "\e\fR\fIn\fR\fB"\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Swig implements all constants as numeric variables (instead of the more natural constant subs), so don\(cqt forget the leading \(lq$\(rq when accessing a constant\&. Also do not forget to prepend the namespace of the constant:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fI$pool\fR\fB\->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.SH "PYTHON SPECIFICS"
+.sp
+The python bindings can be loaded with:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBimport solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Objects are either created by calling the constructor method for a class or they are returned by calling methods on other objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpool\fR \fB= solv\&.Pool()\fR
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo("my_first_repo")\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Attributes can be accessed as usual:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpool\fR\fB\&.appdata = 42\fR
+\fBprint "appdata is %d" % (\fR\fIpool\fR\fB\&.appdata)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterators also work as expected:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter():\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Arrays are passed and returned as list objects:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIjobs\fR \fB= []\fR
+\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The bindings define stringification for many classes, some also have a \fIrepr\fR method to ease debugging\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBprint\fR \fIdep\fR
+\fBprint repr(\fR\fIrepo\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Constants are attributes of the corresponding classes:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpool\fR\fB\&.set_flag(solv\&.Pool\&.POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.SH "RUBY SPECIFICS"
+.sp
+The ruby bindings can be loaded with:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBrequire \*(Aqsolv\*(Aq\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Objects are either created by calling the new method on a class or they are returned by calling methods on other objects\&. Note that all classes start with an uppercase letter in ruby, so the class is called \(lqSolv\(rq\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpool\fR \fB= Solv::Pool\&.new\fR
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo("my_first_repo")\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Attributes can be accessed as usual:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpool\fR\fB\&.appdata = 42\fR
+\fBputs "appdata is #{\fR\fIpool\fR\fB\&.appdata}"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterators also work as expected:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter() do \&.\&.\&.\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Arrays are passed and returned as array objects:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIjobs\fR \fB= []\fR
+\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Most classes define a to_s method, so objects can be easily stringified\&. Many also define an inspect() method\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBputs\fR \fIdep\fR
+\fBputs\fR \fIrepo\fR\fB\&.inspect\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Constants live in the namespace of the class they belong to:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpool\fR\fB\&.set_flag(Solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Note that boolean methods have an added trailing \(lq?\(rq, to be consistent with other ruby modules:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBputs "empty" if\fR \fIrepo\fR\fB\&.isempty?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.SH "TCL SPECIFICS"
+.sp
+Libsolv\(cqs tcl bindings can be loaded with the following statement:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBpackage require solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Objects are either created by calling class name prefixed with \(lqnew_\(rq, or they are returned by calling methods on other objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBset pool [solv::new_Pool]\fR
+\fBset repo [\fR\fI$pool\fR \fBadd_repo "my_first_repo"]\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Swig provides a \(lqcget\(rq method to read object attributes, and a \(lqconfigure\(rq method to write them:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fI$pool\fR \fBconfigure \-appdata 42\fR
+\fBputs "appdata is [\fR\fI$pool\fR \fBcget \-appdata]"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The tcl bindings provide a little helper to work with iterators in a foreach style:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBset iter [\fR\fI$pool\fR \fBsolvables_iter]\fR
+\fBsolv::iter s\fR \fI$iter\fR \fB{ \&.\&.\&. }\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+libsolv\(cqs arrays are mapped to tcl\(cqs lists:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBset jobs [list\fR \fI$job1 $job2\fR\fB]\fR
+\fBset problems [\fR\fI$solver\fR \fBsolve\fR \fI$jobs\fR\fB]\fR
+\fBputs "We have [llength\fR \fI$problems\fR\fB] problems\&.\&.\&."\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Stringification is done by calling the object\(cqs \(lqstr\(rq method\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBputs [\fR\fI$dep\fR \fBstr]\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+There is one exception: you have to use \(lqstringify\(rq for Datamatch objects, as swig reports a clash with the \(lqstr\(rq attribute\&. Some objects also support a \(lq==\(rq method for equality tests, and a \(lq!=\(rq method\&.
+.sp
+Swig implements all constants as numeric variables, constants belonging to a libsolv class are prefixed with the class name:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fI$pool\fR \fBset_flag\fR \fI$solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS\fR \fB1\fR
+\fBputs [\fR\fI$solvable\fR \fBlookup_str\fR \fI$solv::SOLVABLE_SUMMARY\fR\fB]\fR
+.fi
+.if n \{\
+.RE
+.\}
+.SH "THE SOLV CLASS"
+.sp
+This is the main namespace of the library, you cannot create objects of this type but it contains some useful constants\&.
+.SS "CONSTANTS"
+.sp
+Relational flag constants, the first three can be or\-ed together
+.PP
+\fBREL_LT\fR
+.RS 4
+the \(lqless than\(rq bit
+.RE
+.PP
+\fBREL_EQ\fR
+.RS 4
+the \(lqequals to\(rq bit
+.RE
+.PP
+\fBREL_GT\fR
+.RS 4
+the \(lqgreater than\(rq bit
+.RE
+.PP
+\fBREL_ARCH\fR
+.RS 4
+used for relations that describe an extra architecture filter, the version part of the relation is interpreted as architecture\&.
+.RE
+.sp
+Special Solvable Ids
+.PP
+\fBSOLVID_META\fR
+.RS 4
+Access the meta section of a repository or repodata area\&. This is like an extra Solvable that has the Id SOLVID_META\&.
+.RE
+.PP
+\fBSOLVID_POS\fR
+.RS 4
+Use the data position stored inside of the pool instead of accessing some solvable by Id\&. The bindings have the Datapos objects as an abstraction mechanism, so you most likely do not need this constant\&.
+.RE
+.sp
+Constant string Ids
+.PP
+\fBID_NULL\fR
+.RS 4
+Always zero
+.RE
+.PP
+\fBID_EMPTY\fR
+.RS 4
+Always one, describes the empty string
+.RE
+.PP
+\fBSOLVABLE_NAME\fR
+.RS 4
+The keyname Id of the name of the solvable\&.
+.RE
+.PP
+\fB\&...\fR
+.RS 4
+see the libsolv\-constantids manpage for a list of fixed Ids\&.
+.RE
+.SH "THE POOL CLASS"
+.sp
+The pool is libsolv\(cqs central resource manager\&. A pool consists of Solvables, Repositories, Dependencies, each indexed by Ids\&.
+.SS "CLASS METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *Pool()\fR
+my \fI$pool\fR \fB= solv::Pool\->new()\fR;
+\fIpool\fR \fB= solv\&.Pool()\fR
+\fIpool\fR \fB= Solv::Pool\&.new()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a new pool instance\&. In most cases you just need one pool\&. Note that the returned object "owns" the pool, i\&.e\&. if the object is freed, the pool is also freed\&. You can use the disown method to break this ownership relation\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid *appdata;\fR                  /* read/write */
+\fI$pool\fR\fB\->{appdata}\fR
+\fIpool\fR\fB\&.appdata\fR
+\fIpool\fR\fB\&.appdata\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Application specific data that may be used in any way by the code using the pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable solvables[];\fR           /* read only */
+my \fI$solvable\fR \fB=\fR \fI$pool\fR\fB\->{solvables}\->[\fR\fI$solvid\fR\fB]\fR;
+\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.solvables[\fR\fIsolvid\fR\fB]\fR
+\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.solvables[\fR\fIsolvid\fR\fB]\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Look up a Solvable by its id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo repos[];\fR                   /* read only */
+my \fI$repo\fR \fB=\fR \fI$pool\fR\fB\->{repos}\->[\fR\fI$repoid\fR\fB]\fR;
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.repos[\fR\fIrepoid\fR\fB]\fR
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.repos[\fR\fIrepoid\fR\fB]\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Look up a Repository by its id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo *installed;\fR                /* read/write */
+\fI$pool\fR\fB\->{installed} =\fR \fI$repo\fR;
+\fIpool\fR\fB\&.installed =\fR \fIrepo\fR
+\fIpool\fR\fB\&.installed =\fR \fIrepo\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Define which repository contains all the installed packages\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *errstr;\fR             /* read only */
+my \fI$err\fR \fB=\fR \fI$pool\fR\fB\->{errstr}\fR;
+\fIerr\fR \fB=\fR \fIpool\fR\fB\&.errstr\fR
+\fIerr\fR \fB=\fR \fIpool\fR\fB\&.errstr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the last error string that was stored in the pool\&.
+.SS "CONSTANTS"
+.PP
+\fBPOOL_FLAG_PROMOTEEPOCH\fR
+.RS 4
+Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch\&. Used at some time in old rpm versions, modern systems should never need this\&.
+.RE
+.PP
+\fBPOOL_FLAG_FORBIDSELFCONFLICTS\fR
+.RS 4
+Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them since rpm\-4\&.9\&.0\&.
+.RE
+.PP
+\fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR
+.RS 4
+Make obsolete type dependency match against provides instead of just the name and version of packages\&. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version\&.
+.RE
+.PP
+\fBPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES\fR
+.RS 4
+An implicit obsoletes is the internal mechanism to remove the old package on an update\&. The default is to remove all packages with the same name, rpm\-5 switched to also removing packages providing the same name\&.
+.RE
+.PP
+\fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR
+.RS 4
+Rpm\(cqs multilib implementation distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&.
+.RE
+.PP
+\fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR
+.RS 4
+Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel\&. For current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled)\&.
+.RE
+.PP
+\fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR
+.RS 4
+Since version 4\&.9\&.0 rpm considers the obsoletes of installed packages when checking for dependency conflicts, thus you may not install a package that is obsoleted by some other installed package unless you also erase the other package\&.
+.RE
+.PP
+\fBPOOL_FLAG_HAVEDISTEPOCH\fR
+.RS 4
+Mandriva added a new field called distepoch that gets checked in version comparison if the epoch/version/release of two packages are the same\&.
+.RE
+.PP
+\fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR
+.RS 4
+If a package is installed in multiversion mode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&.
+.RE
+.PP
+\fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR
+.RS 4
+Make the addfileprovides method only add files from the standard locations (i\&.e\&. the \(lqbin\(rq and \(lqetc\(rq directories)\&. This is useful if you have only few packages that use non\-standard file dependencies, but you still want the fast speed that addfileprovides() generates\&.
+.RE
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid free()\fR
+\fI$pool\fR\fB\->free()\fR;
+\fIpool\fR\fB\&.free()\fR
+\fIpool\fR\fB\&.free()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Force a free of the pool\&. After this call, you must not access any object that still references the pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid disown()\fR
+\fI$pool\fR\fB\->disown()\fR;
+\fIpool\fR\fB\&.disown()\fR
+\fIpool\fR\fB\&.disown()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Break the ownership relation between the binding object and the pool\&. After this call, the pool will not get freed even if the object goes out of scope\&. This also means that you must manually call the free method to free the pool data\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid setdebuglevel(int\fR \fIlevel\fR\fB)\fR
+\fI$pool\fR\fB\->setdebuglevel(\fR\fI$level\fR\fB)\fR;
+\fIpool\fR\fB\&.setdebuglevel(\fR\fIlevel\fR\fB)\fR
+\fIpool\fR\fB\&.setdebuglevel(\fR\fIlevel\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the debug level\&. A value of zero means no debug output, the higher the value, the more output is generated\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint set_flag(int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR
+my \fI$oldvalue\fR \fB=\fR \fI$pool\fR\fB\->set_flag(\fR\fI$flag\fR\fB,\fR \fI$value\fR\fB)\fR;
+\fIoldvalue\fR \fB=\fR \fIpool\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
+\fIoldvalue\fR \fB=\fR \fIpool\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint get_flag(int\fR \fIflag\fR\fB)\fR
+my \fI$value\fR \fB=\fR \fI$pool\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR;
+\fIvalue\fR \fB=\fR \fIpool\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
+\fIvalue\fR \fB=\fR \fIpool\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set/get a pool specific flag\&. The flags define how the system works, e\&.g\&. how the package manager treats obsoletes\&. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if you want to solve package dependencies for some other system\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_rootdir(const char *\fR\fIrootdir\fR\fB)\fR
+\fI$pool\fR\fB\->set_rootdir(\fR\fIrootdir\fR\fB)\fR;
+\fIpool\fR\fB\&.set_rootdir(\fR\fIrootdir\fR\fB)\fR
+\fIpool\fR\fB\&.set_rootdir(\fR\fIrootdir\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *get_rootdir()\fR
+my \fI$rootdir\fR \fB=\fR \fI$pool\fR\fB\->get_rootdir()\fR;
+\fIrootdir\fR \fB=\fR \fIpool\fR\fB\&.get_rootdir()\fR
+\fIrootdir\fR \fB=\fR \fIpool\fR\fB\&.get_rootdir()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set/get the rootdir to use\&. This is useful if you want package management to work only in some directory, for example if you want to setup a chroot jail\&. Note that the rootdir will only be prepended to file paths if the \fBREPO_USE_ROOTDIR\fR flag is used\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid setarch(const char *\fR\fIarch\fR \fB= 0)\fR
+\fI$pool\fR\fB\->setarch()\fR;
+\fIpool\fR\fB\&.setarch()\fR
+\fIpool\fR\fB\&.setarch()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the architecture for your system\&. The architecture is used to determine which packages are installable\&. It defaults to the result of \(lquname \-m\(rq\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo add_repo(const char *\fR\fIname\fR\fB)\fR
+\fI$repo\fR \fB=\fR \fI$pool\fR\fB\->add_repo(\fR\fI$name\fR\fB)\fR;
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo(\fR\fIname\fR\fB)\fR
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.add_repo(\fR\fIname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a Repository with the specified name to the pool\&. The repository is empty on creation, use the repository methods to populate it with packages\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepoiterator repos_iter()\fR
+\fBfor my\fR \fI$repo\fR \fB(\fR\fI@\fR\fB{\fR\fI$pool\fR\fB\->repos_iter()})\fR
+\fBfor\fR \fIrepo\fR \fBin\fR \fIpool\fR\fB\&.repos_iter():\fR
+\fBfor\fR \fIrepo\fR \fBin\fR \fIpool\fR\fB\&.repos_iter()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over the existing repositories\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvableiterator solvables_iter()\fR
+\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@\fR\fB{\fR\fI$pool\fR\fB\->solvables_iter()})\fR
+\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter():\fR
+\fBfor\fR \fIsolvable\fR \fBin\fR \fIpool\fR\fB\&.solvables_iter()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over the existing solvables\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDep Dep(const char *\fR\fIstr\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$dep\fR \fB=\fR \fI$pool\fR\fB\->Dep(\fR\fI$string\fR\fB)\fR;
+\fIdep\fR \fB=\fR \fIpool\fR\fB\&.Dep(\fR\fIstring\fR\fB)\fR
+\fIdep\fR \fB=\fR \fIpool\fR\fB\&.Dep(\fR\fIstring\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create an object describing a string or dependency\&. If the string is currently not in the pool and \fIcreate\fR is false, \fBundef\fR/\fBNone\fR/\fBnil\fR is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid addfileprovides()\fR
+\fI$pool\fR\fB\->addfileprovides()\fR;
+\fIpool\fR\fB\&.addfileprovides()\fR
+\fIpool\fR\fB\&.addfileprovides()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *addfileprovides_queue()\fR
+my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->addfileprovides_queue()\fR;
+\fIids\fR \fB=\fR \fIpool\fR\fB\&.addfileprovides_queue()\fR
+\fIids\fR \fB=\fR \fIpool\fR\fB\&.addfileprovides_queue()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Some package managers like rpm allow dependencies on files contained in other packages\&. To allow libsolv to deal with those dependencies in an efficient way, you need to call the addfileprovides method after creating and reading all repositories\&. This method will scan all dependency for file names and then scan all packages for matching files\&. If a filename has been matched, it will be added to the provides list of the corresponding package\&. The addfileprovides_queue variant works the same way but returns an array containing all file dependencies\&. This information can be stored in the meta section of the repositories to speed up the next time the repository is loaded and addfileprovides is called\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid createwhatprovides()\fR
+\fI$pool\fR\fB\->createwhatprovides()\fR;
+\fIpool\fR\fB\&.createwhatprovides()\fR
+\fIpool\fR\fB\&.createwhatprovides()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create the internal \(lqwhatprovides\(rq hash over all of the provides of all installable packages\&. This method must be called before doing any lookups on provides\&. It\(cqs encouraged to do it right after all repos are set up, usually right after the call to addfileprovides()\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *whatprovides(DepId\fR \fIdep\fR\fB)\fR
+my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatprovides(\fR\fI$dep\fR\fB)\fR;
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatprovides(\fR\fIdep\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatprovides(\fR\fIdep\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all solvables that provide the specified dependency\&. You can use either a Dep object or a simple Id as argument\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *matchprovidingids(const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR
+my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->matchprovidingids(\fR\fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Search the names of all provides and return the ones matching the specified string\&. See the Dataiterator class for the allowed flags\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId towhatprovides(Id *\fR\fIids\fR\fB)\fR
+my \fI$offset\fR \fB=\fR \fI$pool\fR\fB\->towhatprovides(\e\fR\fI@ids\fR\fB)\fR;
+\fIoffset\fR \fB=\fR \fIpool\fR\fB\&.towhatprovides(\fR\fIids\fR\fB)\fR
+\fIoffset\fR \fB=\fR \fIpool\fR\fB\&.towhatprovides(\fR\fIids\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+\(lqInternalize\(rq an array containing Ids\&. The returned value can be used to create solver jobs working on a specific set of packages\&. See the Solver class for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_namespaceproviders(DepId\fR \fIns\fR\fB, DepId\fR \fIevr\fR\fB, bool\fR \fIvalue\fR \fB= 1)\fR
+\fI$pool\fR\fB\->set_namespaceproviders(\fR\fI$ns\fR\fB,\fR \fI$evr\fR\fB, 1)\fR;
+\fIpool\fR\fB\&.set_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB,\fR \fITrue\fR\fB)\fR
+\fIpool\fR\fB\&.set_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB,\fR \fItrue\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Manually set a namespace provides entry in the whatprovides index\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid flush_namespaceproviders(DepId\fR \fIns\fR\fB, DepId\fR \fIevr\fR\fB)\fR
+\fI$pool\fR\fB\->flush_namespaceproviders(\fR\fI$ns\fR\fB,\fR \fI$evr\fR\fB)\fR;
+\fI$pool\fR\fB\&.flush_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB)\fR
+\fI$pool\fR\fB\&.flush_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Flush the cache of all namespaceprovides matching the specified namespace dependency\&. You can use zero as a wildcard argument\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool isknownarch(DepId\fR \fIid\fR\fB)\fR
+my \fI$bool\fR \fB=\fR \fI$pool\fR\fB\->isknownarch(\fR\fI$id\fR\fB)\fR;
+\fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch(\fR\fIid\fR\fB)\fR
+\fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch?(\fR\fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the specified Id describes a known architecture\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolver Solver()\fR
+my \fI$solver\fR \fB=\fR \fI$pool\fR\fB\->Solver()\fR;
+\fIsolver\fR \fB=\fR \fIpool\fR\fB\&.Solver()\fR
+\fIsolver\fR \fB=\fR \fIpool\fR\fB\&.Solver()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a new solver object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBJob Job(int\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR
+my \fI$job\fR \fB=\fR \fI$pool\fR\fB\->Job(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR;
+\fIjob\fR \fB=\fR \fIpool\fR\fB\&.Job(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
+\fIjob\fR \fB=\fR \fIpool\fR\fB\&.Job(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a new Job object\&. Kind of low level, in most cases you would instead use a Selection or Dep job constructor\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection Selection()\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->Selection()\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection()\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create an empty selection\&. Useful as a starting point for merging other selections\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection Selection_all()\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->Selection_all()\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection_all()\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.Selection_all()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection containing all packages\&. Useful as starting point for intersecting other selections or for update/distupgrade jobs\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection select(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB)\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->select(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection by matching packages against the specified string\&. See the Selection class for a list of flags and how to create solver jobs from a selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection matchdeps(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection by matching package dependencies against the specified string\&. This can be used if you want to match other dependency types than \(lqprovides\(rq\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdepid(\fR\fIdep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection by matching package dependencies against the specified dependency\&. This may be faster than matchdeps and also works with complex dependencies\&. The downside is that you cannot use globs or case insensitive matching\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid setpooljobs(Jobs *\fR\fIjobs\fR\fB)\fR
+\fI$pool\fR\fB\->setpooljobs(\e\fR\fI@jobs\fR\fB)\fR;
+\fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR
+\fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBJob *getpooljobs()\fR
+\fI@jobs\fR \fB=\fR \fI$pool\fR\fB\->getpooljobs()\fR;
+\fIjobs\fR \fB=\fR \fIpool\fR\fB\&.getpooljobs()\fR
+\fIjobs\fR \fB=\fR \fIpool\fR\fB\&.getpooljobs()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Get/Set fixed jobs stored in the pool\&. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages can be multiversion installed, which packages were userinstalled, or which packages must not be erased\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_loadcallback(Callable *\fR\fIcallback\fR\fB)\fR
+\fI$pool\fR\fB\->setloadcallback(\e\fR\fI&callbackfunction\fR\fB)\fR;
+\fIpool\fR\fB\&.setloadcallback(\fR\fIcallbackfunction\fR\fB)\fR
+\fIpool\fR\fB\&.setloadcallback { |\fR\fIrepodata\fR\fB| \&.\&.\&. }\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the callback function called when repository metadata needs to be loaded on demand\&. To make use of this feature, you need to create repodata stubs that tell the library which data is available but not loaded\&. If later on the data needs to be accessed, the callback function is called with a repodata argument\&. You can then load the data (maybe fetching it first from a remote server)\&. The callback should return true if the data has been made available\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+/* bindings only */
+\fI$pool\fR\fB\->appdata_disown()\fR
+\fIpool\fR\fB\&.appdata_disown()\fR
+\fIpool\fR\fB\&.appdata_disown()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Decrement the reference count of the appdata object\&. This can be used to break circular references (e\&.g\&. if the pool\(cqs appdata value points to some meta data structure that contains a pool handle)\&. If used incorrectly, this method can lead to application crashes, so beware\&. (This method is a no\-op for ruby and tcl\&.)
+.SS "DATA RETRIEVAL METHODS"
+.sp
+In the following functions, the \fIkeyname\fR argument describes what to retrieve\&. For the standard cases you can use the available Id constants\&. For example,
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB$solv::SOLVABLE_SUMMARY\fR
+\fBsolv\&.SOLVABLE_SUMMARY\fR
+\fBSolv::SOLVABLE_SUMMARY\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+selects the \(lqSummary\(rq entry of a solvable\&. The \fIsolvid\fR argument selects the desired solvable by Id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$string\fR \fB=\fR \fI$pool\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIpool\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIpool\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$id\fR \fB=\fR \fI$pool\fR\fB\->lookup_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
+my \fI$num\fR \fB=\fR \fI$pool\fR\fB\->lookup_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fInum\fR \fB=\fR \fIpool\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fInum\fR \fB=\fR \fIpool\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool lookup_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$bool\fR \fB=\fR \fI$pool\fR\fB\->lookup_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIbool\fR \fB=\fR \fIpool\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIbool\fR \fB=\fR \fIpool\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *lookup_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIids\fR \fB=\fR \fIpool\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIids\fR \fB=\fR \fIpool\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum lookup_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$chksum\fR \fB=\fR \fI$pool\fR\fB\->lookup_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIchksum\fR \fB=\fR \fIpool\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIchksum\fR \fB=\fR \fIpool\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Lookup functions\&. Return the data element stored in the specified solvable\&. You should probably use the methods of the Solvable class instead\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$di\fR \fB=\fR \fI$pool\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator Dataiterator_solvid(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$di\fR \fB=\fR \fI$pool\fR\fB\->Dataiterator(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIpool\fR\fB\&.Dataiterator(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over the matching data elements\&. See the Dataiterator class for more information\&. The Dataiterator method iterates over all solvables in the pool, whereas the Dataiterator_solvid only iterates over the specified solvable\&.
+.SS "ID METHODS"
+.sp
+The following methods deal with Ids, i\&.e\&. integers representing objects in the pool\&. They are considered \(lqlow level\(rq, in most cases you would not use them but instead the object orientated methods\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo id2repo(Id\fR \fIid\fR\fB)\fR
+\fI$repo\fR \fB=\fR \fI$pool\fR\fB\->id2repo(\fR\fI$id\fR\fB)\fR;
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.id2repo(\fR\fIid\fR\fB)\fR
+\fIrepo\fR \fB=\fR \fIpool\fR\fB\&.id2repo(\fR\fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Lookup an existing Repository by id\&. You can also do this by using the \fBrepos\fR attribute\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable id2solvable(Id\fR \fIid\fR\fB)\fR
+\fI$solvable\fR \fB=\fR \fI$pool\fR\fB\->id2solvable(\fR\fI$id\fR\fB)\fR;
+\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.id2solvable(\fR\fIid\fR\fB)\fR
+\fIsolvable\fR \fB=\fR \fIpool\fR\fB\&.id2solvable(\fR\fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Lookup an existing Repository by id\&. You can also do this by using the \fBsolvables\fR attribute\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *solvid2str(Id\fR \fIid\fR\fB)\fR
+my \fI$str\fR \fB=\fR \fI$pool\fR\fB\->solvid2str(\fR\fI$id\fR\fB)\fR;
+\fIstr\fR \fB=\fR \fIpool\fR\fB\&.solvid2str(\fR\fIid\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIpool\fR\fB\&.solvid2str(\fR\fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string describing the Solvable with the specified id\&. The string consists of the name, version, and architecture of the Solvable\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId str2id(const char *\fR\fIstr\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$id\fR \fB=\fR \fIpool\fR\fB\->str2id(\fR\fI$string\fR\fB)\fR;
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.str2id(\fR\fIstring\fR\fB)\fR
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.str2id(\fR\fIstring\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *id2str(Id\fR \fIid\fR\fB)\fR
+\fI$string\fR \fB=\fR \fIpool\fR\fB\->id2str(\fR\fI$id\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIpool\fR\fB\&.id2str(\fR\fIid\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIpool\fR\fB\&.id2str(\fR\fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a string into an Id and back\&. If the string is currently not in the pool and \fIcreate\fR is false, zero is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId rel2id(Id\fR \fIname\fR\fB, Id\fR \fIevr\fR\fB, int\fR \fIflags\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$id\fR \fB=\fR \fIpool\fR\fB\->rel2id(\fR\fI$nameid\fR\fB,\fR \fI$evrid\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.rel2id(\fR\fInameid\fR\fB,\fR \fIevrid\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.rel2id(\fR\fInameid\fR\fB,\fR \fIevrid\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a \(lqrelational\(rq dependency\&. Such dependencies consist of a name part, \fIflags\fR describing the relation, and a version part\&. The flags are:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB$solv::REL_EQ | $solv::REL_GT | $solv::REL_LT\fR
+\fBsolv\&.REL_EQ | solv\&.REL_GT | solv\&.REL_LT\fR
+\fBSolv::REL_EQ | Solv::REL_GT | Solv::REL_LT\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Thus, if you want a \(lq<=\(rq relation, you would use \fBREL_LT | REL_EQ\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id2langid(Id\fR \fIid\fR\fB, const char *\fR\fIlang\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$id\fR \fB=\fR \fI$pool\fR\fB\->id2langid(\fR\fI$id\fR\fB,\fR \fI$language\fR\fB)\fR;
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.id2langid(\fR\fIid\fR\fB,\fR \fIlanguage\fR\fB)\fR
+\fIid\fR \fB=\fR \fIpool\fR\fB\&.id2langid(\fR\fIid\fR\fB,\fR \fIlanguage\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a language specific Id from some other id\&. This function simply converts the id into a string, appends a dot and the specified language to the string and converts the result back into an Id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *dep2str(Id\fR \fIid\fR\fB)\fR
+\fI$string\fR \fB=\fR \fIpool\fR\fB\->dep2str(\fR\fI$id\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIpool\fR\fB\&.dep2str(\fR\fIid\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIpool\fR\fB\&.dep2str(\fR\fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a dependency id into a string\&. If the id is just a string, this function has the same effect as id2str()\&. For relational dependencies, the result is the correct \(lqname relation evr\(rq string\&.
+.SH "THE DEPENDENCY CLASS"
+.sp
+The dependency class is an object orientated way to work with strings and dependencies\&. Internally, dependencies are represented as Ids, i\&.e\&. simple numbers\&. Dependency objects can be constructed by using the Pool\(cqs Dep() method\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR             /* read only */
+\fI$dep\fR\fB\->{pool}\fR
+\fIdep\fR\fB\&.pool\fR
+\fIdep\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back reference to the pool this dependency belongs to\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR          /* read only */
+\fI$dep\fR\fB\->{id}\fR
+\fIdep\fR\fB\&.id\fR
+\fIdep\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of this dependency\&.
+.SH "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDep Rel(int\fR \fIflags\fR\fB, DepId\fR \fIevrid\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$reldep\fR \fB=\fR \fI$dep\fR\fB\->Rel(\fR\fI$flags\fR\fB,\fR \fI$evrdep\fR\fB)\fR;
+\fIreldep\fR \fB=\fR \fIdep\fR\fB\&.Rel(\fR\fIflags\fR\fB,\fR \fIevrdep\fR\fB)\fR
+\fIreldep\fR \fB=\fR \fIdep\fR\fB\&.Rel(\fR\fIflags\fR\fB,\fR \fIevrdep\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a relational dependency from the caller dependency, the flags, and a dependency describing the \(lqversion\(rq part\&. See the pool\(cqs rel2id method for a description of the flags\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection Selection_name(int\fR \fIsetflags\fR \fB= 0)\fR
+my \fI$sel\fR \fB=\fR \fI$dep\fR\fB\->Selection_name()\fR;
+\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_name()\fR
+\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_name()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a Selection from a dependency\&. The selection consists of all packages that have a name equal to the dependency\&. If the dependency is of a relational type, the packages version must also fulfill the dependency\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection Selection_provides(int\fR \fIsetflags\fR \fB= 0)\fR
+my \fI$sel\fR \fB=\fR \fI$dep\fR\fB\->Selection_provides()\fR;
+\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_provides()\fR
+\fIsel\fR \fB=\fR \fIdep\fR\fB\&.Selection_provides()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a Selection from a dependency\&. The selection consists of all packages that have at least one provides matching the dependency\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *str()\fR
+my \fI$str\fR \fB=\fR \fI$dep\fR\fB\->str()\fR;
+\fIstr\fR \fB=\fR \fI$dep\fR\fB\&.str()\fR
+\fIstr\fR \fB=\fR \fI$dep\fR\fB\&.str()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string describing the dependency\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$dep\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIdep\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIdep\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as calling the str() method\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$dep1\fR \fB==\fR \fI$dep2\fR\fB)\fR
+\fBif\fR \fIdep1\fR \fB==\fR \fIdep2\fR\fB:\fR
+\fBif\fR \fIdep1\fR \fB==\fR \fIdep2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Two dependencies are equal if they are part of the same pool and have the same ids\&.
+.SH "THE REPOSITORY CLASS"
+.sp
+A Repository describes a group of packages, normally coming from the same source\&. Repositories are created by the Pool\(cqs add_repo() method\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                     /* read only */
+\fI$repo\fR\fB\->{pool}\fR
+\fIrepo\fR\fB\&.pool\fR
+\fIrepo\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back reference to the pool this dependency belongs to\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                          /* read only */
+\fI$repo\fR\fB\->{id}\fR
+\fIrepo\fR\fB\&.id\fR
+\fIrepo\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *name;\fR               /* read/write */
+\fI$repo\fR\fB\->{name}\fR
+\fIrepo\fR\fB\&.name\fR
+\fIrepo\fR\fB\&.name\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The repositories name\&. To libsolv, the name is just a string with no specific meaning\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint priority;\fR                   /* read/write */
+\fI$repo\fR\fB\->{priority}\fR
+\fIrepo\fR\fB\&.priority\fR
+\fIrepo\fR\fB\&.priority\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The priority of the repository\&. A higher number means that packages of this repository will be chosen over other repositories, even if they have a greater package version\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint subpriority;\fR                /* read/write */
+\fI$repo\fR\fB\->{subpriority}\fR
+\fIrepo\fR\fB\&.subpriority\fR
+\fIrepo\fR\fB\&.subpriority\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The sub\-priority of the repository\&. This value is compared when the priorities of two repositories are the same\&. It is useful to make the library prefer on\-disk repositories to remote ones\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint nsolvables;\fR                 /* read only */
+\fI$repo\fR\fB\->{nsolvables}\fR
+\fIrepo\fR\fB\&.nsolvables\fR
+\fIrepo\fR\fB\&.nsolvables\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The number of solvables in this repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid *appdata;\fR                  /* read/write */
+\fI$repo\fR\fB\->{appdata}\fR
+\fIrepo\fR\fB\&.appdata\fR
+\fIrepo\fR\fB\&.appdata\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Application specific data that may be used in any way by the code using the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDatapos *meta;\fR                  /* read only */
+\fI$repo\fR\fB\->{meta}\fR
+\fIrepo\fR\fB\&.meta\fR
+\fIrepo\fR\fB\&.meta\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a Datapos object of the repodata\(cqs metadata\&. You can use the lookup methods of the Datapos class to lookup metadata attributes, like the repository timestamp\&.
+.SS "CONSTANTS"
+.PP
+\fBREPO_REUSE_REPODATA\fR
+.RS 4
+Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new area\&.
+.RE
+.PP
+\fBREPO_NO_INTERNALIZE\fR
+.RS 4
+Do not internalize the added repository data\&. This is useful if you plan to add more data because internalization is a costly operation\&.
+.RE
+.PP
+\fBREPO_LOCALPOOL\fR
+.RS 4
+Use the repodata\(cqs pool for Id storage instead of the global pool\&. Useful if you don\(cqt want to pollute the global pool with many unneeded ids, like when storing the filelist\&.
+.RE
+.PP
+\fBREPO_USE_LOADING\fR
+.RS 4
+Use the repodata that is currently being loaded instead of creating a new one\&. This only makes sense if used in a load callback\&.
+.RE
+.PP
+\fBREPO_EXTEND_SOLVABLES\fR
+.RS 4
+Do not create new solvables for the new data, but match existing solvables and add the data to them\&. Repository metadata is often split into multiple parts, with one primary file describing all packages and other parts holding information that is normally not needed, like the changelog\&.
+.RE
+.PP
+\fBREPO_USE_ROOTDIR\fR
+.RS 4
+Prepend the pool\(cqs rootdir to the path when doing file operations\&.
+.RE
+.PP
+\fBREPO_NO_LOCATION\fR
+.RS 4
+Do not add a location element to the solvables\&. Useful if the solvables are not in the final position, so you can add the correct location later in your code\&.
+.RE
+.PP
+\fBSOLV_ADD_NO_STUBS\fR
+.RS 4
+Do not create stubs for repository parts that can be downloaded on demand\&.
+.RE
+.PP
+\fBSUSETAGS_RECORD_SHARES\fR
+.RS 4
+This is specific to the add_susetags() method\&. Susetags allows one to refer to already read packages to save disk space\&. If this data sharing needs to work over multiple calls to add_susetags, you need to specify this flag so that the share information is made available to subsequent calls\&.
+.RE
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid free(bool\fR \fIreuseids\fR \fB= 0)\fR
+\fI$repo\fR\fB\->free()\fR;
+\fIrepo\fR\fB\&.free()\fR
+\fIrepo\fR\fB\&.free()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Free the repository and all solvables it contains\&. If \fIreuseids\fR is set to true, the solvable ids and the repository id may be reused by the library when added new solvables\&. Thus you should leave it false if you are not sure that somebody holds a reference\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid empty(bool\fR \fIreuseids\fR \fB= 0)\fR
+\fI$repo\fR\fB\->empty()\fR;
+\fIrepo\fR\fB\&.empty()\fR
+\fIrepo\fR\fB\&.empty()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Free all the solvables in a repository\&. The repository will be empty after this call\&. See the free() method for the meaning of \fIreuseids\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool isempty()\fR
+\fI$repo\fR\fB\->isempty()\fR
+\fIrepo\fR\fB\&.empty()\fR
+\fIrepo\fR\fB\&.empty?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if there are no solvables in this repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid internalize()\fR
+\fI$repo\fR\fB\->internalize()\fR;
+\fIrepo\fR\fB\&.internalize()\fR
+\fIrepo\fR\fB\&.internalize()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Internalize added data\&. Data must be internalized before it is available to the lookup and data iterator functions\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool write(FILE *\fR\fIfp\fR\fB)\fR
+\fI$repo\fR\fB\->write(\fR\fI$fp\fR\fB)\fR
+\fIrepo\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Write a repo as a \(lqsolv\(rq file\&. These files can be read very fast and thus are a good way to cache repository data\&. Returns false if there was some error writing the file\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvableiterator solvables_iter()\fR
+\fBfor my\fR \fI$solvable\fR \fB(\fR\fI@\fR\fB{\fR\fI$repo\fR\fB\->solvables_iter()})\fR
+\fBfor\fR \fIsolvable\fR \fBin\fR \fIrepo\fR\fB\&.solvables_iter():\fR
+\fBfor\fR \fIsolvable\fR \fBin\fR \fIrepo\fR\fB\&.solvables_iter()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over all solvables in a repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepodata add_repodata(int\fR \fIflags\fR \fB= 0)\fR
+my \fI$repodata\fR \fB=\fR \fI$repo\fR\fB\->add_repodata()\fR;
+\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.add_repodata()\fR
+\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.add_repodata()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a new repodata area to the repository\&. This is normally automatically done by the repo_add methods, so you need this method only in very rare circumstances\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid create_stubs()\fR
+\fI$repo\fR\fB\->create_stubs()\fR;
+\fIrepo\fR\fB\&.create_stubs()\fR
+\fIrepo\fR\fB\&.create_stubs()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Calls the create_stubs() repodata method for the last repodata of the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool iscontiguous()\fR
+\fI$repo\fR\fB\->iscontiguous()\fR
+\fIrepo\fR\fB\&.iscontiguous()\fR
+\fIrepo\fR\fB\&.iscontiguous?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the solvables of this repository are all in a single block with no holes, i\&.e\&. they have consecutive ids\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepodata first_repodata()\fR
+my \fI$repodata\fR \fB=\fR \fI$repo\fR\fB\->first_repodata()\fR;
+\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.first_repodata()\fR
+\fIrepodata\fR \fB=\fR \fIrepo\fR\fB\&.first_repodata()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Checks if all repodatas but the first repodata are extensions, and return the first repodata if this is the case\&. Useful if you want to do a store/retrieve sequence on the repository to reduce the memory using and enable paging, as this does not work if the repository contains multiple non\-extension repodata areas\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection Selection(int\fR \fIsetflags\fR \fB= 0)\fR
+my \fI$sel\fR \fB=\fR \fI$repo\fR\fB\->Selection()\fR;
+\fIsel\fR \fB=\fR \fIrepo\fR\fB\&.Selection()\fR
+\fIsel\fR \fB=\fR \fIrepo\fR\fB\&.Selection()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a Selection consisting of all packages in the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator Dataiterator(Id\fR \fIkey\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$di\fR \fB=\fR \fI$repo\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator Dataiterator_meta(Id\fR \fIkey\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$di\fR \fB=\fR \fI$repo\fR\fB\->Dataiterator_meta(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator_meta(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIrepo\fR\fB\&.Dataiterator_meta(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over the matching data elements in this repository\&. See the Dataiterator class for more information\&. The Dataiterator() method iterates over all solvables in a repository, whereas the Dataiterator_meta method only iterates over the repository\(cqs meta data\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$repo\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIrepo\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIrepo\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the name of the repository, or "Repo#<id>" if no name is set\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$repo1\fR \fB==\fR \fI$repo2\fR\fB)\fR
+\fBif\fR \fIrepo1\fR \fB==\fR \fIrepo2\fR\fB:\fR
+\fBif\fR \fIrepo1\fR \fB==\fR \fIrepo2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Two repositories are equal if they belong to the same pool and have the same id\&.
+.SS "DATA ADD METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable add_solvable()\fR
+\fI$repo\fR\fB\->add_solvable()\fR;
+\fIrepo\fR\fB\&.add_solvable()\fR
+\fIrepo\fR\fB\&.add_solvable()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a single empty solvable to the repository\&. Returns a Solvable object, see the Solvable class for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_solv(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_solv(\fR\fI$name\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_solv(\fR\fIname\fR\fB)\fR
+\fIrepo\fR\fB\&.add_solv(\fR\fIname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Read a \(lqsolv\(rq file and add its contents to the repository\&. These files can be written with the write() method and are normally used as fast cache for repository metadata\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_rpmdb(int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_rpmdb()\fR;
+\fIrepo\fR\fB\&.add_rpmdb()\fR
+\fIrepo\fR\fB\&.add_rpmdb()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_rpmdb_reffp(FILE *\fR\fIreffp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_rpmdb_reffp(\fR\fI$reffp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_rpmdb_reffp(\fR\fIreffp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_rpmdb_reffp(\fR\fIreffp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the rpm database to the repository\&. If a solv file containing an old version of the database is available, it can be passed as reffp to speed up reading\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable add_rpm(const char *\fR\fIfilename\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_rpm(\fR\fI$filename\fR\fB)\fR;
+\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_rpm(\fR\fIfilename\fR\fB)\fR
+\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_rpm(\fR\fIfilename\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the metadata of a single rpm package to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_rpmdb_pubkeys(int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_rpmdb_pubkeys()\fR;
+\fIrepo\fR\fB\&.add_rpmdb_pubkeys()\fR
+\fIrepo\fR\fB\&.add_rpmdb_pubkeys()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add all pubkeys contained in the rpm database to the repository\&. Note that newer rpm versions also allow to store the pubkeys in some directory instead of the rpm database\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable add_pubkey(const char *\fR\fIkeyfile\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_pubkey(\fR\fI$keyfile\fR\fB)\fR;
+\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_pubkey(\fR\fIkeyfile\fR\fB)\fR
+\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_pubkey(\fR\fIkeyfile\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a pubkey from a file to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_rpmmd(FILE *\fR\fIfp\fR\fB, const char *\fR\fIlanguage\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_rpmmd(\fR\fI$fp\fR\fB,\fR \fIundef\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_rpmmd(\fR\fIfp\fR\fB,\fR \fINone\fR\fB)\fR
+\fIrepo\fR\fB\&.add_rpmmd(\fR\fIfp\fR\fB,\fR \fInil\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add metadata stored in the "rpm\-md" format (i\&.e\&. from files in the \(lqrepodata\(rq directory) to a repository\&. Supported files are "primary", "filelists", "other", "suseinfo"\&. Do not forget to specify the \fBREPO_EXTEND_SOLVABLES\fR for extension files like "filelists" and "other"\&. Use the \fIlanguage\fR parameter if you have language extension files, otherwise simply use a \fBundef\fR/\fBNone\fR/\fBnil\fR parameter\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_repomdxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_repomdxml(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_repomdxml(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_repomdxml(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the repomd\&.xml meta description from the "rpm\-md" format to the repository\&. This file contains information about the repository like keywords, and also a list of all database files with checksums\&. The data is added to the "meta" section of the repository, i\&.e\&. no package gets created\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_updateinfoxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_updateinfoxml(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_updateinfoxml(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_updateinfoxml(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the updateinfo\&.xml file containing available maintenance updates to the repository\&. All updates are created as special packages that have a "patch:" prefix in their name\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_deltainfoxml(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_deltainfoxml(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_deltainfoxml(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_deltainfoxml(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the deltainfo\&.xml file (also called prestodelta\&.xml) containing available delta\-rpms to the repository\&. The data is added to the "meta" section, i\&.e\&. no package gets created\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_debdb(int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_debdb()\fR;
+\fIrepo\fR\fB\&.add_debdb()\fR
+\fIrepo\fR\fB\&.add_debdb()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the debian installed package database to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_debpackages(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_debpackages(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_debpackages(\fR\fI$fp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_debpackages(\fR\fI$fp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the debian repository metadata (the "packages" file) to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable add_deb(const char *\fR\fIfilename\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$solvable\fR \fB=\fR \fI$repo\fR\fB\->add_deb(\fR\fI$filename\fR\fB)\fR;
+\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_deb(\fR\fIfilename\fR\fB)\fR
+\fIsolvable\fR \fB=\fR \fIrepo\fR\fB\&.add_deb(\fR\fIfilename\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the metadata of a single deb package to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_mdk(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_mdk(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_mdk(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the mageia/mandriva repository metadata (the "synthesis\&.hdlist" file) to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_mdk_info(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_mdk_info(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_mdk_info(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_mdk_info(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Extend the packages from the synthesis file with the info\&.xml and files\&.xml data\&. Do not forget to specify \fBREPO_EXTEND_SOLVABLES\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_arch_repo(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_arch_repo(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_arch_repo(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_arch_repo(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the archlinux repository metadata (the "\&.db\&.tar" file) to the repository\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_arch_local(const char *\fR\fIdir\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_arch_local(\fR\fI$dir\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_arch_local(\fR\fIdir\fR\fB)\fR
+\fIrepo\fR\fB\&.add_arch_local(\fR\fIdir\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the archlinux installed package database to the repository\&. The \fIdir\fR parameter is usually set to "/var/lib/pacman/local"\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_content(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_content(\fR\fI$fp\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_content(\fR\fIfp\fR\fB)\fR
+\fIrepo\fR\fB\&.add_content(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the \(lqcontent\(rq meta description from the susetags format to the repository\&. This file contains information about the repository like keywords, and also a list of all database files with checksums\&. The data is added to the "meta" section of the repository, i\&.e\&. no package gets created\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_susetags(FILE *\fR\fIfp\fR\fB, Id\fR \fIdefvendor\fR\fB, const char *\fR\fIlanguage\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_susetags(\fR\fI$fp\fR\fB,\fR \fI$defvendor\fR\fB,\fR \fI$language\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_susetags(\fR\fIfp\fR\fB,\fR \fIdefvendor\fR\fB,\fR \fIlanguage\fR\fB)\fR
+\fIrepo\fR\fB\&.add_susetags(\fR\fIfp\fR\fB,\fR \fIdefvendor\fR\fB,\fR \fIlanguage\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add repository metadata in the susetags format to the repository\&. Like with add_rpmmd, you can specify a language if you have language extension files\&. The \fIdefvendor\fR parameter provides a default vendor for packages with missing vendors, it is usually provided in the content file\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_products(const char *\fR\fIdir\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+\fI$repo\fR\fB\->add_products(\fR\fI$dir\fR\fB)\fR;
+\fIrepo\fR\fB\&.add_products(\fR\fIdir\fR\fB)\fR
+\fIrepo\fR\fB\&.add_products(\fR\fIdir\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the installed SUSE products database to the repository\&. The \fIdir\fR parameter is usually "/etc/products\&.d"\&.
+.SH "THE SOLVABLE CLASS"
+.sp
+A solvable describes all the information of one package\&. Each solvable belongs to one repository, it can be added and filled manually but in most cases solvables will get created by the repo_add methods\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo *repo;\fR                     /* read only */
+\fI$solvable\fR\fB\->{repo}\fR
+\fIsolvable\fR\fB\&.repo\fR
+\fIsolvable\fR\fB\&.repo\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The repository this solvable belongs to\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                     /* read only */
+\fI$solvable\fR\fB\->{pool}\fR
+\fIsolvable\fR\fB\&.pool\fR
+\fIsolvable\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The pool this solvable belongs to, same as the pool of the repo\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                          /* read only */
+\fI$solvable\fR\fB\->{id}\fR
+\fIsolvable\fR\fB\&.id\fR
+\fIsolvable\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The specific id of the solvable\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *name;\fR                     /* read/write */
+\fI$solvable\fR\fB\->{name}\fR
+\fIsolvable\fR\fB\&.name\fR
+\fIsolvable\fR\fB\&.name\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *evr;\fR                      /* read/write */
+\fI$solvable\fR\fB\->{evr}\fR
+\fIsolvable\fR\fB\&.evr\fR
+\fIsolvable\fR\fB\&.evr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *arch;\fR                     /* read/write */
+\fI$solvable\fR\fB\->{arch}\fR
+\fIsolvable\fR\fB\&.arch\fR
+\fIsolvable\fR\fB\&.arch\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *vendor;\fR                   /* read/write */
+\fI$solvable\fR\fB\->{vendor}\fR
+\fIsolvable\fR\fB\&.vendor\fR
+\fIsolvable\fR\fB\&.vendor\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Easy access to often used attributes of solvables\&. They are internally stored as Ids\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId nameid;\fR                      /* read/write */
+\fI$solvable\fR\fB\->{nameid}\fR
+\fIsolvable\fR\fB\&.nameid\fR
+\fIsolvable\fR\fB\&.nameid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId evrid;\fR                       /* read/write */
+\fI$solvable\fR\fB\->{evrid}\fR
+\fIsolvable\fR\fB\&.evrid\fR
+\fIsolvable\fR\fB\&.evrid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId archid;\fR                      /* read/write */
+\fI$solvable\fR\fB\->{archid}\fR
+\fIsolvable\fR\fB\&.archid\fR
+\fIsolvable\fR\fB\&.archid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId vendorid;\fR                    /* read/write */
+\fI$solvable\fR\fB\->{vendorid}\fR
+\fIsolvable\fR\fB\&.vendorid\fR
+\fIsolvable\fR\fB\&.vendorid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Raw interface to the ids\&. Useful if you want to search for a specific id and want to avoid the string compare overhead\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_str(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$string\fR \fB=\fR \fI$solvable\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId lookup_id(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$id\fR \fB=\fR \fI$solvable\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR;
+\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
+\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long lookup_num(Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
+my \fI$num\fR \fB=\fR \fI$solvable\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR;
+\fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
+\fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool lookup_void(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$bool\fR \fB=\fR \fI$solvable\fR\fB\->lookup_void(\fR\fI$keyname\fR\fB)\fR;
+\fIbool\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
+\fIbool\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum lookup_checksum(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$chksum\fR \fB=\fR \fI$solvable\fR\fB\->lookup_checksum(\fR\fI$keyname\fR\fB)\fR;
+\fIchksum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
+\fIchksum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *lookup_idarray(Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI@ids\fR \fB=\fR \fI$solvable\fR\fB\->lookup_idarray(\fR\fI$keyname\fR\fB)\fR;
+\fIids\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
+\fIids\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDep *lookup_deparray(Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI@deps\fR \fB=\fR \fI$solvable\fR\fB\->lookup_deparray(\fR\fI$keyname\fR\fB)\fR;
+\fIdeps\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_deparray(\fR\fIkeyname\fR\fB)\fR
+\fIdeps\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_deparray(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Generic lookup methods\&. Retrieve data stored for the specific keyname\&. The lookup_idarray() method will return an array of Ids, use lookup_deparray if you want an array of Dependency objects instead\&. Some Id arrays contain two parts of data divided by a specific marker, for example the provides array uses the SOLVABLE_FILEMARKER id to store both the ids provided by the package and the ids added by the addfileprovides method\&. The default, \-1, translates to the correct marker for the keyname and returns the first part of the array, use 1 to select the second part or 0 to retrieve all ids including the marker\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_location(unsigned int *\fR\fIOUTPUT\fR\fB)\fR;
+my \fB(\fR\fI$location\fR\fB,\fR \fI$mediano\fR\fB) =\fR \fI$solvable\fR\fB\->lookup_location()\fR;
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a tuple containing the on\-media location and an optional media number for multi\-part repositories (e\&.g\&. repositories spawning multiple DVDs)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_sourcepkg()\fR;
+my \fI$sourcepkg\fR \fB=\fR \fI$solvable\fR\fB\->lookup_sourcepkg()\fR;
+\fIsourcepkg\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_sourcepkg()\fR
+\fIsourcepkg\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_sourcepkg()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a sourcepkg name associated with solvable\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$di\fR \fB=\fR \fI$solvable\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIsolvable\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIsolvable\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over the matching data elements\&. See the Dataiterator class for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_deparray(Id\fR \fIkeyname\fR\fB, DepId\fR \fIdep\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR;
+\fI$solvable\fR\fB\->add_deparray(\fR\fI$keyname\fR\fB,\fR \fI$dep\fR\fB)\fR;
+\fIsolvable\fR\fB\&.add_deparray(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR
+\fIsolvable\fR\fB\&.add_deparray(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a new dependency to the attributes stored in keyname\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid unset(Id\fR \fIkeyname\fR\fB)\fR;
+\fI$solvable\fR\fB\->unset(\fR\fI$keyname\fR\fB)\fR;
+\fIsolvable\fR\fB\&.unset(\fR\fIkeyname\fR\fB)\fR
+\fIsolvable\fR\fB\&.unset(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Delete data stored for the specific keyname\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool installable()\fR;
+\fI$solvable\fR\fB\->installable()\fR
+\fIsolvable\fR\fB\&.installable()\fR
+\fIsolvable\fR\fB\&.installable?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the solvable is installable on the system\&. Solvables are not installable if the system does not support their architecture\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool isinstalled()\fR;
+\fI$solvable\fR\fB\->isinstalled()\fR
+\fIsolvable\fR\fB\&.isinstalled()\fR
+\fIsolvable\fR\fB\&.isinstalled?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the solvable is installed on the system\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool identical(Solvable *\fR\fIother\fR\fB)\fR
+\fI$solvable\fR\fB\->identical(\fR\fI$other\fR\fB)\fR
+\fIsolvable\fR\fB\&.identical(\fR\fIother\fR\fB)\fR
+\fIsolvable\fR\fB\&.identical?(\fR\fIother\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the two solvables are identical\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint evrcmp(Solvable *\fR\fIother\fR\fB)\fR
+\fI$solvable\fR\fB\->evrcmp(\fR\fI$other\fR\fB)\fR
+\fIsolvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR
+\fIsolvable\fR\fB\&.evrcmp(\fR\fIother\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Returns \-1 if the epoch/version/release of the solvable is less than the one from the other solvable, 1 if it is greater, and 0 if they are equal\&. Note that "equal" does not mean that the evr is identical\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint matchesdep(Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$solvable\fR\fB\->matchesdep(\fR\fI$keyname\fR\fB,\fR \fI$dep\fR\fB)\fR
+\fIsolvable\fR\fB\&.matchesdep(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR
+\fIsolvable\fR\fB\&.matchesdep?(\fR\fIkeyname\fR\fB,\fR \fIdep\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the dependencies stored in keyname match the specified dependency\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection Selection(int\fR \fIsetflags\fR \fB= 0)\fR
+my \fI$sel\fR \fB=\fR \fI$solvable\fR\fB\->Selection()\fR;
+\fIsel\fR \fB=\fR \fIsolvable\fR\fB\&.Selection()\fR
+\fIsel\fR \fB=\fR \fIsolvable\fR\fB\&.Selection()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a Selection containing just the single solvable\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *str()\fR
+my \fI$str\fR \fB=\fR \fI$solvable\fR\fB\->str()\fR;
+\fIstr\fR \fB=\fR \fI$solvable\fR\fB\&.str()\fR
+\fIstr\fR \fB=\fR \fI$solvable\fR\fB\&.str()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string describing the solvable\&. The string consists of the name, version, and architecture of the Solvable\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$solvable\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIsolvable\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIsolvable\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as calling the str() method\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$solvable1\fR \fB==\fR \fI$solvable2\fR\fB)\fR
+\fBif\fR \fIsolvable1\fR \fB==\fR \fIsolvable2\fR\fB:\fR
+\fBif\fR \fIsolvable1\fR \fB==\fR \fIsolvable2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Two solvables are equal if they are part of the same pool and have the same ids\&.
+.SH "THE DATAITERATOR CLASS"
+.sp
+Dataiterators can be used to do complex string searches or to iterate over arrays\&. They can be created via the constructors in the Pool, Repo, and Solvable classes\&. The Repo and Solvable constructors will limit the search to the repository or the specific package\&.
+.SS "CONSTANTS"
+.PP
+\fBSEARCH_STRING\fR
+.RS 4
+Return a match if the search string matches the value\&.
+.RE
+.PP
+\fBSEARCH_STRINGSTART\fR
+.RS 4
+Return a match if the value starts with the search string\&.
+.RE
+.PP
+\fBSEARCH_STRINGEND\fR
+.RS 4
+Return a match if the value ends with the search string\&.
+.RE
+.PP
+\fBSEARCH_SUBSTRING\fR
+.RS 4
+Return a match if the search string can be matched somewhere in the value\&.
+.RE
+.PP
+\fBSEARCH_GLOB\fR
+.RS 4
+Do a glob match of the search string against the value\&.
+.RE
+.PP
+\fBSEARCH_REGEX\fR
+.RS 4
+Do a regular expression match of the search string against the value\&.
+.RE
+.PP
+\fBSEARCH_NOCASE\fR
+.RS 4
+Ignore case when matching strings\&. Works for all the above match types\&.
+.RE
+.PP
+\fBSEARCH_FILES\fR
+.RS 4
+Match the complete filenames of the file list, not just the base name\&.
+.RE
+.PP
+\fBSEARCH_COMPLETE_FILELIST\fR
+.RS 4
+When matching the file list, check every file of the package not just the subset from the primary metadata\&.
+.RE
+.PP
+\fBSEARCH_CHECKSUMS\fR
+.RS 4
+Allow the matching of checksum entries\&.
+.RE
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid prepend_keyname(Id\fR \fIkeyname\fR\fB)\fR;
+\fI$di\fR\fB\->prepend_keyname(\fR\fI$keyname\fR\fB)\fR;
+\fIdi\fR\fB\&.prepend_keyname(\fR\fIkeyname\fR\fB)\fR
+\fIdi\fR\fB\&.prepend_keyname(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a sub\-search in the array stored in keyname\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid skip_solvable()\fR;
+\fI$di\fR\fB\->skip_solvable()\fR;
+\fIdi\fR\fB\&.skip_solvable()\fR
+\fIdi\fR\fB\&.skip_solvable()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Stop matching the current solvable and advance to the next one\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<iteration>\fR
+\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate through the matches\&. If there is a match, the object in d will be of type Datamatch\&.
+.SH "THE DATAMATCH CLASS"
+.sp
+Objects of this type will be created for every value matched by a dataiterator\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                             /* read only */
+\fI$d\fR\fB\->{pool}\fR
+\fId\fR\fB\&.pool\fR
+\fId\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo *repo;\fR                             /* read only */
+\fI$d\fR\fB\->{repo}\fR
+\fId\fR\fB\&.repo\fR
+\fId\fR\fB\&.repo\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The repository containing the matched object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *solvable;\fR                     /* read only */
+\fI$d\fR\fB\->{solvable}\fR
+\fId\fR\fB\&.solvable\fR
+\fId\fR\fB\&.solvable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The solvable containing the value that was matched\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId solvid;\fR                              /* read only */
+\fI$d\fR\fB\->{solvid}\fR
+\fId\fR\fB\&.solvid\fR
+\fId\fR\fB\&.solvid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of the solvable that matched\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId\fR \fIkey_id\fR;
+\fI$d\fR\fB\->{\fR\fIkey_id\fR\fB}\fR
+\fId\fR\fB\&.key_id\fR
+\fId\fR\fB\&.key_id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *\fR\fIkey_idstr\fR;
+\fI$d\fR\fB\->{\fR\fIkey_idstr\fR\fB}\fR
+\fId\fR\fB\&.key_idstr\fR
+\fId\fR\fB\&.key_idstr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The keyname that matched, either as id or string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId\fR \fItype_id\fR;
+\fI$d\fR\fB\->{\fR\fItype_id\fR\fB}\fR
+\fId\fR\fB\&.type_id\fR
+\fId\fR\fB\&.type_id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *\fR\fItype_idstr\fR;
+\fI$d\fR\fB\->{\fR\fItype_idstr\fR\fB}\fR;
+\fId\fR\fB\&.type_idstr\fR
+\fId\fR\fB\&.type_idstr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The key type of the value that was matched, either as id or string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId\fR \fIid\fR;
+\fI$d\fR\fB\->{id}\fR
+\fId\fR\fB\&.id\fR
+\fId\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId\fR \fIidstr\fR;
+\fI$d\fR\fB\->{idstr}\fR
+\fId\fR\fB\&.idstr\fR
+\fId\fR\fB\&.idstr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The Id of the value that was matched (only valid for id types), either as id or string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *\fR\fIstr\fR;
+\fI$d\fR\fB\->{str}\fR
+\fId\fR\fB\&.str\fR
+\fId\fR\fB\&.str\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The string value that was matched (only valid for string types)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long\fR \fInum\fR;
+\fI$d\fR\fB\->{num}\fR
+\fId\fR\fB\&.num\fR
+\fId\fR\fB\&.num\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The numeric value that was matched (only valid for numeric types)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned int\fR \fInum2\fR;
+\fI$d\fR\fB\->{num2}\fR
+\fId\fR\fB\&.num2\fR
+\fId\fR\fB\&.num2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The secondary numeric value that was matched (only valid for types containing two values)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned int\fR \fIbinary\fR;
+\fI$d\fR\fB\->{binary}\fR
+\fId\fR\fB\&.binary\fR
+\fId\fR\fB\&.binary\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The value in binary form, useful for checksums and other data that cannot be represented as a string\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDatapos pos()\fR;
+my \fI$pos\fR \fB=\fR \fI$d\fR\fB\->pos()\fR;
+\fIpos\fR \fB=\fR \fId\fR\fB\&.pos()\fR
+\fIpos\fR \fB=\fR \fId\fR\fB\&.pos()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The position object of the current match\&. It can be used to do sub\-searches starting at the match (if it is of an array type)\&. See the Datapos class for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDatapos parentpos()\fR;
+my \fI$pos\fR \fB=\fR \fI$d\fR\fB\->parentpos()\fR;
+\fIpos\fR \fB=\fR \fId\fR\fB\&.parentpos()\fR
+\fIpos\fR \fB=\fR \fId\fR\fB\&.parentpos()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The position object of the array containing the current match\&. It can be used to do sub\-searches, see the Datapos class for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$d\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fId\fR\fB)\fR
+\fIstr\fR \fB=\fR \fId\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the stringification of the matched value\&. Stringification depends on the search flags, for file list entries it will return just the base name unless SEARCH_FILES is used, for checksums it will return an empty string unless SEARCH_CHECKSUMS is used\&. Numeric values are currently stringified to an empty string\&.
+.SH "THE SELECTION CLASS"
+.sp
+Selections are a way to easily deal with sets of packages\&. There are multiple constructors to create them, the most useful is probably the select() method in the Pool class\&.
+.SS "CONSTANTS"
+.PP
+\fBSELECTION_NAME\fR
+.RS 4
+Create the selection by matching package names\&.
+.RE
+.PP
+\fBSELECTION_PROVIDES\fR
+.RS 4
+Create the selection by matching package provides\&.
+.RE
+.PP
+\fBSELECTION_FILELIST\fR
+.RS 4
+Create the selection by matching package files\&.
+.RE
+.PP
+\fBSELECTION_CANON\fR
+.RS 4
+Create the selection by matching the canonical representation of the package\&. This is normally a combination of the name, the version, and the architecture of a package\&.
+.RE
+.PP
+\fBSELECTION_DOTARCH\fR
+.RS 4
+Allow an "\&.<architecture>" suffix when matching names or provides\&.
+.RE
+.PP
+\fBSELECTION_REL\fR
+.RS 4
+Allow the specification of a relation when matching names or dependencies, e\&.g\&. "name >= 1\&.2"\&.
+.RE
+.PP
+\fBSELECTION_GLOB\fR
+.RS 4
+Allow glob matching for package names, package provides, and file names\&.
+.RE
+.PP
+\fBSELECTION_NOCASE\fR
+.RS 4
+Ignore case when matching package names, package provides, and file names\&.
+.RE
+.PP
+\fBSELECTION_FLAT\fR
+.RS 4
+Return only one selection element describing the selected packages\&. The default is to create multiple elements for all globbed packages\&. Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package\&.
+.RE
+.PP
+\fBSELECTION_SKIP_KIND\fR
+.RS 4
+Remove a "packagekind:" prefix from the package names\&.
+.RE
+.PP
+\fBSELECTION_MATCH_DEPSTR\fR
+.RS 4
+When matching dependencies, do a string match on the result of dep2str instead of using the normal dependency intersect algorithm\&.
+.RE
+.PP
+\fBSELECTION_INSTALLED_ONLY\fR
+.RS 4
+Limit the package search to installed packages\&.
+.RE
+.PP
+\fBSELECTION_SOURCE_ONLY\fR
+.RS 4
+Limit the package search to source packages only\&.
+.RE
+.PP
+\fBSELECTION_WITH_SOURCE\fR
+.RS 4
+Extend the package search to also match source packages\&. The default is only to match binary packages\&.
+.RE
+.PP
+\fBSELECTION_WITH_DISABLED\fR
+.RS 4
+Extend the package search to also include disabled packages\&.
+.RE
+.PP
+\fBSELECTION_WITH_BADARCH\fR
+.RS 4
+Extend the package search to also include packages that are not installable on the configured architecture\&.
+.RE
+.PP
+\fBSELECTION_WITH_ALL\fR
+.RS 4
+Shortcut for selecting the three modifiers above\&.
+.RE
+.PP
+\fBSELECTION_ADD\fR
+.RS 4
+Add the result of the match to the current selection instead of replacing it\&.
+.RE
+.PP
+\fBSELECTION_SUBTRACT\fR
+.RS 4
+Remove the result of the match to the current selection instead of replacing it\&.
+.RE
+.PP
+\fBSELECTION_FILTER\fR
+.RS 4
+Intersect the result of the match to the current selection instead of replacing it\&.
+.RE
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                             /* read only */
+\fI$d\fR\fB\->{pool}\fR
+\fId\fR\fB\&.pool\fR
+\fId\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint flags;\fR                              /* read only */
+\fI$sel\fR\fB\->{flags}\fR
+\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags\fR
+\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The result flags of the selection\&. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result\&. For example, if you create the selection with \(lqSELECTION_NAME | SELECTION_PROVIDES\(rq, the resulting flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not\&. If there was no match at all, the flags will be zero\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool isempty()\fR
+\fI$sel\fR\fB\->isempty()\fR
+\fIsel\fR\fB\&.isempty()\fR
+\fIsel\fR\fB\&.isempty?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return true if the selection is empty, i\&.e\&. no package could be matched\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection clone(int\fR \fIflags\fR \fB= 0)\fR
+my \fI$cloned\fR \fB=\fR \fI$sel\fR\fB\->clone()\fR;
+\fIcloned\fR \fB=\fR \fIsel\fR\fB\&.clone()\fR
+\fIcloned\fR \fB=\fR \fIsel\fR\fB\&.clone()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a copy of a selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid filter(Selection *\fR\fIother\fR\fB)\fR
+\fI$sel\fR\fB\->filter(\fR\fI$other\fR\fB)\fR;
+\fIsel\fR\fB\&.filter(\fR\fIother\fR\fB)\fR
+\fIsel\fR\fB\&.filter(\fR\fIother\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Intersect two selections\&. Packages will only stay in the selection if there are also included in the other selecting\&. Does an in\-place modification\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add(Selection *\fR\fIother\fR\fB)\fR
+\fI$sel\fR\fB\->add(\fR\fI$other\fR\fB)\fR;
+\fIsel\fR\fB\&.add(\fR\fIother\fR\fB)\fR
+\fIsel\fR\fB\&.add(\fR\fIother\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Build the union of two selections\&. All packages of the other selection will be added to the set of packages of the selection object\&. Does an in\-place modification\&. Note that the selection flags are no longer meaningful after the add operation\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid subtract(Selection *\fR\fIother\fR\fB)\fR
+\fI$sel\fR\fB\->subtract(\fR\fI$other\fR\fB)\fR;
+\fIsel\fR\fB\&.subtract(\fR\fIother\fR\fB)\fR
+\fIsel\fR\fB\&.subtract(\fR\fIother\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Remove the packages of the other selection from the packages of the selection object\&. Does an in\-place modification\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_raw(Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR
+\fI$sel\fR\fB\->add_raw(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR;
+\fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
+\fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a raw element to the selection\&. Check the Job class for information about the how and what parameters\&. Note that the selection flags are no longer meaningful after the add_raw operation\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBJob *jobs(int\fR \fIaction\fR\fB)\fR
+my \fI@jobs\fR \fB=\fR \fI$sel\fR\fB\->jobs(\fR\fI$action\fR\fB)\fR;
+\fIjobs\fR \fB=\fR \fIsel\fR\fB\&.jobs(\fR\fIaction\fR\fB)\fR
+\fIjobs\fR \fB=\fR \fIsel\fR\fB\&.jobs(\fR\fIaction\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a selection into an array of Job objects\&. The action parameter is or\-ed to the \(lqhow\(rq part of the job, it describes the type of job (e\&.g\&. install, erase)\&. See the Job class for the action and action modifier constants\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *solvables()\fR
+my \fI@solvables\fR \fB=\fR \fI$sel\fR\fB\->solvables()\fR;
+\fIsolvables\fR \fB=\fR \fIsel\fR\fB\&.solvables()\fR
+\fIsolvables\fR \fB=\fR \fIsel\fR\fB\&.solvables()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a selection into an array of Solvable objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid select(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB)\fR
+\fI$sel\fR\fB\->select(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIsel\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIsel\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a select operation and combine the result with the current selection\&. You can choose the desired combination method by using either the SELECTION_ADD, SELECTION_SUBTRACT, or SELECTION_FILTER flag\&. If none of the flags are used, SELECTION_FILTER|SELECTION_WITH_ALL is assumed\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid matchdeps(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$sel\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a matchdeps operation and combine the result with the current selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$sel\fR\fB\->matchdepid(\fR\fI$dep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a matchdepid operation and combine the result with the current selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$sel\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIsel\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIsel\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string describing the selection\&.
+.SH "THE JOB CLASS"
+.sp
+Jobs are the way to specify to the dependency solver what to do\&. Most of the times jobs will get created by calling the jobs() method on a Selection object, but there is also a Job() constructor in the Pool class\&.
+.SS "CONSTANTS"
+.sp
+Selection constants:
+.PP
+\fBSOLVER_SOLVABLE\fR
+.RS 4
+The \(lqwhat\(rq part is the id of a solvable\&.
+.RE
+.PP
+\fBSOLVER_SOLVABLE_NAME\fR
+.RS 4
+The \(lqwhat\(rq part is the id of a package name\&.
+.RE
+.PP
+\fBSOLVER_SOLVABLE_PROVIDES\fR
+.RS 4
+The \(lqwhat\(rq part is the id of a package provides\&.
+.RE
+.PP
+\fBSOLVER_SOLVABLE_ONE_OF\fR
+.RS 4
+The \(lqwhat\(rq part is an offset into the \(lqwhatprovides\(rq data, created by calling the towhatprovides() pool method\&.
+.RE
+.PP
+\fBSOLVER_SOLVABLE_REPO\fR
+.RS 4
+The \(lqwhat\(rq part is the id of a repository\&.
+.RE
+.PP
+\fBSOLVER_SOLVABLE_ALL\fR
+.RS 4
+The \(lqwhat\(rq part is ignored, all packages are selected\&.
+.RE
+.PP
+\fBSOLVER_SOLVABLE_SELECTMASK\fR
+.RS 4
+A mask containing all the above selection bits\&.
+.RE
+.sp
+Action constants:
+.PP
+\fBSOLVER_NOOP\fR
+.RS 4
+Do nothing\&.
+.RE
+.PP
+\fBSOLVER_INSTALL\fR
+.RS 4
+Install a package of the specified set of packages\&. It tries to install the best matching package (i\&.e\&. the highest version of the packages from the repositories with the highest priority)\&.
+.RE
+.PP
+\fBSOLVER_ERASE\fR
+.RS 4
+Erase all of the packages from the specified set\&. If a package is not installed, erasing it will keep it from getting installed\&.
+.RE
+.PP
+\fBSOLVER_UPDATE\fR
+.RS 4
+Update the matching installed packages to their best version\&. If none of the specified packages are installed, try to update the installed packages to the specified versions\&. See the section about targeted updates about more information\&.
+.RE
+.PP
+\fBSOLVER_WEAKENDEPS\fR
+.RS 4
+Allow to break the dependencies of the matching packages\&. Handle with care\&.
+.RE
+.PP
+\fBSOLVER_MULTIVERSION\fR
+.RS 4
+Mark the matched packages for multiversion install\&. If they get to be installed because of some other job, the installation will keep the old version of the package installed (for rpm this is done by using \(lq\-i\(rq instead of \(lq\-U\(rq)\&.
+.RE
+.PP
+\fBSOLVER_LOCK\fR
+.RS 4
+Do not change the state of the matched packages, i\&.e\&. when they are installed they stay installed, if not they are not selected for installation\&.
+.RE
+.PP
+\fBSOLVER_DISTUPGRADE\fR
+.RS 4
+Update the matching installed packages to the best version included in one of the repositories\&. After this operation, all come from one of the available repositories except orphaned packages\&. Orphaned packages are packages that have no relation to the packages in the repositories, i\&.e\&. no package in the repositories have the same name or obsolete the orphaned package\&. This action brings the installed packages in sync with the ones in the repository\&. By default it also turns of arch/vendor/version locking for the affected packages to simulate a fresh installation\&. This means that distupgrade can actually downgrade packages if only lower versions of a package are available in the repositories\&. You can tweak this behavior with the SOLVER_FLAG_DUP_ solver flags\&.
+.RE
+.PP
+\fBSOLVER_DROP_ORPHANED\fR
+.RS 4
+Erase all the matching installed packages if they are orphaned\&. This only makes sense if there is a \(lqdistupgrade all packages\(rq job\&. The default is to erase orphaned packages only if they block the installation of other packages\&.
+.RE
+.PP
+\fBSOLVER_VERIFY\fR
+.RS 4
+Fix dependency problems of matching installed packages\&. The default is to ignore dependency problems for installed packages\&.
+.RE
+.PP
+\fBSOLVER_USERINSTALLED\fR
+.RS 4
+The matching installed packages are considered to be installed by a user, thus not installed to fulfill some dependency\&. This is needed input for the calculation of unneeded packages for jobs that have the SOLVER_CLEANDEPS flag set\&.
+.RE
+.PP
+\fBSOLVER_ALLOWUNINSTALL\fR
+.RS 4
+Allow the solver to deinstall the matching installed packages if they get into the way of resolving a dependency\&. This is like the SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages\&.
+.RE
+.PP
+\fBSOLVER_FAVOR\fR
+.RS 4
+Prefer the specified packages if the solver encounters an alternative\&. If a job contains multiple matching favor/disfavor elements, the last one takes precedence\&.
+.RE
+.PP
+\fBSOLVER_DISFAVOR\fR
+.RS 4
+Avoid the specified packages if the solver encounters an alternative\&. This can also be used to block recommended or supplemented packages from being installed\&.
+.RE
+.PP
+\fBSOLVER_JOBMASK\fR
+.RS 4
+A mask containing all the above action bits\&.
+.RE
+.sp
+Action modifier constants:
+.PP
+\fBSOLVER_WEAK\fR
+.RS 4
+Makes the job a weak job\&. The solver tries to fulfill weak jobs, but does not report a problem if it is not possible to do so\&.
+.RE
+.PP
+\fBSOLVER_ESSENTIAL\fR
+.RS 4
+Makes the job an essential job\&. If there is a problem with the job, the solver will not propose to remove the job as one solution (unless all other solutions are also to remove essential jobs)\&.
+.RE
+.PP
+\fBSOLVER_CLEANDEPS\fR
+.RS 4
+The solver will try to also erase all packages dragged in through dependencies when erasing the package\&. This needs SOLVER_USERINSTALLED jobs to maximize user satisfaction\&.
+.RE
+.PP
+\fBSOLVER_FORCEBEST\fR
+.RS 4
+Insist on the best package for install, update, and distupgrade jobs\&. If this flag is not used, the solver will use the second\-best package if the best package cannot be installed for some reason\&. When this flag is used, the solver will generate a problem instead\&.
+.RE
+.PP
+\fBSOLVER_TARGETED\fR
+.RS 4
+Forces targeted operation update and distupgrade jobs\&. See the section about targeted updates about more information\&.
+.RE
+.sp
+Set constants\&.
+.PP
+\fBSOLVER_SETEV\fR
+.RS 4
+The job specified the exact epoch and version of the package set\&.
+.RE
+.PP
+\fBSOLVER_SETEVR\fR
+.RS 4
+The job specified the exact epoch, version, and release of the package set\&.
+.RE
+.PP
+\fBSOLVER_SETARCH\fR
+.RS 4
+The job specified the exact architecture of the packages from the set\&.
+.RE
+.PP
+\fBSOLVER_SETVENDOR\fR
+.RS 4
+The job specified the exact vendor of the packages from the set\&.
+.RE
+.PP
+\fBSOLVER_SETREPO\fR
+.RS 4
+The job specified the exact repository of the packages from the set\&.
+.RE
+.PP
+\fBSOLVER_SETNAME\fR
+.RS 4
+The job specified the exact name of the packages from the set\&.
+.RE
+.PP
+\fBSOLVER_NOAUTOSET\fR
+.RS 4
+Turn of automatic set flag generation for SOLVER_SOLVABLE jobs\&.
+.RE
+.PP
+\fBSOLVER_SETMASK\fR
+.RS 4
+A mask containing all the above set bits\&.
+.RE
+.sp
+See the section about set bits for more information\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                             /* read only */
+\fI$job\fR\fB\->{pool}\fR
+\fId\fR\fB\&.pool\fR
+\fId\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId how;\fR                                 /* read/write */
+\fI$job\fR\fB\->{how}\fR
+\fId\fR\fB\&.how\fR
+\fId\fR\fB\&.how\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Union of the selection, action, action modifier, and set flags\&. The selection part describes the semantics of the \(lqwhat\(rq Id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId what;\fR                                /* read/write */
+\fI$job\fR\fB\->{what}\fR
+\fId\fR\fB\&.what\fR
+\fId\fR\fB\&.what\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id describing the set of packages, the meaning depends on the selection part of the \(lqhow\(rq attribute\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *solvables()\fR
+my \fI@solvables\fR \fB=\fR \fI$job\fR\fB\->solvables()\fR;
+\fIsolvables\fR \fB=\fR \fIjob\fR\fB\&.solvables()\fR
+\fIsolvables\fR \fB=\fR \fIjob\fR\fB\&.solvables()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the set of solvables of the job as an array of Solvable objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool isemptyupdate()\fR;
+\fI$job\fR\fB\->isemptyupdate()\fR
+\fIjob\fR\fB\&.isemptyupdate()\fR
+\fIjob\fR\fB\&.isemptyupdate?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convenience function to find out if the job describes an update job with no matching packages, i\&.e\&. a job that does nothing\&. Some package managers like \(lqzypper\(rq like to turn those jobs into install jobs, i\&.e\&. an update of a not\-installed package will result into the installation of the package\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$job\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIjob\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIjob\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string describing the job\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$job1\fR \fB==\fR \fI$job2\fR\fB)\fR
+\fBif\fR \fIjob1\fR \fB==\fR \fIjob2\fR\fB:\fR
+\fBif\fR \fIjob1\fR \fB==\fR \fIjob2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Two jobs are equal if they belong to the same pool and both the \(lqhow\(rq and the \(lqwhat\(rq attributes are the same\&.
+.SS "TARGETED UPDATES"
+.sp
+Libsolv has two modes for upgrades and distupgrade: targeted and untargeted\&. Untargeted mode means that the installed packages from the specified set will be updated to the best version\&. Targeted means that packages that can be updated to a package in the specified set will be updated to the best package of the set\&.
+.sp
+Here\(cqs an example to explain the subtle difference\&. Suppose that you have package A installed in version "1\&.1", "A\-1\&.2" is available in one of the repositories and there is also package "B" that obsoletes package A\&.
+.sp
+An untargeted update of "A" will update the installed "A\-1\&.1" to package "B", because that is the newest version (B obsoletes A and is thus newer)\&.
+.sp
+A targeted update of "A" will update "A\-1\&.1" to "A\-1\&.2", as the set of packages contains both "A\-1\&.1" and "A\-1\&.2", and "A\-1\&.2" is the newer one\&.
+.sp
+An untargeted update of "B" will do nothing, as "B" is not installed\&.
+.sp
+An targeted update of "B" will update "A\-1\&.1" to "B"\&.
+.sp
+Note that the default is to do "auto\-targeting", thus if the specified set of packages does not include an installed package, the solver will assume targeted operation even if SOLVER_TARGETED is not used\&.
+.sp
+This mostly matches the intent of the user, with one exception: In the example above, an update of "A\-1\&.2" will update "A\-1\&.1" to "A\-1\&.2" (targeted mode), but a second update of "A\-1\&.2" will suddenly update to "B", as untargeted mode is chosen because "A\-1\&.2" is now installed\&.
+.sp
+If you want to have full control over when targeting mode is chosen, turn off auto\-targeting with the SOLVER_FLAG_NO_AUTOTARGET solver option\&. In that case, all updates are considered to be untargeted unless they include the SOLVER_TARGETED flag\&.
+.SS "SET BITS"
+.sp
+Set bits specify which parts of the specified packages where specified by the user\&. It is used by the solver when checking if an operation is allowed or not\&. For example, the solver will normally not allow the downgrade of an installed package\&. But it will not report a problem if the SOLVER_SETEVR flag is used, as it then assumes that the user specified the exact version and thus knows what he is doing\&.
+.sp
+So if a package "screen\-1\-1" is installed for the x86_64 architecture and version "2\-1" is only available for the i586 architecture, installing package "screen\-2\&.1" will ask the user for confirmation because of the different architecture\&. When using the Selection class to create jobs the set bits are automatically added, e\&.g\&. selecting \(lqscreen\&.i586\(rq will automatically add SOLVER_SETARCH, and thus no problem will be reported\&.
+.SH "THE SOLVER CLASS"
+.sp
+Dependency solving is what this library is about\&. A solver object is needed for solving to store the result of the solver run\&. The solver object can be used multiple times for different jobs, reusing it allows the solver to re\-use the dependency rules it already computed\&.
+.SS "CONSTANTS"
+.sp
+Flags to modify some of the solver\(cqs behavior:
+.PP
+\fBSOLVER_FLAG_ALLOW_DOWNGRADE\fR
+.RS 4
+Allow the solver to downgrade packages without asking for confirmation (i\&.e\&. reporting a problem)\&.
+.RE
+.PP
+\fBSOLVER_FLAG_ALLOW_ARCHCHANGE\fR
+.RS 4
+Allow the solver to change the architecture of an installed package without asking for confirmation\&. Note that changes to/from noarch are always considered to be allowed\&.
+.RE
+.PP
+\fBSOLVER_FLAG_ALLOW_VENDORCHANGE\fR
+.RS 4
+Allow the solver to change the vendor of an installed package without asking for confirmation\&. Each vendor is part of one or more vendor equivalence classes, normally installed packages may only change their vendor if the new vendor shares at least one equivalence class\&.
+.RE
+.PP
+\fBSOLVER_FLAG_ALLOW_NAMECHANGE\fR
+.RS 4
+Allow the solver to change the name of an installed package, i\&.e\&. install a package with a different name that obsoletes the installed package\&. This option is on by default\&.
+.RE
+.PP
+\fBSOLVER_FLAG_ALLOW_UNINSTALL\fR
+.RS 4
+Allow the solver to erase installed packages to fulfill the jobs\&. This flag also includes the above flags\&. You may want to set this flag if you only have SOLVER_ERASE jobs, as in that case it\(cqs better for the user to check the transaction overview instead of approving every single package that needs to be erased\&.
+.RE
+.PP
+\fBSOLVER_FLAG_DUP_ALLOW_DOWNGRADE\fR
+.RS 4
+Like SOLVER_FLAG_ALLOW_DOWNGRADE, but used in distupgrade mode\&.
+.RE
+.PP
+\fBSOLVER_FLAG_DUP_ALLOW_ARCHCHANGE\fR
+.RS 4
+Like SOLVER_FLAG_ALLOW_ARCHCHANGE, but used in distupgrade mode\&.
+.RE
+.PP
+\fBSOLVER_FLAG_DUP_ALLOW_VENDORCHANGE\fR
+.RS 4
+Like SOLVER_FLAG_ALLOW_VENDORCHANGE, but used in distupgrade mode\&.
+.RE
+.PP
+\fBSOLVER_FLAG_DUP_ALLOW_NAMECHANGE\fR
+.RS 4
+Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode\&.
+.RE
+.PP
+\fBSOLVER_FLAG_NO_UPDATEPROVIDE\fR
+.RS 4
+If multiple packages obsolete an installed package, the solver checks the provides of every such package and ignores all packages that do not provide the installed package name\&. Thus, you can have an official update candidate that provides the old name, and other packages that also obsolete the package but are not considered for updating\&. If you cannot use this feature, you can turn it off by setting this flag\&.
+.RE
+.PP
+\fBSOLVER_FLAG_NEED_UPDATEPROVIDE\fR
+.RS 4
+This is somewhat the opposite of SOLVER_FLAG_NO_UPDATEPROVIDE: Only packages that provide the installed package names are considered for updating\&.
+.RE
+.PP
+\fBSOLVER_FLAG_SPLITPROVIDES\fR
+.RS 4
+Make the solver aware of special provides of the form \(lq<packagename>:<path>\(rq used in SUSE systems to support package splits\&.
+.RE
+.PP
+\fBSOLVER_FLAG_IGNORE_RECOMMENDED\fR
+.RS 4
+Do not process optional (aka weak) dependencies\&.
+.RE
+.PP
+\fBSOLVER_FLAG_ADD_ALREADY_RECOMMENDED\fR
+.RS 4
+Install recommended or supplemented packages even if they have no connection to the current transaction\&. You can use this feature to implement a simple way for the user to install new recommended packages that were not available in the past\&.
+.RE
+.PP
+\fBSOLVER_FLAG_NO_INFARCHCHECK\fR
+.RS 4
+Turn off the inferior architecture checking that is normally done by the solver\&. Normally, the solver allows only the installation of packages from the "best" architecture if a package is available for multiple architectures\&.
+.RE
+.PP
+\fBSOLVER_FLAG_BEST_OBEY_POLICY\fR
+.RS 4
+Make the SOLVER_FORCEBEST job option consider only packages that meet the policies for installed packages, i\&.e\&. no downgrades, no architecture change, no vendor change (see the first flags of this section)\&. If the flag is not specified, the solver will enforce the installation of the best package ignoring the installed packages, which may conflict with the set policy\&.
+.RE
+.PP
+\fBSOLVER_FLAG_NO_AUTOTARGET\fR
+.RS 4
+Do not enable auto\-targeting up update and distupgrade jobs\&. See the section on targeted updates for more information\&.
+.RE
+.PP
+\fBSOLVER_FLAG_KEEP_ORPHANS\fR
+.RS 4
+Do not allow orphaned packages to be deinstalled if they get in the way of resolving other packages\&.
+.RE
+.PP
+\fBSOLVER_FLAG_BREAK_ORPHANS\fR
+.RS 4
+Ignore dependencies of orphaned packages that get in the way of resolving non\-orphaned ones\&. Setting the flag might result in no longer working packages in case they are orphaned\&.
+.RE
+.PP
+\fBSOLVER_FLAG_FOCUS_INSTALLED\fR
+.RS 4
+Resolve installed packages before resolving the given jobs\&. Setting this flag means that the solver will prefer picking a package version that fits the other installed packages over updating installed packages\&.
+.RE
+.PP
+\fBSOLVER_FLAG_FOCUS_BEST\fR
+.RS 4
+First resolve the given jobs, then the dependencies of the resulting packages, then resolve all already installed packages\&. This will result in more packages being updated as when the flag is not used\&.
+.RE
+.PP
+\fBSOLVER_FLAG_INSTALL_ALSO_UPDATES\fR
+.RS 4
+Update the package if a job is already fulfilled by an installed package\&.
+.RE
+.PP
+\fBSOLVER_FLAG_YUM_OBSOLETES\fR
+.RS 4
+Turn on yum\-like package split handling\&. See the yum documentation for more details\&.
+.RE
+.PP
+\fBSOLVER_FLAG_URPM_REORDER\fR
+.RS 4
+Turn on urpm like package reordering for kernel packages\&. See the urpm documentation for more details\&.
+.RE
+.sp
+Basic rule types:
+.PP
+\fBSOLVER_RULE_UNKNOWN\fR
+.RS 4
+A rule of an unknown class\&. You should never encounter those\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG\fR
+.RS 4
+A package dependency rule\&.
+.RE
+.PP
+\fBSOLVER_RULE_UPDATE\fR
+.RS 4
+A rule to implement the update policy of installed packages\&. Every installed package has an update rule that consists of the packages that may replace the installed package\&.
+.RE
+.PP
+\fBSOLVER_RULE_FEATURE\fR
+.RS 4
+Feature rules are fallback rules used when an update rule is disabled\&. They include all packages that may replace the installed package ignoring the update policy, i\&.e\&. they contain downgrades, arch changes and so on\&. Without them, the solver would simply erase installed packages if their update rule gets disabled\&.
+.RE
+.PP
+\fBSOLVER_RULE_JOB\fR
+.RS 4
+Job rules implement the job given to the solver\&.
+.RE
+.PP
+\fBSOLVER_RULE_DISTUPGRADE\fR
+.RS 4
+These are simple negative assertions that make sure that only packages are kept that are also available in one of the repositories\&.
+.RE
+.PP
+\fBSOLVER_RULE_INFARCH\fR
+.RS 4
+Infarch rules are also negative assertions, they disallow the installation of packages when there are packages of the same name but with a better architecture\&.
+.RE
+.PP
+\fBSOLVER_RULE_CHOICE\fR
+.RS 4
+Choice rules are used to make sure that the solver prefers updating to installing different packages when some dependency is provided by multiple packages with different names\&. The solver may always break choice rules, so you will not see them when a problem is found\&.
+.RE
+.PP
+\fBSOLVER_RULE_LEARNT\fR
+.RS 4
+These rules are generated by the solver to keep it from running into the same problem multiple times when it has to backtrack\&. They are the main reason why a sat solver is faster than other dependency solver implementations\&.
+.RE
+.sp
+Special dependency rule types:
+.PP
+\fBSOLVER_RULE_PKG_NOT_INSTALLABLE\fR
+.RS 4
+This rule was added to prevent the installation of a package of an architecture that does not work on the system\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_NOTHING_PROVIDES_DEP\fR
+.RS 4
+The package contains a required dependency which was not provided by any package\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_REQUIRES\fR
+.RS 4
+Similar to SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, but in this case some packages provided the dependency but none of them could be installed due to other dependency issues\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_SELF_CONFLICT\fR
+.RS 4
+The package conflicts with itself\&. This is not allowed by older rpm versions\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_CONFLICTS\fR
+.RS 4
+To fulfill the dependencies two packages need to be installed, but one of the packages contains a conflict with the other one\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_SAME_NAME\fR
+.RS 4
+The dependencies can only be fulfilled by multiple versions of a package, but installing multiple versions of the same package is not allowed\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_OBSOLETES\fR
+.RS 4
+To fulfill the dependencies two packages need to be installed, but one of the packages obsoletes the other one\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_IMPLICIT_OBSOLETES\fR
+.RS 4
+To fulfill the dependencies two packages need to be installed, but one of the packages has provides a dependency that is obsoleted by the other one\&. See the POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES flag\&.
+.RE
+.PP
+\fBSOLVER_RULE_PKG_INSTALLED_OBSOLETES\fR
+.RS 4
+To fulfill the dependencies a package needs to be installed that is obsoleted by an installed package\&. See the POOL_FLAG_NOINSTALLEDOBSOLETES flag\&.
+.RE
+.PP
+\fBSOLVER_RULE_JOB_NOTHING_PROVIDES_DEP\fR
+.RS 4
+The user asked for installation of a package providing a specific dependency, but no available package provides it\&.
+.RE
+.PP
+\fBSOLVER_RULE_JOB_UNKNOWN_PACKAGE\fR
+.RS 4
+The user asked for installation of a package with a specific name, but no available package has that name\&.
+.RE
+.PP
+\fBSOLVER_RULE_JOB_PROVIDED_BY_SYSTEM\fR
+.RS 4
+The user asked for the erasure of a dependency that is provided by the system (i\&.e\&. for special hardware or language dependencies), this cannot be done with a job\&.
+.RE
+.PP
+\fBSOLVER_RULE_JOB_UNSUPPORTED\fR
+.RS 4
+The user asked for something that is not yet implemented, e\&.g\&. the installation of all packages at once\&.
+.RE
+.sp
+Policy error constants
+.PP
+\fBPOLICY_ILLEGAL_DOWNGRADE\fR
+.RS 4
+The solver ask for permission before downgrading packages\&.
+.RE
+.PP
+\fBPOLICY_ILLEGAL_ARCHCHANGE\fR
+.RS 4
+The solver ask for permission before changing the architecture of installed packages\&.
+.RE
+.PP
+\fBPOLICY_ILLEGAL_VENDORCHANGE\fR
+.RS 4
+The solver ask for permission before changing the vendor of installed packages\&.
+.RE
+.PP
+\fBPOLICY_ILLEGAL_NAMECHANGE\fR
+.RS 4
+The solver ask for permission before replacing an installed packages with a package that has a different name\&.
+.RE
+.sp
+Solution element type constants
+.PP
+\fBSOLVER_SOLUTION_JOB\fR
+.RS 4
+The problem can be solved by removing the specified job\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_POOLJOB\fR
+.RS 4
+The problem can be solved by removing the specified job that is defined in the pool\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_INFARCH\fR
+.RS 4
+The problem can be solved by allowing the installation of the specified package with an inferior architecture\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_DISTUPGRADE\fR
+.RS 4
+The problem can be solved by allowing to keep the specified package installed\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_BEST\fR
+.RS 4
+The problem can be solved by allowing to install the specified package that is not the best available package\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_ERASE\fR
+.RS 4
+The problem can be solved by allowing to erase the specified package\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_REPLACE\fR
+.RS 4
+The problem can be solved by allowing to replace the package with some other package\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_REPLACE_DOWNGRADE\fR
+.RS 4
+The problem can be solved by allowing to replace the package with some other package that has a lower version\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_REPLACE_ARCHCHANGE\fR
+.RS 4
+The problem can be solved by allowing to replace the package with some other package that has a different architecture\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_REPLACE_VENDORCHANGE\fR
+.RS 4
+The problem can be solved by allowing to replace the package with some other package that has a different vendor\&.
+.RE
+.PP
+\fBSOLVER_SOLUTION_REPLACE_NAMECHANGE\fR
+.RS 4
+The problem can be solved by allowing to replace the package with some other package that has a different name\&.
+.RE
+.sp
+Reason constants
+.PP
+\fBSOLVER_REASON_UNRELATED\fR
+.RS 4
+The package status did not change as it was not related to any job\&.
+.RE
+.PP
+\fBSOLVER_REASON_UNIT_RULE\fR
+.RS 4
+The package was installed/erased/kept because of a unit rule, i\&.e\&. a rule where all literals but one were false\&.
+.RE
+.PP
+\fBSOLVER_REASON_KEEP_INSTALLED\fR
+.RS 4
+The package was chosen when trying to keep as many packages installed as possible\&.
+.RE
+.PP
+\fBSOLVER_REASON_RESOLVE_JOB\fR
+.RS 4
+The decision happened to fulfill a job rule\&.
+.RE
+.PP
+\fBSOLVER_REASON_UPDATE_INSTALLED\fR
+.RS 4
+The decision happened to fulfill a package update request\&.
+.RE
+.PP
+\fBSOLVER_REASON_CLEANDEPS_ERASE\fR
+.RS 4
+The package was erased when cleaning up dependencies from other erased packages\&.
+.RE
+.PP
+\fBSOLVER_REASON_RESOLVE\fR
+.RS 4
+The package was installed to fulfill package dependencies\&.
+.RE
+.PP
+\fBSOLVER_REASON_WEAKDEP\fR
+.RS 4
+The package was installed because of a weak dependency (Recommends or Supplements)\&.
+.RE
+.PP
+\fBSOLVER_REASON_RESOLVE_ORPHAN\fR
+.RS 4
+The decision about the package was made when deciding the fate of orphaned packages\&.
+.RE
+.PP
+\fBSOLVER_REASON_RECOMMENDED\fR
+.RS 4
+This is a special case of SOLVER_REASON_WEAKDEP\&.
+.RE
+.PP
+\fBSOLVER_REASON_SUPPLEMENTED\fR
+.RS 4
+This is a special case of SOLVER_REASON_WEAKDEP\&.
+.RE
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                             /* read only */
+\fI$job\fR\fB\->{pool}\fR
+\fId\fR\fB\&.pool\fR
+\fId\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to pool\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint set_flag(int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR
+my \fI$oldvalue\fR \fB=\fR \fI$solver\fR\fB\->set_flag(\fR\fI$flag\fR\fB,\fR \fI$value\fR\fB)\fR;
+\fIoldvalue\fR \fB=\fR \fIsolver\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
+\fIoldvalue\fR \fB=\fR \fIsolver\fR\fB\&.set_flag(\fR\fIflag\fR\fB,\fR \fIvalue\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint get_flag(int\fR \fIflag\fR\fB)\fR
+my \fI$value\fR \fB=\fR \fI$solver\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR;
+\fIvalue\fR \fB=\fR \fIsolver\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
+\fIvalue\fR \fB=\fR \fIsolver\fR\fB\&.get_flag(\fR\fIflag\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set/get a solver specific flag\&. The flags define the policies the solver has to obey\&. The flags are explained in the CONSTANTS section of this class\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBProblem *solve(Job *\fR\fIjobs\fR\fB)\fR
+my \fI@problems\fR \fB=\fR \fI$solver\fR\fB\->solve(\e\fR\fI@jobs\fR\fB)\fR;
+\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
+\fIproblems\fR \fB=\fR \fIsolver\fR\fB\&.solve(\fR\fIjobs\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Solve a problem specified in the job list (plus the jobs defined in the pool)\&. Returns an array of problems that need user interaction, or an empty array if no problems were encountered\&. See the Problem class on how to deal with problems\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBTransaction transaction()\fR
+my \fI$trans\fR \fB=\fR \fI$solver\fR\fB\->transaction()\fR;
+\fItrans\fR \fB=\fR \fIsolver\fR\fB\&.transaction()\fR
+\fItrans\fR \fB=\fR \fIsolver\fR\fB\&.transaction()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the transaction to implement the calculated package changes\&. A transaction is available even if problems were found, this is useful for interactive user interfaces that show both the job result and the problems\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint\fR \fIreason\fR \fB= describe_decision(Solvable *\fR\fIs\fR\fB, Rule *\fR\fIOUTPUT\fR\fB)\fR
+my \fB(\fR\fI$reason\fR\fB,\fR \fI$rule\fR\fB) =\fR \fI$solver\fR\fB\->describe_decision(\fR\fI$solvable\fR\fB)\fR;
+\fB(\fR\fIreason\fR\fB,\fR \fIrule\fR\fB) =\fR \fIsolver\fR\fB\&.describe_decision(\fR\fIsolvable\fR\fB)\fR
+\fB(\fR\fIreason\fR\fB,\fR \fIrule\fR\fB) =\fR \fIsolver\fR\fB\&.describe_decision(\fR\fIsolvable\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the reason why a specific solvable was installed or erased\&. For most of the reasons the rule that triggered the decision is also returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *get_recommended(bool\fR \fInoselected\fR\fB=0)\fR;
+my \fI@solvables\fR \fB=\fR \fI$solver\fR\fB\->get_recommended()\fR;
+\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_recommended()\fR
+\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_recommended()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all solvables that are recommended by the solver run result\&. This includes solvables included in the result, set noselected if you want to filter those\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *get_suggested(bool\fR \fInoselected\fR\fB=0)\fR;
+my \fI@solvables\fR \fB=\fR \fI$solver\fR\fB\->get_suggested()\fR;
+\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_suggested()\fR
+\fIsolvables\fR \fB=\fR \fIsolver\fR\fB\&.get_suggested()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all solvables that are suggested by the solver run result\&. This includes solvables included in the result, set noselected if you want to filter those\&.
+.SH "THE PROBLEM CLASS"
+.sp
+Problems are the way of the solver to interact with the user\&. You can simply list all problems and terminate your program, but a better way is to present solutions to the user and let him pick the ones he likes\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolver *solv;\fR                           /* read only */
+\fI$problem\fR\fB\->{solv}\fR
+\fIproblem\fR\fB\&.solv\fR
+\fIproblem\fR\fB\&.solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to solver object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                                  /* read only */
+\fI$problem\fR\fB\->{id}\fR
+\fIproblem\fR\fB\&.id\fR
+\fIproblem\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id of the problem\&. The first problem has Id 1, they are numbered consecutively\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRule findproblemrule()\fR
+my \fI$probrule\fR \fB=\fR \fI$problem\fR\fB\->findproblemrule()\fR;
+\fIprobrule\fR \fB=\fR \fIproblem\fR\fB\&.findproblemrule()\fR
+\fIprobrule\fR \fB=\fR \fIproblem\fR\fB\&.findproblemrule()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the rule that caused the problem\&. Of course in most situations there is no single responsible rule, but many rules that interconnect with each created the problem\&. Nevertheless, the solver uses some heuristic approach to find a rule that somewhat describes the problem best to the user\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRule *findallproblemrules(bool\fR \fIunfiltered\fR \fB= 0)\fR
+my \fI@probrules\fR \fB=\fR \fI$problem\fR\fB\->findallproblemrules()\fR;
+\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrules()\fR
+\fIprobrules\fR \fB=\fR \fIproblem\fR\fB\&.findallproblemrules()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all rules responsible for the problem\&. The returned set of rules contains all the needed information why there was a problem, but it\(cqs hard to present them to the user in a sensible way\&. The default is to filter out all update and job rules (unless the returned rules only consist of those types)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolution *solutions()\fR
+my \fI@solutions\fR \fB=\fR \fI$problem\fR\fB\->solutions()\fR;
+\fIsolutions\fR \fB=\fR \fIproblem\fR\fB\&.solutions()\fR
+\fIsolutions\fR \fB=\fR \fIproblem\fR\fB\&.solutions()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return an array containing multiple possible solutions to fix the problem\&. See the solution class for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint solution_count()\fR
+my \fI$cnt\fR \fB=\fR \fI$problem\fR\fB\->solution_count()\fR;
+\fIcnt\fR \fB=\fR \fIproblem\fR\fB\&.solution_count()\fR
+\fIcnt\fR \fB=\fR \fIproblem\fR\fB\&.solution_count()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the number of solutions without creating solution objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$problem\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIproblem\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIproblem\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string describing the problem\&. This is a convenience function, it is a shorthand for calling findproblemrule(), then ruleinfo() on the problem rule and problemstr() on the ruleinfo object\&.
+.SH "THE RULE CLASS"
+.sp
+Rules are the basic block of sat solving\&. Each package dependency gets translated into one or multiple rules\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolver *solv;\fR                           /* read only */
+\fI$rule\fR\fB\->{solv}\fR
+\fIrule\fR\fB\&.solv\fR
+\fIrule\fR\fB\&.solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to solver object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                                  /* read only */
+\fI$rule\fR\fB\->{id}\fR
+\fIrule\fR\fB\&.id\fR
+\fIrule\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of the rule\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint type;\fR                               /* read only */
+\fI$rule\fR\fB\->{type}\fR
+\fIrule\fR\fB\&.type\fR
+\fIrule\fR\fB\&.type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The basic type of the rule\&. See the constant section of the solver class for the type list\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRuleinfo info()\fR
+my \fI$ruleinfo\fR \fB=\fR \fI$rule\fR\fB\->info()\fR;
+\fIruleinfo\fR \fB=\fR \fIrule\fR\fB\&.info()\fR
+\fIruleinfo\fR \fB=\fR \fIrule\fR\fB\&.info()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a Ruleinfo object that contains information about why the rule was created\&. But see the allinfos() method below\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRuleinfo *allinfos()\fR
+my \fI@ruleinfos\fR \fB=\fR \fI$rule\fR\fB\->allinfos()\fR;
+\fIruleinfos\fR \fB=\fR \fIrule\fR\fB\&.allinfos()\fR
+\fIruleinfos\fR \fB=\fR \fIrule\fR\fB\&.allinfos()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+As the same dependency rule can get created because of multiple dependencies, one Ruleinfo is not enough to describe the reason\&. Thus the allinfos() method returns an array of all infos about a rule\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$rule1\fR \fB==\fR \fI$rule2\fR\fB)\fR
+\fBif\fR \fIrule1\fR \fB==\fR \fIrule2\fR\fB:\fR
+\fBif\fR \fIrule1\fR \fB==\fR \fIrule2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Two rules are equal if they belong to the same solver and have the same id\&.
+.SH "THE RULEINFO CLASS"
+.sp
+A Ruleinfo describes one reason why a rule was created\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolver *solv;\fR                           /* read only */
+\fI$ruleinfo\fR\fB\->{solv}\fR
+\fIruleinfo\fR\fB\&.solv\fR
+\fIruleinfo\fR\fB\&.solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to solver object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint type;\fR                               /* read only */
+\fI$ruleinfo\fR\fB\->{type}\fR
+\fIruleinfo\fR\fB\&.type\fR
+\fIruleinfo\fR\fB\&.type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The type of the ruleinfo\&. See the constant section of the solver class for the rule type list and the special type list\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDep *dep;\fR                               /* read only */
+\fI$ruleinfo\fR\fB\->{dep}\fR
+\fIruleinfo\fR\fB\&.dep\fR
+\fIruleinfo\fR\fB\&.dep\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The dependency leading to the creation of the rule\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDep *dep_id;\fR                            /* read only */
+\fI$ruleinfo\fR\fB\->{\*(Aqdep_id\*(Aq}\fR
+\fIruleinfo\fR\fB\&.dep_id\fR
+\fIruleinfo\fR\fB\&.dep_id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The Id of the dependency leading to the creation of the rule, or zero\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *solvable;\fR                     /* read only */
+\fI$ruleinfo\fR\fB\->{solvable}\fR
+\fIruleinfo\fR\fB\&.solvable\fR
+\fIruleinfo\fR\fB\&.solvable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The involved Solvable, e\&.g\&. the one containing the dependency\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *othersolvable;\fR                /* read only */
+\fI$ruleinfo\fR\fB\->{othersolvable}\fR
+\fIruleinfo\fR\fB\&.othersolvable\fR
+\fIruleinfo\fR\fB\&.othersolvable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The other involved Solvable (if any), e\&.g\&. the one containing providing the dependency for conflicts\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *problemstr()\fR;
+my \fI$str\fR \fB=\fR \fI$ruleinfo\fR\fB\->problemstr()\fR;
+\fIstr\fR \fB=\fR \fIruleinfo\fR\fB\&.problemstr()\fR
+\fIstr\fR \fB=\fR \fIruleinfo\fR\fB\&.problemstr()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A string describing the ruleinfo from a problem perspective\&. This probably only makes sense if the rule is part of a problem\&.
+.SH "THE SOLUTION CLASS"
+.sp
+A solution solves one specific problem\&. It consists of multiple solution elements that all need to be executed\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolver *solv;\fR                           /* read only */
+\fI$solution\fR\fB\->{solv}\fR
+\fIsolution\fR\fB\&.solv\fR
+\fIsolution\fR\fB\&.solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to solver object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId problemid;\fR                           /* read only */
+\fI$solution\fR\fB\->{problemid}\fR
+\fIsolution\fR\fB\&.problemid\fR
+\fIsolution\fR\fB\&.problemid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id of the problem the solution solves\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                                  /* read only */
+\fI$solution\fR\fB\->{id}\fR
+\fIsolution\fR\fB\&.id\fR
+\fIsolution\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id of the solution\&. The first solution has Id 1, they are numbered consecutively\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolutionelement *elements(bool\fR \fIexpandreplaces\fR \fB= 0)\fR
+my \fI@solutionelements\fR \fB=\fR \fI$solution\fR\fB\->elements()\fR;
+\fIsolutionelements\fR \fB=\fR \fIsolution\fR\fB\&.elements()\fR
+\fIsolutionelements\fR \fB=\fR \fIsolution\fR\fB\&.elements()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return an array containing the elements describing what needs to be done to implement the specific solution\&. If expandreplaces is true, elements of type SOLVER_SOLUTION_REPLACE will be replaced by one or more elements replace elements describing the policy mismatches\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint element_count()\fR
+my \fI$cnt\fR \fB=\fR \fI$solution\fR\fB\->solution_count()\fR;
+\fIcnt\fR \fB=\fR \fIsolution\fR\fB\&.element_count()\fR
+\fIcnt\fR \fB=\fR \fIsolution\fR\fB\&.element_count()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the number of solution elements without creating objects\&. Note that the count does not match the number of objects returned by the elements() method of expandreplaces is set to true\&.
+.SH "THE SOLUTIONELEMENT CLASS"
+.sp
+A solution element describes a single action of a solution\&. The action is always either to remove one specific job or to add a new job that installs or erases a single specific package\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolver *solv;\fR                           /* read only */
+\fI$solutionelement\fR\fB\->{solv}\fR
+\fIsolutionelement\fR\fB\&.solv\fR
+\fIsolutionelement\fR\fB\&.solv\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to solver object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId problemid;\fR                           /* read only */
+\fI$solutionelement\fR\fB\->{problemid}\fR
+\fIsolutionelement\fR\fB\&.problemid\fR
+\fIsolutionelement\fR\fB\&.problemid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id of the problem the element (partly) solves\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId solutionid;\fR                          /* read only */
+\fI$solutionelement\fR\fB\->{solutionid}\fR
+\fIsolutionelement\fR\fB\&.solutionid\fR
+\fIsolutionelement\fR\fB\&.solutionid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id of the solution the element is a part of\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                                  /* read only */
+\fI$solutionelement\fR\fB\->{id}\fR
+\fIsolutionelement\fR\fB\&.id\fR
+\fIsolutionelement\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Id of the solution element\&. The first element has Id 1, they are numbered consecutively\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId type;\fR                                /* read only */
+\fI$solutionelement\fR\fB\->{type}\fR
+\fIsolutionelement\fR\fB\&.type\fR
+\fIsolutionelement\fR\fB\&.type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Type of the solution element\&. See the constant section of the solver class for the existing types\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *solvable;\fR                     /* read only */
+\fI$solutionelement\fR\fB\->{solvable}\fR
+\fIsolutionelement\fR\fB\&.solvable\fR
+\fIsolutionelement\fR\fB\&.solvable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The installed solvable that needs to be replaced for replacement elements\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *replacement;\fR                  /* read only */
+\fI$solutionelement\fR\fB\->{replacement}\fR
+\fIsolutionelement\fR\fB\&.replacement\fR
+\fIsolutionelement\fR\fB\&.replacement\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The solvable that needs to be installed to fix the problem\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint jobidx;\fR                             /* read only */
+\fI$solutionelement\fR\fB\->{jobidx}\fR
+\fIsolutionelement\fR\fB\&.jobidx\fR
+\fIsolutionelement\fR\fB\&.jobidx\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The index of the job that needs to be removed to fix the problem, or \-1 if the element is of another type\&. Note that it\(cqs better to change the job to SOLVER_NOOP type so that the numbering of other elements does not get disturbed\&. This method works both for types SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolutionelement *replaceelements()\fR
+my \fI@solutionelements\fR \fB=\fR \fI$solutionelement\fR\fB\->replaceelements()\fR;
+\fIsolutionelements\fR \fB=\fR \fIsolutionelement\fR\fB\&.replaceelements()\fR
+\fIsolutionelements\fR \fB=\fR \fIsolutionelement\fR\fB\&.replaceelements()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+If the solution element is of type SOLVER_SOLUTION_REPLACE, return an array of elements describing the policy mismatches, otherwise return a copy of the element\&. See also the \(lqexpandreplaces\(rq option in the solution\(cqs elements() method\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint illegalreplace()\fR
+my \fI$illegal\fR \fB=\fR \fI$solutionelement\fR\fB\->illegalreplace()\fR;
+\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.illegalreplace()\fR
+\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.illegalreplace()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return an integer that contains the policy mismatch bits or\-ed together, or zero if there was no policy mismatch\&. See the policy error constants in the solver class\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBJob Job()\fR
+my \fI$job\fR \fB=\fR \fI$solutionelement\fR\fB\->Job()\fR;
+\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.Job()\fR
+\fIillegal\fR \fB=\fR \fIsolutionelement\fR\fB\&.Job()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a job that implements the solution element\&. Add this job to the array of jobs for all elements of type different to SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB\&. For the latter two, a SOLVER_NOOB Job is created, you should replace the old job with the new one\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *str()\fR
+my \fI$str\fR \fB=\fR \fI$solutionelement\fR\fB\->str()\fR;
+\fIstr\fR \fB=\fR \fIsolutionelement\fR\fB\&.str()\fR
+\fIstr\fR \fB=\fR \fIsolutionelement\fR\fB\&.str()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A string describing the change the solution element consists of\&.
+.SH "THE TRANSACTION CLASS"
+.sp
+Transactions describe the output of a solver run\&. A transaction contains a number of transaction elements, each either the installation of a new package or the removal of an already installed package\&. The Transaction class supports a classify() method that puts the elements into different groups so that a transaction can be presented to the user in a meaningful way\&.
+.SS "CONSTANTS"
+.sp
+Transaction element types, both active and passive
+.PP
+\fBSOLVER_TRANSACTION_IGNORE\fR
+.RS 4
+This element does nothing\&. Used to map element types that do not match the view mode\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_INSTALL\fR
+.RS 4
+This element installs a package\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_ERASE\fR
+.RS 4
+This element erases a package\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_MULTIINSTALL\fR
+.RS 4
+This element installs a package with a different version keeping the other versions installed\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_MULTIREINSTALL\fR
+.RS 4
+This element reinstalls an installed package keeping the other versions installed\&.
+.RE
+.sp
+Transaction element types, active view
+.PP
+\fBSOLVER_TRANSACTION_REINSTALL\fR
+.RS 4
+This element re\-installs a package, i\&.e\&. installs the same package again\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_CHANGE\fR
+.RS 4
+This element installs a package with same name, version, architecture but different content\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_UPGRADE\fR
+.RS 4
+This element installs a newer version of an installed package\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_DOWNGRADE\fR
+.RS 4
+This element installs an older version of an installed package\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_OBSOLETES\fR
+.RS 4
+This element installs a package that obsoletes an installed package\&.
+.RE
+.sp
+Transaction element types, passive view
+.PP
+\fBSOLVER_TRANSACTION_REINSTALLED\fR
+.RS 4
+This element re\-installs a package, i\&.e\&. installs the same package again\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_CHANGED\fR
+.RS 4
+This element replaces an installed package with one of the same name, version, architecture but different content\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_UPGRADED\fR
+.RS 4
+This element replaces an installed package with a new version\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_DOWNGRADED\fR
+.RS 4
+This element replaces an installed package with an old version\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_OBSOLETED\fR
+.RS 4
+This element replaces an installed package with a package that obsoletes it\&.
+.RE
+.sp
+Pseudo element types for showing extra information used by classify()
+.PP
+\fBSOLVER_TRANSACTION_ARCHCHANGE\fR
+.RS 4
+This element replaces an installed package with a package of a different architecture\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_VENDORCHANGE\fR
+.RS 4
+This element replaces an installed package with a package of a different vendor\&.
+.RE
+.sp
+Transaction mode flags
+.PP
+\fBSOLVER_TRANSACTION_SHOW_ACTIVE\fR
+.RS 4
+Filter for active view types\&. The default is to return passive view type, i\&.e\&. to show how the installed packages get changed\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_SHOW_OBSOLETES\fR
+.RS 4
+Do not map the obsolete view type into INSTALL/ERASE elements\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_SHOW_ALL\fR
+.RS 4
+If multiple packages replace an installed package, only the best of them is kept as OBSOLETE element, the other ones are mapped to INSTALL/ERASE elements\&. This is because most applications want to show just one package replacing the installed one\&. The SOLVER_TRANSACTION_SHOW_ALL makes the library keep all OBSOLETE elements\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_SHOW_MULTIINSTALL\fR
+.RS 4
+The library maps MULTIINSTALL elements to simple INSTALL elements\&. This flag can be used to disable the mapping\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_CHANGE_IS_REINSTALL\fR
+.RS 4
+Use this flag if you want to map CHANGE elements to the REINSTALL type\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE\fR
+.RS 4
+Use this flag if you want to map OBSOLETE elements to the UPGRADE type\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_MERGE_ARCHCHANGES\fR
+.RS 4
+Do not add extra categories for every architecture change, instead cumulate them in one category\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_MERGE_VENDORCHANGES\fR
+.RS 4
+Do not add extra categories for every vendor change, instead cumulate them in one category\&.
+.RE
+.PP
+\fBSOLVER_TRANSACTION_RPM_ONLY\fR
+.RS 4
+Special view mode that just returns IGNORE, ERASE, INSTALL, MULTIINSTALL elements\&. Useful if you want to find out what to feed to the underlying package manager\&.
+.RE
+.sp
+Transaction order flags
+.PP
+\fBSOLVER_TRANSACTION_KEEP_ORDERDATA\fR
+.RS 4
+Do not throw away the dependency graph used for ordering the transaction\&. This flag is needed if you want to do manual ordering\&.
+.RE
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool;\fR                             /* read only */
+\fI$trans\fR\fB\->{pool}\fR
+\fItrans\fR\fB\&.pool\fR
+\fItrans\fR\fB\&.pool\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to pool\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool isempty()\fR;
+\fI$trans\fR\fB\->isempty()\fR
+\fItrans\fR\fB\&.isempty()\fR
+\fItrans\fR\fB\&.isempty?\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Returns true if the transaction does not do anything, i\&.e\&. has no elements\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *newsolvables()\fR;
+my \fI@newsolvables\fR \fB=\fR \fI$trans\fR\fB\->newsolvables()\fR;
+\fInewsolvables\fR \fB=\fR \fItrans\fR\fB\&.newsolvables()\fR
+\fInewsolvables\fR \fB=\fR \fItrans\fR\fB\&.newsolvables()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all packages that are to be installed by the transaction\&. These are the packages that need to be downloaded from the repositories\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *keptsolvables()\fR;
+my \fI@keptsolvables\fR \fB=\fR \fI$trans\fR\fB\->keptsolvables()\fR;
+\fIkeptsolvables\fR \fB=\fR \fItrans\fR\fB\&.keptsolvables()\fR
+\fIkeptsolvables\fR \fB=\fR \fItrans\fR\fB\&.keptsolvables()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all installed packages that the transaction will keep installed\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *steps()\fR;
+my \fI@steps\fR \fB=\fR \fI$trans\fR\fB\->steps()\fR;
+\fIsteps\fR \fB=\fR \fItrans\fR\fB\&.steps()\fR
+\fIsteps\fR \fB=\fR \fItrans\fR\fB\&.steps()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all solvables that need to be installed (if the returned solvable is not already installed) or erased (if the returned solvable is installed)\&. A step is also called a transaction element\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint steptype(Solvable *\fR\fIsolvable\fR\fB, int\fR \fImode\fR\fB)\fR
+my \fI$type\fR \fB=\fR \fI$trans\fR\fB\->steptype(\fR\fI$solvable\fR\fB,\fR \fI$mode\fR\fB)\fR;
+\fItype\fR \fB=\fR \fItrans\fR\fB\&.steptype(\fR\fIsolvable\fR\fB,\fR \fImode\fR\fB)\fR
+\fItype\fR \fB=\fR \fItrans\fR\fB\&.steptype(\fR\fIsolvable\fR\fB,\fR \fImode\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the transaction type of the specified solvable\&. See the CONSTANTS sections for the mode argument flags and the list of returned types\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBTransactionClass *classify(int\fR \fImode\fR \fB= 0)\fR
+my \fI@classes\fR \fB=\fR \fI$trans\fR\fB\->classify()\fR;
+\fIclasses\fR \fB=\fR \fItrans\fR\fB\&.classify()\fR
+\fIclasses\fR \fB=\fR \fItrans\fR\fB\&.classify()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Group the transaction elements into classes so that they can be displayed in a structured way\&. You can use various mapping mode flags to tweak the result to match your preferences, see the mode argument flag in the CONSTANTS section\&. See the TransactionClass class for how to deal with the returned objects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable othersolvable(Solvable *\fR\fIsolvable\fR\fB)\fR;
+my \fI$other\fR \fB=\fR \fI$trans\fR\fB\->othersolvable(\fR\fI$solvable\fR\fB)\fR;
+\fIother\fR \fB=\fR \fItrans\fR\fB\&.othersolvable(\fR\fIsolvable\fR\fB)\fR
+\fIother\fR \fB=\fR \fItrans\fR\fB\&.othersolvable(\fR\fIsolvable\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the \(lqother\(rq solvable for a given solvable\&. For installed packages the other solvable is the best package with the same name that replaces the installed package, or the best package of the obsoleting packages if the package does not get replaced by one with the same name\&.
+.sp
+For to be installed packages, the \(lqother\(rq solvable is the best installed package with the same name that will be replaced, or the best packages of all the packages that are obsoleted if the new package does not replace a package with the same name\&.
+.sp
+Thus, the \(lqother\(rq solvable is normally the package that is also shown for a given package\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *allothersolvables(Solvable *\fR\fIsolvable\fR\fB)\fR;
+my \fI@others\fR \fB=\fR \fI$trans\fR\fB\->allothersolvables(\fR\fI$solvable\fR\fB)\fR;
+\fIothers\fR \fB=\fR \fItrans\fR\fB\&.allothersolvables(\fR\fIsolvable\fR\fB)\fR
+\fIothers\fR \fB=\fR \fItrans\fR\fB\&.allothersolvables(\fR\fIsolvable\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+For installed packages, returns all of the packages that replace us\&. For to be installed packages, returns all of the packages that the new package replaces\&. The special \(lqother\(rq solvable is always the first entry of the returned array\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBlong long calc_installsizechange()\fR;
+my \fI$change\fR \fB=\fR \fI$trans\fR\fB\->calc_installsizechange()\fR;
+\fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR
+\fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the size change of the installed system in kilobytes (kibibytes)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid order(int\fR \fIflags\fR \fB= 0)\fR;
+\fI$trans\fR\fB\->order()\fR;
+\fItrans\fR\fB\&.order()\fR
+\fItrans\fR\fB\&.order()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Order the steps in the transactions so that dependent packages are updated before packages that depend on them\&. For rpm, you can also use rpmlib\(cqs ordering functionality, debian\(cqs dpkg does not provide a way to order a transaction\&.
+.SS "ACTIVE/PASSIVE VIEW"
+.sp
+Active view lists what new packages get installed, while passive view shows what happens to the installed packages\&. Most often there\(cqs not much difference between the two modes, but things get interesting if multiple packages get replaced by one new package\&. Say you have installed packages A\-1\-1 and B\-1\-1, and now install A\-2\-1 which has a new dependency that obsoletes B\&. The transaction elements will be
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+updated   A\-1\-1 (other: A\-2\-1)
+obsoleted B\-1\-1 (other: A\-2\-1)
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+in passive mode, but
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+update A\-2\-1 (other: A\-1\-1)
+erase  B
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+in active mode\&. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the passive mode list will be unchanged but the active mode list will just contain A\-2\-1\&.
+.SH "THE TRANSACTIONCLASS CLASS"
+.sp
+Objects of this type are returned by the classify() Transaction method\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBTransaction *transaction;\fR               /* read only */
+\fI$class\fR\fB\->{transaction}\fR
+\fIclass\fR\fB\&.transaction\fR
+\fIclass\fR\fB\&.transaction\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to transaction object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint type;\fR                               /* read only */
+\fI$class\fR\fB\->{type}\fR
+\fIclass\fR\fB\&.type\fR
+\fIclass\fR\fB\&.type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The type of the transaction elements in the class\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint count;\fR                              /* read only */
+\fI$class\fR\fB\->{count}\fR
+\fIclass\fR\fB\&.count\fR
+\fIclass\fR\fB\&.count\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The number of elements in the class\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *\fR\fIfromstr\fR;
+\fI$class\fR\fB\->{fromstr}\fR
+\fIclass\fR\fB\&.fromstr\fR
+\fIclass\fR\fB\&.fromstr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The old vendor or architecture\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *\fR\fItostr\fR;
+\fI$class\fR\fB\->{tostr}\fR
+\fIclass\fR\fB\&.tostr\fR
+\fIclass\fR\fB\&.tostr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The new vendor or architecture\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId\fR \fIfromid\fR;
+\fI$class\fR\fB\->{fromid}\fR
+\fIclass\fR\fB\&.fromid\fR
+\fIclass\fR\fB\&.fromid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of the old vendor or architecture\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId\fR \fItoid\fR;
+\fI$class\fR\fB\->{toid}\fR
+\fIclass\fR\fB\&.toid\fR
+\fIclass\fR\fB\&.toid\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of the new vendor or architecture\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid solvables()\fR;
+my \fI@solvables\fR \fB=\fR \fI$class\fR\fB\->solvables()\fR;
+\fIsolvables\fR \fB=\fR \fIclass\fR\fB\&.solvables()\fR
+\fIsolvables\fR \fB=\fR \fIclass\fR\fB\&.solvables()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the solvables for all transaction elements in the class\&.
+.SH "CHECKSUMS"
+.sp
+Checksums (also called hashes) are used to make sure that downloaded data is not corrupt and also as a fingerprint mechanism to check if data has changed\&.
+.SS "CLASS METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum Chksum(Id\fR \fItype\fR\fB)\fR
+my \fI$chksum\fR \fB= solv::Chksum\->new(\fR\fI$type\fR\fB)\fR;
+\fIchksum\fR \fB= solv\&.Chksum(\fR\fItype\fR\fB)\fR
+\fIchksum\fR \fB= Solv::Chksum\&.new(\fR\fItype\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a checksum object\&. Currently the following types are supported:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBREPOKEY_TYPE_MD5\fR
+\fBREPOKEY_TYPE_SHA1\fR
+\fBREPOKEY_TYPE_SHA256\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+These keys are constants in the \fBsolv\fR class\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum Chksum(Id\fR \fItype\fR\fB, const char *\fR\fIhex\fR\fB)\fR
+my \fI$chksum\fR \fB= solv::Chksum\->new(\fR\fI$type\fR\fB,\fR \fI$hex\fR\fB)\fR;
+\fIchksum\fR \fB= solv\&.Chksum(\fR\fItype\fR\fB,\fR \fIhex\fR\fB)\fR
+\fIchksum\fR \fB= Solv::Chksum\&.new(\fR\fItype\fR\fB,\fR \fIhex\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create an already finalized checksum object from a hex string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum Chksum_from_bin(Id\fR \fItype\fR\fB, char *\fR\fIbin\fR\fB)\fR
+my \fI$chksum\fR \fB= solv::Chksum\->from_bin(\fR\fI$type\fR\fB,\fR \fI$bin\fR\fB)\fR;
+\fIchksum\fR \fB= solv\&.Chksum\&.from_bin(\fR\fItype\fR\fB,\fR \fIbin\fR\fB)\fR
+\fIchksum\fR \fB= Solv::Chksum\&.from_bin(\fR\fItype\fR\fB,\fR \fIbin\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create an already finalized checksum object from a binary checksum\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId type;\fR                        /* read only */
+\fI$chksum\fR\fB\->{type}\fR
+\fIchksum\fR\fB\&.type\fR
+\fIchksum\fR\fB\&.type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the type of the checksum object\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add(const char *\fR\fIstr\fR\fB)\fR
+\fI$chksum\fR\fB\->add(\fR\fI$str\fR\fB)\fR;
+\fIchksum\fR\fB\&.add(\fR\fIstr\fR\fB)\fR
+\fIchksum\fR\fB\&.add(\fR\fIstr\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a (binary) string to the checksum\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_fp(FILE *\fR\fIfp\fR\fB)\fR
+\fI$chksum\fR\fB\->add_fp(\fR\fI$file\fR\fB)\fR;
+\fIchksum\fR\fB\&.add_fp(\fR\fIfile\fR\fB)\fR
+\fIchksum\fR\fB\&.add_fp(\fR\fIfile\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of a file to the checksum\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_stat(const char *\fR\fIfilename\fR\fB)\fR
+\fI$chksum\fR\fB\->add_stat(\fR\fI$filename\fR\fB)\fR;
+\fIchksum\fR\fB\&.add_stat(\fR\fIfilename\fR\fB)\fR
+\fIchksum\fR\fB\&.add_stat(\fR\fIfilename\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Stat the file and add the dev/ino/size/mtime member to the checksum\&. If the stat fails, the members are zeroed\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_fstat(int\fR \fIfd\fR\fB)\fR
+\fI$chksum\fR\fB\->add_fstat(\fR\fI$fd\fR\fB)\fR;
+\fIchksum\fR\fB\&.add_fstat(\fR\fIfd\fR\fB)\fR
+\fIchksum\fR\fB\&.add_fstat(\fR\fIfd\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as add_stat, but instead of the filename a file descriptor is used\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned char *raw()\fR
+my \fI$raw\fR \fB=\fR \fI$chksum\fR\fB\->raw()\fR;
+\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.raw()\fR
+\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.raw()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Finalize the checksum and return the result as raw bytes\&. This means that the result can contain NUL bytes or unprintable characters\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *hex()\fR
+my \fI$raw\fR \fB=\fR \fI$chksum\fR\fB\->hex()\fR;
+\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.hex()\fR
+\fIraw\fR \fB=\fR \fIchksum\fR\fB\&.hex()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Finalize the checksum and return the result as hex string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *typestr()\fR
+my \fI$typestr\fR \fB=\fR \fI$chksum\fR\fB\->typestr()\fR;
+\fItypestr\fR \fB=\fR \fIchksum\fR\fB\&.typestr\fR
+\fItypestr\fR \fB=\fR \fIchksum\fR\fB\&.typestr\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the type of the checksum as a string, e\&.g\&. "sha256"\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$chksum1\fR \fB==\fR \fI$chksum2\fR\fB)\fR
+\fBif\fR \fIchksum1\fR \fB==\fR \fIchksum2\fR\fB:\fR
+\fBif\fR \fIchksum1\fR \fB==\fR \fIchksum2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Checksums are equal if they are of the same type and the finalized results are the same\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<stringification>\fR
+my \fI$str\fR \fB=\fR \fI$chksum\fR\fB\->str\fR;
+\fIstr\fR \fB= str(\fR\fIchksum\fR\fB)\fR
+\fIstr\fR \fB=\fR \fIchksum\fR\fB\&.to_s\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+If the checksum is finished, the checksum is returned as "<type>:<hex>" string\&. Otherwise "<type>:unfinished" is returned\&.
+.SH "FILE MANAGEMENT"
+.sp
+This functions were added because libsolv uses standard \fBFILE\fR pointers to read/write files, but languages like perl have their own implementation of files\&. The libsolv functions also support decompression and compression, the algorithm is selected by looking at the file name extension\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBFILE *xfopen(char *\fR\fIfn\fR\fB, char *\fR\fImode\fR \fB= "r")\fR
+my \fI$file\fR \fB= solv::xfopen(\fR\fI$path\fR\fB)\fR;
+\fIfile\fR \fB= solv\&.xfopen(\fR\fIpath\fR\fB)\fR
+\fIfile\fR \fB= Solv::xfopen(\fR\fIpath\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Open a file at the specified path\&. The mode argument is passed on to the stdio library\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBFILE *xfopen_fd(char *\fR\fIfn\fR\fB, int\fR \fIfileno\fR\fB)\fR
+my \fI$file\fR \fB= solv::xfopen_fd(\fR\fI$path\fR\fB,\fR \fI$fileno\fR\fB)\fR;
+\fIfile\fR \fB= solv\&.xfopen_fd(\fR\fIpath\fR\fB,\fR \fIfileno\fR\fB)\fR
+\fIfile\fR \fB= Solv::xfopen_fd(\fR\fIpath\fR\fB,\fR \fIfileno\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a file handle from the specified file descriptor\&. The path argument is only used to select the correct (de\-)compression algorithm, use an empty path if you want to make sure to read/write raw data\&. The file descriptor is dup()ed before the file handle is created\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint fileno()\fR
+my \fI$fileno\fR \fB=\fR \fI$file\fR\fB\->fileno()\fR;
+\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.fileno()\fR
+\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.fileno()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return file file descriptor of the file\&. If the file is not open, \-1 is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid cloexec(bool\fR \fIstate\fR\fB)\fR
+\fI$file\fR\fB\->cloexec(\fR\fI$state\fR\fB)\fR
+\fIfile\fR\fB\&.cloexec(\fR\fIstate\fR\fB)\fR
+\fIfile\fR\fB\&.cloexec(\fR\fIstate\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the close\-on\-exec flag of the file descriptor\&. The xfopen function returns files with close\-on\-exec turned on, so if you want to pass a file to some other process you need to call cloexec(0) before calling exec\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint dup()\fR
+my \fI$fileno\fR \fB=\fR \fI$file\fR\fB\->dup()\fR;
+\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.dup()\fR
+\fIfileno\fR \fB=\fR \fIfile\fR\fB\&.dup()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a copy of the descriptor of the file\&. If the file is not open, \-1 is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool flush()\fR
+\fI$file\fR\fB\->flush()\fR;
+\fIfile\fR\fB\&.flush()\fR
+\fIfile\fR\fB\&.flush()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Flush the file\&. Returns false if there was an error\&. Flushing a closed file always returns true\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool close()\fR
+\fI$file\fR\fB\->close()\fR;
+\fIfile\fR\fB\&.close()\fR
+\fIfile\fR\fB\&.close()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Close the file\&. This is needed for languages like Ruby that do not destruct objects right after they are no longer referenced\&. In that case, it is good style to close open files so that the file descriptors are freed right away\&. Returns false if there was an error\&.
+.SH "THE REPODATA CLASS"
+.sp
+The Repodata stores attributes for packages and the repository itself, each repository can have multiple repodata areas\&. You normally only need to directly access them if you implement lazy downloading of repository data\&. Repodata areas are created by calling the repository\(cqs add_repodata() method or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING flag\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo *repo;\fR                     /* read only */
+\fI$data\fR\fB\->{repo}\fR
+\fIdata\fR\fB\&.repo\fR
+\fIdata\fR\fB\&.repo\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to repository object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId id;\fR                                  /* read only */
+\fI$data\fR\fB\->{id}\fR
+\fIdata\fR\fB\&.id\fR
+\fIdata\fR\fB\&.id\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The id of the repodata area\&. Repodata ids of different repositories overlap\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBinternalize()\fR;
+\fI$data\fR\fB\->internalize()\fR;
+\fIdata\fR\fB\&.internalize()\fR
+\fIdata\fR\fB\&.internalize()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Internalize newly added data\&. The lookup functions will only see the new data after it has been internalized\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool write(FILE *\fR\fIfp\fR\fB)\fR;
+\fI$data\fR\fB\->write(\fR\fI$fp\fR\fB)\fR;
+\fIdata\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
+\fIdata\fR\fB\&.write(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Write the contents of the repodata area as solv file\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId str2dir(const char *\fR\fIdir\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$did\fR \fB=\fR \fIdata\fR\fB\->str2dir(\fR\fI$dir\fR\fB)\fR;
+\fIdid\fR \fB=\fR \fIdata\fR\fB\&.str2dir(\fR\fIdir\fR\fB)\fR
+\fIdid\fR \fB=\fR \fIdata\fR\fB\&.str2dir(\fR\fIdir\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *dir2str(Id\fR \fIdid\fR\fB, const char *\fR\fIsuffix\fR \fB= 0)\fR
+\fI$dir\fR \fB=\fR \fIpool\fR\fB\->dir2str(\fR\fI$did\fR\fB)\fR;
+\fIdir\fR \fB=\fR \fIpool\fR\fB\&.dir2str(\fR\fIdid\fR\fB)\fR
+\fIdir\fR \fB=\fR \fIpool\fR\fB\&.dir2str(\fR\fIdid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a string (directory) into an Id and back\&. If the string is currently not in the pool and \fIcreate\fR is false, zero is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_dirstr(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fIdir\fR\fB, const char *\fR\fIstr\fR\fB)\fR
+\fI$data\fR\fB\->add_dirstr(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$dir\fR\fB,\fR \fI$string\fR\fB)\fR
+\fIdata\fR\fB\&.add_dirstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIdir\fR\fB,\fR \fIstring\fR\fB)\fR
+\fIdata\fR\fB\&.add_dirstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIdir\fR\fB,\fR \fIstring\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a file path consisting of a dirname Id and a basename string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR;
+\fI$data\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR;
+\fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
+\fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Replace a stub repodata object with the data from a solv file\&. This method automatically adds the REPO_USE_LOADING flag\&. It should only be used from a load callback\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid create_stubs()\fR;
+\fI$data\fR\fB\->create_stubs()\fR
+\fIdata\fR\fB\&.create_stubs()\fR
+\fIdata\fR\fB\&.create_stubs()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create stub repodatas from the information stored in the repodata meta area\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid extend_to_repo()\fR;
+\fI$data\fR\fB\->extend_to_repo()\fR;
+\fIdata\fR\fB\&.extend_to_repo()\fR
+\fIdata\fR\fB\&.extend_to_repo()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Extend the repodata so that it has the same size as the repo it belongs to\&. This method is needed when setting up a new extension repodata so that it matches the repository size\&. It is also needed when switching to a just written repodata extension to make the repodata match the written extension (which is always of the size of the repo)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB<equality>\fR
+\fBif (\fR\fI$data1\fR \fB==\fR \fI$data2\fR\fB)\fR
+\fBif\fR \fIdata1\fR \fB==\fR \fIdata2\fR\fB:\fR
+\fBif\fR \fIdata1\fR \fB==\fR \fIdata2\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Two repodata objects are equal if they belong to the same repository and have the same id\&.
+.SS "DATA RETRIEVAL METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
+my \fI$num\fR \fB=\fR \fI$data\fR\fB\->lookup_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fInum\fR \fB=\fR \fIdata\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fInum\fR \fB=\fR \fIdata\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool lookup_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$bool\fR \fB=\fR \fI$data\fR\fB\->lookup_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIbool\fR \fB=\fR \fIdata\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIbool\fR \fB=\fR \fIdata\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *lookup_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI@ids\fR \fB=\fR \fI$data\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum lookup_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$chksum\fR \fB=\fR \fI$data\fR\fB\->lookup_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIchksum\fR \fB=\fR \fIdata\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIchksum\fR \fB=\fR \fIdata\fR\fB\&.lookup_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Lookup functions\&. Return the data element stored in the specified solvable\&. The methods probably only make sense to retrieve data from the special SOLVID_META solvid that stores repodata meta information\&.
+.SS "DATA STORAGE METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR;
+\fI$data\fR\fB\->set_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR;
+\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR;
+\fI$data\fR\fB\->set_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR;
+\fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
+\fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInum\fR\fB)\fR;
+\fI$data\fR\fB\->set_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$num\fR\fB)\fR;
+\fIdata\fR\fB\&.set_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fInum\fR\fB)\fR
+\fIdata\fR\fB\&.set_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fInum\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+\fI$data\fR\fB\->set_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIdata\fR\fB\&.set_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIdata\fR\fB\&.set_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_poolstr(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR;
+\fI$data\fR\fB\->set_poolstr(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR;
+\fIdata\fR\fB\&.set_poolstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+\fIdata\fR\fB\&.set_poolstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_checksum(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Chksum *\fR\fIchksum\fR\fB)\fR;
+\fI$data\fR\fB\->set_checksum(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$chksum\fR\fB)\fR;
+\fIdata\fR\fB\&.set_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIchksum\fR\fB)\fR
+\fIdata\fR\fB\&.set_checksum(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIchksum\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_sourcepkg(Id\fR \fIsolvid\fR\fB, const char *\fR\fIsourcepkg\fR\fB)\fR;
+\fI$data\fR\fB\&.set_sourcepkg(\fR\fI$solvid\fR\fB,\fR \fI$sourcepkg\fR\fB)\fR;
+\fIdata\fR\fB\&.set_sourcepkg(\fR\fIsolvid\fR\fB,\fR \fIsourcepkg\fR\fB)\fR
+\fIdata\fR\fB\&.set_sourcepkg(\fR\fIsolvid\fR\fB,\fR \fIsourcepkg\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_location(Id\fR \fIsolvid\fR\fB, unsigned int\fR \fImediano\fR\fB, const char *\fR\fIlocation\fR\fB)\fR;
+\fI$data\fR\fB\&.set_location(\fR\fI$solvid\fR\fB,\fR \fI$mediano\fR\fB,\fR \fI$location\fR\fB)\fR;
+\fIdata\fR\fB\&.set_location(\fR\fIsolvid\fR\fB,\fR \fImediano\fR\fB,\fR \fIlocation\fR\fB)\fR
+\fIdata\fR\fB\&.set_location(\fR\fIsolvid\fR\fB,\fR \fImediano\fR\fB,\fR \fIlocation\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR;
+\fI$data\fR\fB\->add_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR;
+\fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
+\fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId new_handle()\fR;
+my \fI$handle\fR \fB=\fR \fI$data\fR\fB\->new_handle()\fR;
+\fIhandle\fR \fB=\fR \fIdata\fR\fB\&.new_handle()\fR
+\fIhandle\fR \fB=\fR \fIdata\fR\fB\&.new_handle()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_flexarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fIhandle\fR\fB)\fR;
+\fI$data\fR\fB\->add_flexarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$handle\fR\fB)\fR;
+\fIdata\fR\fB\&.add_flexarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIhandle\fR\fB)\fR
+\fIdata\fR\fB\&.add_flexarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIhandle\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid unset(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+\fI$data\fR\fB\->unset(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIdata\fR\fB\&.unset(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIdata\fR\fB\&.unset(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Data storage methods\&. Probably only useful to store data in the special SOLVID_META solvid that stores repodata meta information\&. Note that repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag), so be careful if you need to store ids\&. Arrays are created by calling the add function for every element\&. A flexarray is an array of sub\-structures, call new_handle to create a new structure, use the handle as solvid to fill the structure with data and call add_flexarray to put the structure in an array\&.
+.SH "THE DATAPOS CLASS"
+.sp
+Datapos objects describe a specific position in the repository data area\&. Thus they are only valid until the repository is modified in some way\&. Datapos objects can be created by the pos() and parentpos() methods of a Datamatch object or by accessing the \(lqmeta\(rq attribute of a repository\&.
+.SS "ATTRIBUTES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBRepo *repo;\fR                     /* read only */
+\fI$data\fR\fB\->{repo}\fR
+\fIdata\fR\fB\&.repo\fR
+\fIdata\fR\fB\&.repo\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Back pointer to repository object\&.
+.SS "METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR
+my \fI$di\fR \fB=\fR \fI$datapos\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a Dataiterator at the position of the datapos object\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_deltalocation(unsigned int *\fR\fIOUTPUT\fR\fB)\fR;
+my \fB(\fR\fI$location\fR\fB,\fR \fI$mediano\fR\fB) =\fR \fI$datapos\fR\fB\->lookup_deltalocation()\fR;
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a tuple containing the on\-media location and an optional media number for a delta rpm\&. This obviously only works if the data position points to structure describing a delta rpm\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_deltaseq()\fR;
+my \fI$seq\fR \fB=\fR \fI$datapos\fR\fB\->lookup_deltaseq()\fR;
+\fIseq\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltaseq()\fR;
+\fIseq\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltaseq()\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the delta rpm sequence from the structure describing a delta rpm\&.
+.SS "DATA RETRIEVAL METHODS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *lookup_str(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$string\fR \fB=\fR \fI$datapos\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_str(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$id\fR \fB=\fR \fI$datapos\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR;
+\fIid\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
+\fIid\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long lookup_num(Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
+my \fI$num\fR \fB=\fR \fI$datapos\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR;
+\fInum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
+\fInum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool lookup_void(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$bool\fR \fB=\fR \fI$datapos\fR\fB\->lookup_void(\fR\fI$keyname\fR\fB)\fR;
+\fIbool\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
+\fIbool\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_void(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *lookup_idarray(Id\fR \fIkeyname\fR\fB)\fR
+my \fI@ids\fR \fB=\fR \fI$datapos\fR\fB\->lookup_idarray(\fR\fI$keyname\fR\fB)\fR;
+\fIids\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
+\fIids\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_idarray(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBChksum lookup_checksum(Id\fR \fIkeyname\fR\fB)\fR
+my \fI$chksum\fR \fB=\fR \fI$datapos\fR\fB\->lookup_checksum(\fR\fI$keyname\fR\fB)\fR;
+\fIchksum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
+\fIchksum\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_checksum(\fR\fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Lookup functions\&. Note that the returned Ids are always translated into the Ids of the global pool even if the repodata area contains its own pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBDataiterator Dataiterator(Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR \fB= 0, int\fR \fIflags\fR \fB= 0)\fR
+my \fI$di\fR \fB=\fR \fI$datapos\fR\fB\->Dataiterator(\fR\fI$keyname\fR\fB,\fR \fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIdi\fR \fB=\fR \fIdatapos\fR\fB\&.Dataiterator(\fR\fIkeyname\fR\fB,\fR \fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfor my\fR \fI$d\fR \fB(\fR\fI@$di\fR\fB)\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR\fB:\fR
+\fBfor\fR \fId\fR \fBin\fR \fIdi\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Iterate over the matching data elements\&. See the Dataiterator class for more information\&.
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/libsolv-constantids.3 b/libsolv-0.7.2/doc/gen/libsolv-constantids.3
new file mode 100644 (file)
index 0000000..228dfdd
--- /dev/null
@@ -0,0 +1,906 @@
+'\" t
+.\"     Title: Libsolv-Constantids
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "LIBSOLV\-CONSTANTIDS" "3" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libsolv-constantids \- fixed Ids for often used strings
+.SH "DESCRIPTION"
+.sp
+Constant Ids are Ids of strings that are often needed\&. They are defined to ease programming and reduce the number of pool_str2id calls\&. The constant Ids are part of the binary ABI of libsolv, a minor version update will only add new constants and not change existing Ids to maintain compatible\&. The on\-disk solv format works does not use the fixed Ids, but instead references the strings, so solv files can still be read when the ABI is broken\&.
+.SH "SPECIAL STRINGS"
+.PP
+\fBID_EMPTY ""\fR
+.RS 4
+The empty string\&. It will always have Id 1\&.
+.RE
+.PP
+\fBSYSTEM_SYSTEM "system:system"\fR
+.RS 4
+The name of the always installed "system" solvable\&.
+.RE
+.SH "SOLVABLE ATTRIBUTES"
+.sp
+These are Ids for keyname of attributes\&. They can be used in the lookup and storage functions to select the correct attribute in the solvable\&. The descriptions below describe the intended semantics of the values stored in the attribute with the keyname\&.
+.PP
+\fBSOLVABLE_NAME "solvable:name"\fR
+.RS 4
+The name of the package\&.
+.RE
+.PP
+\fBSOLVABLE_ARCH "solvable:arch"\fR
+.RS 4
+The architecture of the package\&. See the Solvable Architecture section for predefined architecture Id values\&.
+.RE
+.PP
+\fBSOLVABLE_EVR "solvable:evr"\fR
+.RS 4
+The version of the package\&. It usually consists of some combination of the Epoch, the Version, and the Release of the solvable\&.
+.RE
+.PP
+\fBSOLVABLE_VENDOR "solvable:vendor"\fR
+.RS 4
+A vendor string\&. Usually the company or group that created the binary package\&.
+.RE
+.PP
+\fBSOLVABLE_PROVIDES "solvable:provides"\fR
+.RS 4
+Stores an array of dependency Ids that describe the capabilities that the package provides\&.
+.RE
+.PP
+\fBSOLVABLE_OBSOLETES "solvable:obsoletes"\fR
+.RS 4
+Stores an array of dependency Ids that describe the packages that this package replaces\&.
+.RE
+.PP
+\fBSOLVABLE_CONFLICTS "solvable:conflicts"\fR
+.RS 4
+Stores an array of dependency Ids that describe the capabilities that this package conflicts with, i\&.e\&. that can\(cqt be installed together with this package\&.
+.RE
+.PP
+\fBSOLVABLE_REQUIRES "solvable:requires"\fR
+.RS 4
+Stores an array of dependency Ids that describe the capabilities that also must be installed when this package is installed\&.
+.RE
+.PP
+\fBSOLVABLE_RECOMMENDS "solvable:recommends"\fR
+.RS 4
+Stores an array of dependency Ids that describe the capabilities that also should be installed when this package is installed\&. It\(cqs not an error if not all capabilities can be met\&.
+.RE
+.PP
+\fBSOLVABLE_SUGGESTS "solvable:suggests"\fR
+.RS 4
+Stores an array of dependency Ids that describe the capabilities that also useful to have installed when this package is installed\&. This is intended to provide a hint to the user about other packages\&.
+.RE
+.PP
+\fBSOLVABLE_SUPPLEMENTS "solvable:supplements"\fR
+.RS 4
+Stores an array of dependency Ids that define that this package should be installed if one of the capabilities is met\&. This is like the recommends attribute, but works in the reverse way\&.
+.RE
+.PP
+\fBSOLVABLE_ENHANCES "solvable:enhances"\fR
+.RS 4
+Stores an array of dependency Ids that define that this package is useful to have installed if one of the capabilities is met\&. This is like the suggests attribute, but works in the reverse way\&.
+.RE
+.PP
+\fBSOLVABLE_SUMMARY "solvable:summary"\fR
+.RS 4
+The summary should be a short string without any newlines that describes what a package does\&.
+.RE
+.PP
+\fBSOLVABLE_DESCRIPTION "solvable:description"\fR
+.RS 4
+The description should be a more verbose description about what a package does\&. It may consist of multiple lines\&.
+.RE
+.PP
+\fBSOLVABLE_DISTRIBUTION "solvable:distribution"\fR
+.RS 4
+The distribution is a short string that describes the OS and OS version this package is built for\&.
+.RE
+.PP
+\fBSOLVABLE_AUTHORS "solvable:authors"\fR
+.RS 4
+A list of authors of this package\&. This attribute was used in SUSE packages\&.
+.RE
+.PP
+\fBSOLVABLE_PACKAGER "solvable:packager"\fR
+.RS 4
+The person who created the binary package, see also the vendor attribute\&.
+.RE
+.PP
+\fBSOLVABLE_GROUP "solvable:group"\fR
+.RS 4
+The package group that this package belongs to\&. See also the keywords attribute\&.
+.RE
+.PP
+\fBSOLVABLE_URL "solvable:url"\fR
+.RS 4
+An URL that points to more information about the package\&.
+.RE
+.PP
+\fBSOLVABLE_KEYWORDS "solvable:keywords"\fR
+.RS 4
+list of keyword string IDs used for tagging this package\&.
+.RE
+.PP
+\fBSOLVABLE_LICENSE "solvable:license"\fR
+.RS 4
+The license(s) of this package\&.
+.RE
+.PP
+\fBSOLVABLE_BUILDTIME "solvable:buildtime"\fR
+.RS 4
+The seconds since the unix epoch when the binary package was created\&.
+.RE
+.PP
+\fBSOLVABLE_BUILDHOST "solvable:buildhost"\fR
+.RS 4
+The name of the host on which the binary package was created\&.
+.RE
+.PP
+\fBSOLVABLE_EULA "solvable:eula"\fR
+.RS 4
+If this attribute is present the user should be asked to accept the end user license agreement before the package gets installed\&.
+.RE
+.PP
+\fBSOLVABLE_CPEID "solvable:cpeid"\fR
+.RS 4
+A Common Platform Enumeration string describes the platform this package is intended for\&. See also the distribution attribute\&.
+.RE
+.PP
+\fBSOLVABLE_MESSAGEINS "solvable:messageins"\fR
+.RS 4
+A message that should be displayed to the user when the package gets installed\&.
+.RE
+.PP
+\fBSOLVABLE_MESSAGEDEL "solvable:messagedel"\fR
+.RS 4
+A message that should be displayed to the user when the package gets erased\&.
+.RE
+.PP
+\fBSOLVABLE_INSTALLSIZE "solvable:installsize"\fR
+.RS 4
+The disk space in bytes needed when installing the package\&.
+.RE
+.PP
+\fBSOLVABLE_DISKUSAGE "solvable:diskusage"\fR
+.RS 4
+A SUSE extension that stores for each directory the needed amount of disk space in kilobytes and inodes\&.
+.RE
+.PP
+\fBSOLVABLE_FILELIST "solvable:filelist"\fR
+.RS 4
+A list of files that the package contains\&.
+.RE
+.PP
+\fBSOLVABLE_INSTALLTIME "solvable:installtime"\fR
+.RS 4
+The seconds since the unix epoch when the binary package was installed on the system\&.
+.RE
+.PP
+\fBSOLVABLE_MEDIADIR "solvable:mediadir"\fR
+.RS 4
+The directory on the repository that contains the package\&. If this attribute is set to void, the package architecture is used as directory\&.
+.RE
+.PP
+\fBSOLVABLE_MEDIAFILE "solvable:mediafile"\fR
+.RS 4
+The filename on the repository that contains the package\&. If this attribute is set to void, the canonical file name of the package is used (i\&.e\&. a combination of the name, version, architecture)\&.
+.RE
+.PP
+\fBSOLVABLE_MEDIANR "solvable:medianr"\fR
+.RS 4
+The media number\&. This is an integer describing on which of a multi\-part media set this package is on\&.
+.RE
+.PP
+\fBSOLVABLE_MEDIABASE "solvable:mediabase"\fR
+.RS 4
+This attribute can be used to overwrite the repositories base url\&.
+.RE
+.PP
+\fBSOLVABLE_DOWNLOADSIZE "solvable:downloadsize"\fR
+.RS 4
+The size of the binary package in bytes\&.
+.RE
+.PP
+\fBSOLVABLE_SOURCEARCH "solvable:sourcearch"\fR
+.RS 4
+The architecture of the source package that this package belongs to\&.
+.RE
+.PP
+\fBSOLVABLE_SOURCENAME "solvable:sourcename"\fR
+.RS 4
+The name of the source package that this package belongs to\&. If set to void, the package name attribute is used instead\&.
+.RE
+.PP
+\fBSOLVABLE_SOURCEEVR "solvable:sourceevr"\fR
+.RS 4
+The version of the source package that this package belongs to\&. If set to void, the package version attribute is used instead\&.
+.RE
+.PP
+\fBSOLVABLE_TRIGGERS "solvable:triggers"\fR
+.RS 4
+A list of package triggers for this package\&. Used in the transaction ordering code\&.
+.RE
+.PP
+\fBSOLVABLE_CHECKSUM "solvable:checksum"\fR
+.RS 4
+The checksum of the binary package\&. See the Data Types section for a list of supported algorithms\&.
+.RE
+.PP
+\fBSOLVABLE_PKGID "solvable:pkgid"\fR
+.RS 4
+A string identifying a package\&. For rpm packages, this is the md5sum over the package header and the payload\&.
+.RE
+.PP
+\fBSOLVABLE_HDRID "solvable:hdrid"\fR
+.RS 4
+A string identifying a package\&. For rpm packages, this is the sha1sum over just the package header\&.
+.RE
+.PP
+\fBSOLVABLE_LEADSIGID "solvable:leadsigid"\fR
+.RS 4
+A string identifying the signature part of a package\&. For rpm packages, this is the md5sum from the start of the file up to the package header (i\&.e\&. it includes the lead, the signature header, and the padding)\&.
+.RE
+.PP
+\fBSOLVABLE_HEADEREND "solvable:headerend"\fR
+.RS 4
+The offset of the payload in rpm binary packages\&. You can use this information to download just the header if you want to display information not included in the repository metadata\&.
+.RE
+.PP
+\fBSOLVABLE_CHANGELOG "solvable:changelog"\fR
+.RS 4
+The array containing all the changelog structures\&.
+.RE
+.PP
+\fBSOLVABLE_CHANGELOG_AUTHOR "solvable:changelog:author"\fR
+.RS 4
+The author of a changelog entry\&.
+.RE
+.PP
+\fBSOLVABLE_CHANGELOG_TIME "solvable:changelog:time"\fR
+.RS 4
+The seconds since the unix epoch when the changelog entry was written\&.
+.RE
+.PP
+\fBSOLVABLE_CHANGELOG_TEXT "solvable:changelog:text"\fR
+.RS 4
+The text of a changelog entry\&.
+.RE
+.SH "SPECIAL SOLVABLE ATTRIBUTES"
+.PP
+\fBRPM_RPMDBID "rpm:dbid"\fR
+.RS 4
+The rpm database id of this (installed) package\&. Usually a small integer number\&.
+.RE
+.PP
+\fBSOLVABLE_PATCHCATEGORY "solvable:patchcategory"\fR
+.RS 4
+The category field for patch solvables\&. Should be named \(lqupdate:category\(rq instead\&.
+.RE
+.PP
+\fBUPDATE_REBOOT "update:reboot"\fR
+.RS 4
+If this attribute is present the system should be rebooted after the update is installed\&.
+.RE
+.PP
+\fBUPDATE_RESTART "update:restart"\fR
+.RS 4
+If this attribute is present the software manager should be run again after the update is installed\&.
+.RE
+.PP
+\fBUPDATE_RELOGIN "update:relogin"\fR
+.RS 4
+If this attribute is present the user should log off and on again after the update is installed\&.
+.RE
+.PP
+\fBUPDATE_MESSAGE "update:message"\fR
+.RS 4
+A message that should be shown to the user to warn him about anything non\-standard\&.
+.RE
+.PP
+\fBUPDATE_SEVERITY "update:severity"\fR
+.RS 4
+The severity of the update\&.
+.RE
+.PP
+\fBUPDATE_RIGHTS "update:rights"\fR
+.RS 4
+Any legal or other rights of the update\&.
+.RE
+.PP
+\fBUPDATE_COLLECTION "update:collection"\fR
+.RS 4
+The array containing the package list of the update\&.
+.RE
+.PP
+\fBUPDATE_COLLECTION_NAME "update:collection:name"\fR
+.RS 4
+The name of the updated package\&.
+.RE
+.PP
+\fBUPDATE_COLLECTION_EVR "update:collection:evr"\fR
+.RS 4
+The version of the updated package\&.
+.RE
+.PP
+\fBUPDATE_COLLECTION_ARCH "update:collection:arch"\fR
+.RS 4
+The architecture of the updated package\&.
+.RE
+.PP
+\fBUPDATE_COLLECTION_FILENAME "update:collection:filename"\fR
+.RS 4
+The file name of the updated package\&.
+.RE
+.PP
+\fBUPDATE_REFERENCE "update:reference"\fR
+.RS 4
+The array containing the reference list of the update\&.
+.RE
+.PP
+\fBUPDATE_REFERENCE_TYPE "update:reference:type"\fR
+.RS 4
+The type of the reference, e\&.g\&. bugzilla\&.
+.RE
+.PP
+\fBUPDATE_REFERENCE_HREF "update:reference:href"\fR
+.RS 4
+The URL of the reference\&.
+.RE
+.PP
+\fBUPDATE_REFERENCE_ID "update:reference:id"\fR
+.RS 4
+The identification string of the reference, e\&.g\&. the bug number\&.
+.RE
+.PP
+\fBUPDATE_REFERENCE_TITLE "update:reference:title"\fR
+.RS 4
+The title of the reference, e\&.g\&. the bug summary\&.
+.RE
+.PP
+\fBPRODUCT_REFERENCEFILE "product:referencefile"\fR
+.RS 4
+The basename of the product file in the package\&.
+.RE
+.PP
+\fBPRODUCT_SHORTLABEL "product:shortlabel"\fR
+.RS 4
+An identification string of the product\&.
+.RE
+.PP
+\fBPRODUCT_DISTPRODUCT "product:distproduct"\fR
+.RS 4
+Obsolete, do not use\&. Was a SUSE Code\-10 product name\&.
+.RE
+.PP
+\fBPRODUCT_DISTVERSION "product:distversion"\fR
+.RS 4
+Obsolete, do not use\&. Was a SUSE Code\-10 product version\&.
+.RE
+.PP
+\fBPRODUCT_TYPE "product:type"\fR
+.RS 4
+The type of the product, e\&.g\&. \(lqbase\(rq\&.
+.RE
+.PP
+\fBPRODUCT_URL "product:url"\fR
+.RS 4
+An array of product URLs\&.
+.RE
+.PP
+\fBPRODUCT_URL_TYPE "product:url:type"\fR
+.RS 4
+An array of product URL types\&.
+.RE
+.PP
+\fBPRODUCT_FLAGS "product:flags"\fR
+.RS 4
+An array of product flags\&.
+.RE
+.PP
+\fBPRODUCT_PRODUCTLINE "product:productline"\fR
+.RS 4
+A product line string used for product registering\&.
+.RE
+.PP
+\fBPRODUCT_REGISTER_TARGET "product:regtarget"\fR
+.RS 4
+A target for product registering\&.
+.RE
+.PP
+\fBPRODUCT_REGISTER_RELEASE "product:regrelease"\fR
+.RS 4
+A release string for product registering\&.
+.RE
+.PP
+\fBPUBKEY_KEYID "pubkey:keyid"\fR
+.RS 4
+The keyid of a pubkey, consisting of 8 bytes in hex\&.
+.RE
+.PP
+\fBPUBKEY_FINGERPRINT "pubkey:fingerprint"\fR
+.RS 4
+The fingerprint of a pubkey, usually a sha1sum in hex\&. Old V3 RSA keys use a md5sum instead\&.
+.RE
+.PP
+\fBPUBKEY_EXPIRES "pubkey:expires"\fR
+.RS 4
+The seconds since the unix epoch when the pubkey expires\&.
+.RE
+.PP
+\fBPUBKEY_SUBKEYOF "pubkey:subkeyof"\fR
+.RS 4
+The keyid of the master pubkey for subkeys\&.
+.RE
+.PP
+\fBPUBKEY_DATA "pubkey:data"\fR
+.RS 4
+The MPI data of the pubkey\&.
+.RE
+.PP
+\fBSOLVABLE_ISVISIBLE "solvable:isvisible"\fR
+.RS 4
+An attribute describing if the package should be listed to the user or not\&. Used for SUSE patterns\&.
+.RE
+.PP
+\fBSOLVABLE_CATEGORY "solvable:category"\fR
+.RS 4
+The category of a pattern\&.
+.RE
+.PP
+\fBSOLVABLE_INCLUDES "solvable:includes"\fR
+.RS 4
+A list of other patterns that this pattern includes\&.
+.RE
+.PP
+\fBSOLVABLE_EXTENDS "solvable:extends"\fR
+.RS 4
+A list of other patterns that this pattern extends\&.
+.RE
+.PP
+\fBSOLVABLE_ICON "solvable:icon"\fR
+.RS 4
+The icon name of a pattern\&.
+.RE
+.PP
+\fBSOLVABLE_ORDER "solvable:order"\fR
+.RS 4
+An ordering clue of a pattern\&.
+.RE
+.PP
+\fBSUSETAGS_SHARE_NAME "susetags:share:name"\fR
+.RS 4
+Internal attribute to implement susetags shared records\&. Holds the name of the solvable used for sharing attributes\&.
+.RE
+.PP
+\fBSUSETAGS_SHARE_EVR "susetags:share:evr"\fR
+.RS 4
+Internal attribute to implement susetags shared records\&. Holds the version of the solvable used for sharing attributes\&.
+.RE
+.PP
+\fBSUSETAGS_SHARE_ARCH "susetags:share:arch"\fR
+.RS 4
+Internal attribute to implement susetags shared records\&. Holds the architecture of the solvable used for sharing attributes\&.
+.RE
+.SH "SOLVABLE ARCHITECTURES"
+.sp
+Predefined architecture values for commonly used architectures\&.
+.PP
+\fBARCH_SRC "src"\fR
+.RS 4
+Used for binary packages that contain the package sources\&.
+.RE
+.PP
+\fBARCH_NOSRC "nosrc"\fR
+.RS 4
+Used for binary packages that contain some of the package sources, but not all files (because of restrictions)\&.
+.RE
+.PP
+\fBARCH_NOARCH "noarch"\fR
+.RS 4
+This package can be installed on any architecture\&. Used for rpm\&.
+.RE
+.PP
+\fBARCH_ALL "all"\fR
+.RS 4
+This package can be installed on any architecture\&. Used for Debian\&.
+.RE
+.PP
+\fBARCH_ANY "any"\fR
+.RS 4
+This package can be installed on any architecture\&. Used for Archlinux and Haiku\&.
+.RE
+.SH "DEPENDENCY IDS"
+.sp
+Namespaces are special modifiers that change the meaning of a dependency\&. Namespace dependencies are created with the REL_NAMESPACE flag\&. To make custom namespaces work you have to implement a namespace callback function\&.
+.sp
+The dependency markers partition the dependency array in two parts with different semantics\&.
+.PP
+\fBNAMESPACE_MODALIAS "namespace:modalias"\fR
+.RS 4
+The dependency is a special modalias dependency that matches installed hardware\&.
+.RE
+.PP
+\fBNAMESPACE_SPLITPROVIDES "namespace:splitprovides"\fR
+.RS 4
+The dependency is a special splitprovides dependency used to implement updates that include a package split\&. A splitprovides dependency contains a filename and a package name, it is matched if a package with the provided package name is installed that contains the filename\&. This namespace is implemented in libsolv, so you do not need a callback\&.
+.RE
+.PP
+\fBNAMESPACE_LANGUAGE "namespace:language"\fR
+.RS 4
+The dependency describes a language\&. The callback should return true if the language was selected by the user\&.
+.RE
+.PP
+\fBNAMESPACE_FILESYSTEM "namespace:filesystem"\fR
+.RS 4
+The dependency describes a filesystem\&. The callback should return true if the filesystem is needed\&.
+.RE
+.PP
+\fBNAMESPACE_OTHERPROVIDERS "namespace:otherproviders"\fR
+.RS 4
+This is a hack to allow self\-conflicting packages\&. It is not needed with current rpm version, so do not use this namespace\&.
+.RE
+.PP
+\fBSOLVABLE_PREREQMARKER "solvable:prereqmarker"\fR
+.RS 4
+This marker partitions the normal require dependencies from the prerequires\&. It is not needed for dependency solving, but it is used by the transaction ordering algorithm when a dependency cycle needs to be broken (non\-prereq deps get broken first)\&.
+.RE
+.PP
+\fBSOLVABLE_FILEMARKER "solvable:filemarker"\fR
+.RS 4
+This marker partitions the package provides dependencies from the synthetic file provides dependencies added by pool_addfileprovides()\&.
+.RE
+.SH "DATA TYPES"
+.sp
+Each attribute data is stored with a type, so that the lookup functions know how to interpret the data\&. The following types are available:
+.PP
+\fBREPOKEY_TYPE_VOID "repokey:type:void"\fR
+.RS 4
+No data is stored with this attribute\&. Thus you can only test if the attribute exists or not\&. Useful to store boolean values\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_CONSTANT "repokey:type:constant"\fR
+.RS 4
+The data is a constant 32bit number\&. The number is stored in the key area, so using it does not cost extra storage space (but you need the extra key space)\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_CONSTANTID "repokey:type:constantid"\fR
+.RS 4
+The data is a constant Id\&. The Id is stored in the key area, so using it does not cost extra storage space (but you need the extra key space)\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_ID "repokey:type:id"\fR
+.RS 4
+The data is an Id\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_NUM "repokey:type:num"\fR
+.RS 4
+The data is an unsigned 64bit number\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_U32 "repokey:type:num32"\fR
+.RS 4
+The data is an unsigned 32bit number\&. Obsolete, do not use\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_DIR "repokey:type:dir"\fR
+.RS 4
+The data is an Id of a directory\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_STR "repokey:type:str"\fR
+.RS 4
+The data is a regular string\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_BINARY "repokey:type:binary"\fR
+.RS 4
+The data is a binary blob\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_IDARRAY "repokey:type:idarray"\fR
+.RS 4
+The data is an array of non\-zero Ids\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_REL_IDARRAY "repokey:type:relidarray"\fR
+.RS 4
+The data is an array of non\-zero Ids ordered so that it needs less space\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_DIRSTRARRAY "repokey:type:dirstrarray"\fR
+.RS 4
+The data is a tuple consisting of a directory Id and a basename\&. Used to store file names\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_DIRNUMNUMARRAY "repokey:type:dirnumnumarray"\fR
+.RS 4
+The data is a triple consisting of a directory Id and two 32bit unsigned integers\&. Used to store disk usage information\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_MD5 "repokey:type:md5"\fR
+.RS 4
+The data is a binary md5sum\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_SHA1 "repokey:type:sha1"\fR
+.RS 4
+The data is a binary sha1sum\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_SHA256 "repokey:type:sha256"\fR
+.RS 4
+The data is a binary sha256sum\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_FIXARRAY "repokey:type:fixarray"\fR
+.RS 4
+The data is an array of structures that have all the same layout (i\&.e\&. the same keynames and keytypes in the same order)\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_FLEXARRAY "repokey:type:flexarray"\fR
+.RS 4
+The data is an array of structures that have a different layout\&.
+.RE
+.PP
+\fBREPOKEY_TYPE_DELETED "repokey:type:deleted"\fR
+.RS 4
+The data does not exist\&. Used to mark an attribute that was deleted\&.
+.RE
+.SH "REPOSITORY METADATA"
+.sp
+This attributes contain meta information about the repository\&.
+.PP
+\fBREPOSITORY_SOLVABLES "repository:solvables"\fR
+.RS 4
+This attribute holds the array including all of the solvables\&. It is only used in the on\-disk solv files, internally the solvables are stored in the pool\(cqs solvable array for fast access\&.
+.RE
+.PP
+\fBREPOSITORY_DELTAINFO "repository:deltainfo"\fR
+.RS 4
+This attribute holds the array including all of the delta packages\&.
+.RE
+.PP
+\fBREPOSITORY_EXTERNAL "repository:external"\fR
+.RS 4
+This attribute holds the array including all of the data to construct stub repodata areas to support on\-demand loading of metadata\&.
+.RE
+.PP
+\fBREPOSITORY_KEYS "repository:keys"\fR
+.RS 4
+This should really be named "repository:external:keys", it contains an array if Ids that consists of (keyname, keytype) pairs that describe the keys of the stub\&.
+.RE
+.PP
+\fBREPOSITORY_LOCATION "repository:location"\fR
+.RS 4
+This is used to provide a file name in the stub\&.
+.RE
+.PP
+\fBREPOSITORY_ADDEDFILEPROVIDES "repository:addedfileprovides"\fR
+.RS 4
+This attribute holds an array of filename Ids, that tell the library, that all of the Ids were already added to the solvable provides\&.
+.RE
+.PP
+\fBREPOSITORY_RPMDBCOOKIE "repository:rpmdbcookie"\fR
+.RS 4
+An attribute that stores a sha256sum over the file stats of the Packages database\&. It\(cqs used to detect rebuilds of the database, as in that case the database Ids of every package are newly distributed\&.
+.RE
+.PP
+\fBREPOSITORY_TIMESTAMP "repository:timestamp"\fR
+.RS 4
+The seconds since the unix epoch when the repository was created\&.
+.RE
+.PP
+\fBREPOSITORY_EXPIRE "repository:expire"\fR
+.RS 4
+The seconds after the timestamp when the repository will expire\&.
+.RE
+.PP
+\fBREPOSITORY_UPDATES "repository:updates"\fR
+.RS 4
+An array of structures describing what this repository updates\&.
+.RE
+.PP
+\fBREPOSITORY_DISTROS "repository:distros"\fR
+.RS 4
+Also an array of structures describing what this repository updates\&. Seems to be the newer name of REPOSITORY_UPDATES\&.
+.RE
+.PP
+\fBREPOSITORY_PRODUCT_LABEL "repository:product:label"\fR
+.RS 4
+Should really be called "repository:updates:label"\&. What distribution is updated with this repository\&.
+.RE
+.PP
+\fBREPOSITORY_PRODUCT_CPEID "repository:product:cpeid"\fR
+.RS 4
+The cpeid of the platform updated by this repository\&. Is both used in REPOSITORY_UPDATES and REPOSITORY_DISTROS to maximize confusion\&.
+.RE
+.PP
+\fBREPOSITORY_REPOID "repository:repoid"\fR
+.RS 4
+An array of Id strings describing keywords/tags about the repository itself\&.
+.RE
+.PP
+\fBREPOSITORY_KEYWORDS "repository:keywords"\fR
+.RS 4
+An array of Id strings describing keywords/tags about the content of the repository\&.
+.RE
+.PP
+\fBREPOSITORY_REVISION "repository:revision"\fR
+.RS 4
+An arbitrary string describing the revision of the repository\&.
+.RE
+.PP
+\fBREPOSITORY_TOOLVERSION "repository:toolversion"\fR
+.RS 4
+Some string describing somewhat the version of libsolv used to create the solv file\&.
+.RE
+.SH "REPOSITORY METADATA FOR SUSETAGS REPOS"
+.sp
+Attributes describing repository files in a susetags repository\&. \fBSUSETAGS_DATADIR "susetags:datadir"\fR:: The directory that contains the packages\&.
+.PP
+\fBSUSETAGS_DESCRDIR "susetags:descrdir"\fR
+.RS 4
+The directory that contains the repository file resources\&.
+.RE
+.PP
+\fBSUSETAGS_DEFAULTVENDOR "susetags:defaultvendor"\fR
+.RS 4
+The default vendor used when a package does not specify a vendor\&.
+.RE
+.PP
+\fBSUSETAGS_FILE "susetags:file"\fR
+.RS 4
+An array of file resources of the repository\&.
+.RE
+.PP
+\fBSUSETAGS_FILE_NAME "susetags:file:name"\fR
+.RS 4
+The filename of the resource\&.
+.RE
+.PP
+\fBSUSETAGS_FILE_TYPE "susetags:file:type"\fR
+.RS 4
+The type of the resource, e\&.g\&. \(lqMETA\(rq\&.
+.RE
+.PP
+\fBSUSETAGS_FILE_CHECKSUM "susetags:file:checksum"\fR
+.RS 4
+The file checksum of the resource\&.
+.RE
+.SH "REPOSITORY METADATA FOR RPMMD REPOS"
+.PP
+\fBREPOSITORY_REPOMD "repository:repomd"\fR
+.RS 4
+An array of file resources of the repository\&.
+.RE
+.PP
+\fBREPOSITORY_REPOMD_TYPE "repository:repomd:type"\fR
+.RS 4
+The type of the resource, e\&.g\&. \(lqprimary\(rq\&.
+.RE
+.PP
+\fBREPOSITORY_REPOMD_LOCATION "repository:repomd:location"\fR
+.RS 4
+The location (aka filename) of the resource
+.RE
+.PP
+\fBREPOSITORY_REPOMD_TIMESTAMP "repository:repomd:timestamp"\fR
+.RS 4
+The seconds since the unix epoch when the resource was created\&.
+.RE
+.PP
+\fBREPOSITORY_REPOMD_CHECKSUM "repository:repomd:checksum"\fR
+.RS 4
+The file checksum of the resource\&.
+.RE
+.PP
+\fBREPOSITORY_REPOMD_OPENCHECKSUM "repository:repomd:openchecksum"\fR
+.RS 4
+The checksum over the uncompressed contents of the resource\&.
+.RE
+.PP
+\fBREPOSITORY_REPOMD_SIZE "repository:repomd:size"\fR
+.RS 4
+The size of the resource file\&.
+.RE
+.SH "DELTA PACKAGE ATTRIBUTES"
+.PP
+\fBDELTA_PACKAGE_NAME "delta:pkgname"\fR
+.RS 4
+The target package name for the delta package\&. Applying the delta will recreate the target package\&.
+.RE
+.PP
+\fBDELTA_PACKAGE_EVR "delta:pkgevr"\fR
+.RS 4
+The version of the target package\&.
+.RE
+.PP
+\fBDELTA_PACKAGE_ARCH "delta:pkgarch"\fR
+.RS 4
+The architecture of the target package\&.
+.RE
+.PP
+\fBDELTA_LOCATION_DIR "delta:locdir"\fR
+.RS 4
+The directory in the repository that contains the delta package\&.
+.RE
+.PP
+\fBDELTA_LOCATION_NAME "delta:locname"\fR
+.RS 4
+The first part of the file name of the delta package\&.
+.RE
+.PP
+\fBDELTA_LOCATION_EVR "delta:locevr"\fR
+.RS 4
+The version part of the file name of the delta package\&.
+.RE
+.PP
+\fBDELTA_LOCATION_SUFFIX "delta:locsuffix"\fR
+.RS 4
+The suffix part of the file name of the delta package\&.
+.RE
+.PP
+\fBDELTA_LOCATION_BASE "delta:locbase"\fR
+.RS 4
+This attribute can be used to overwrite the repositories base url for the delta\&.
+.RE
+.PP
+\fBDELTA_DOWNLOADSIZE "delta:downloadsize"\fR
+.RS 4
+The size of the delta rpm file\&.
+.RE
+.PP
+\fBDELTA_CHECKSUM "delta:checksum"\fR
+.RS 4
+The checksum of the delta rpm file\&.
+.RE
+.PP
+\fBDELTA_BASE_EVR "delta:baseevr"\fR
+.RS 4
+The version of the package the delta was built against\&.
+.RE
+.PP
+\fBDELTA_SEQ_NAME "delta:seqname"\fR
+.RS 4
+The first part of the delta sequence, the base package name\&.
+.RE
+.PP
+\fBDELTA_SEQ_EVR "delta:seqevr"\fR
+.RS 4
+The evr part of the delta sequence, the base package evr\&. Identical to the DELTA_BASE_EVR attribute\&.
+.RE
+.PP
+\fBDELTA_SEQ_NUM "delta:seqnum"\fR
+.RS 4
+The last part of the delta sequence, the content selection string\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/libsolv-history.3 b/libsolv-0.7.2/doc/gen/libsolv-history.3
new file mode 100644 (file)
index 0000000..fc2d69b
--- /dev/null
@@ -0,0 +1,119 @@
+'\" t
+.\"     Title: Libsolv-History
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "LIBSOLV\-HISTORY" "3" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libsolv-history \- how the libsolv library came into existence
+.SH "HISTORY"
+.sp
+This project was started in May 2007 when the zypp folks decided to switch to a database to speed up installation\&. As I am not a big fan of databases, I (mls) wondered if there would be really some merit of using one for solving, as package dependencies of all packages have to be read in anyway\&.
+.sp
+Back in 2002, I researched that using a dictionary approach for storing dependencies can reduce the packages file to 1/3 of its size\&. Extending this idea a bit more, I decided to store all strings and relations as unique 32\-bit numbers\&. This has three big advantages:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+because of the unification, testing whether two strings are equal is the same as testing the equality of two numbers, thus very fast
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+much space is saved, as numbers do not take up as much space as strings the internal memory representation does not take more space on a 64\-bit system where a pointer is twice the size of a 32\-bit number
+.RE
+.sp
+Thus, the solv format was created, which stores a repository as a string dictionary, a relation dictionary and then all packages dependencies\&. Tests showed that reading and merging multiple solv repositories takes just some milliseconds\&.
+.SS "Early solver experiments"
+.sp
+Having a new repository format was one big step, but the other area where libzypp needed improvement was the solver\&. Libzypp\(cqs solver was a port from the Red Carpet solver, which was written to update packages in an already installed system\&. Using it for the complete installation progress brought it to its limits\&. Also, the added extensions like support for weak dependencies and patches made it fragile and unpredictable\&.
+.sp
+As I was not very pleased with the way the solver worked, I looked at other solver algorithms\&. I checked smart, yum and apt, but could not find a convincing algorithm\&. My own experiments also were not very convincing, they worked fine for some problems but failed miserably for other corner cases\&.
+.SS "Using SAT for solving"
+.sp
+SUSE\(cqs hack week at the end of June 2007 turned out to be a turning point for the solver\&. Googling for solver algorithms, I stumbled over some note saying that some people are trying to use SAT algorithms to improve solving on Debian\&. Looking at the SAT entry in Wikipedia, it was easy to see that this indeed was the missing piece: SAT algorithms are well researched and there are quite some open source implementations\&. I decided to look at the minisat code, as it is one of the fastest solvers while consisting of too many lines of code\&.
+.sp
+Of course, directly using minisat would not work, as a package solver does not need to find just one correct solution, but it also has to optimize some metrics, i\&.e\&. keep as many packages installed as possible\&. Thus, I needed to write my own solver incorporation the ideas and algorithms used in minisat\&. This wasn\(cqt very hard, and at the end of the hack week the solver calculated the first right solutions\&.
+.SS "Selling it to libzypp"
+.sp
+With those encouraging results, I went to Klaus Kaempf, the system management architect at SUSE\&. We spoke about how to convince the team to make libzypp switch to the new solver\&. Fortunately, libzypp comes with a plethora of solver test cases, so we decided to make the solver pass most of the test cases first\&. Klaus wrote a "deptestomatic" implementation to check the test cases\&. Together with Stephan Kulow, who is responsible for the openSUSE distribution, we tweaked and extended the solver until most of the test cases looked good\&.
+.sp
+Duncan Mac\-Vicar Prett, the team lead of the YaST team, also joined development by creating Ruby bindings for the solver\&. Later, Klaus improved the bindings and ported them to some other languages\&.
+.SS "The attribute store"
+.sp
+The progress with the repository format and the solver attracted another hacker to the project: Michael Matz from the compiler team\&. He started with improving the repository parsers so that patches and content files also generate solvables\&. After that, he concentrated on storing all of the other metadata of the repositories that are not used for solving, like the package summaries and descriptions\&. At the end of October, a first version of this "attribute store" was checked in\&. Its design goals were:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+space efficient storage of attributes
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+paging/on demand loading of data
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+page compression
+.RE
+.sp
+The first version of the attribute store used a different format for storing information, we later merged this format with the solv file format\&.
+.SS "libzypp integration"
+.sp
+Integration of the sat\-solver into libzypp also started in October 2007 by Stefan Schubert and Michael Andres from the YaST team\&. The first versions supported both the old solver and the new one by using the old repository read functions and converting the old package data in\-memory into a sat solver pool\&. Solvers could be switched with the environment variable ZYPP_SAT_SOLVER\&. The final decision to move to the new solver was made in January of 2008, first just by making the new solver the default one, later by completely throwing out the old solver code\&. This had the advantage that the internal solvable storage could also be done by using the solver pool, something Michael Matz already played with in a proof of concept implementation showing some drastic speed gains\&. The last traces of the old database code were removed in February\&.
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/libsolv-pool.3 b/libsolv-0.7.2/doc/gen/libsolv-pool.3
new file mode 100644 (file)
index 0000000..51dc1a4
--- /dev/null
@@ -0,0 +1,1337 @@
+'\" t
+.\"     Title: Libsolv-Pool
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 10/22/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "LIBSOLV\-POOL" "3" "10/22/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libsolv-pool \- Libsolv\*(Aqs pool object
+.SH "PUBLIC ATTRIBUTES"
+.PP
+\fBvoid *appdata\fR
+.RS 4
+A no\-purpose pointer free to use for the library user\&. Freeing the pool simply discards the pointer\&.
+.RE
+.PP
+\fBStringpool ss\fR
+.RS 4
+The pool of unified strings\&.
+.RE
+.PP
+\fBReldep *rels\fR
+.RS 4
+The pool of unified relation dependencies\&.
+.RE
+.PP
+\fBint nrels\fR
+.RS 4
+Number of allocated relation dependencies\&.
+.RE
+.PP
+\fBRepo **repos\fR
+.RS 4
+The array of repository pointers, indexed by repository Id\&.
+.RE
+.PP
+\fBint nrepos\fR
+.RS 4
+Number of allocated repository array elements, i\&.e\&. the size of the repos array\&.
+.RE
+.PP
+\fBint urepos\fR
+.RS 4
+Number of used (i\&.e\&. non\-zero) repository array elements\&.
+.RE
+.PP
+\fBRepo *installed\fR
+.RS 4
+Pointer to the repo holding the installed packages\&. You are free to read this attribute, but you should use pool_set_installed() if you want to change it\&.
+.RE
+.PP
+\fBSolvable *solvables\fR
+.RS 4
+The array of Solvable objects\&.
+.RE
+.PP
+\fBint nsolvables\fR
+.RS 4
+Number of Solvable objects, i\&.e\&. the size of the solvables array\&. Note that the array may contain freed solvables, in that case the repo pointer of the solvable will be zero\&.
+.RE
+.PP
+\fBint disttype\fR
+.RS 4
+The distribution type of your system, e\&.g\&. DISTTYPE_DEB\&. You are free to read this attribute, but you should use pool_setdisttype() if you want to change it\&.
+.RE
+.PP
+\fBId *whatprovidesdata\fR
+.RS 4
+Multi\-purpose Id storage holding zero terminated arrays of Ids\&. pool_whatprovides() returns an offset into this data\&.
+.RE
+.PP
+\fBMap *considered\fR
+.RS 4
+Optional bitmap that can make the library ignore solvables\&. If a bitmap is set, only solvables that have a set bit in the bitmap at their Id are considered usable\&.
+.RE
+.PP
+\fBint debugmask\fR
+.RS 4
+A mask that defines which debug events should be reported\&. pool_setdebuglevel() sets this mask\&.
+.RE
+.PP
+\fBDatapos pos\fR
+.RS 4
+An object storing some position in the repository data\&. Functions like dataiterator_set_pos() set this object, accessing data with a pseudo solvable Id of SOLVID_POS uses it\&.
+.RE
+.PP
+\fBQueue pooljobs\fR
+.RS 4
+A queue where fixed solver jobs can be stored\&. This jobs are automatically added when solver_solve() is called, they are useful to store configuration data like which packages should be multiversion installed\&.
+.RE
+.SH "CREATION AND DESTRUCTION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBPool *pool_create()\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a new instance of a pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_free(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Free a pool and all of the data it contains, e\&.g\&. the solvables, repositories, strings\&.
+.SH "DEBUGGING AND ERROR REPORTING"
+.SS "Constants"
+.PP
+\fBSOLV_FATAL\fR
+.RS 4
+Report the error and call \(lqexit(1)\(rq afterwards\&. You cannot mask this level\&. Reports to stderr instead of stdout\&.
+.RE
+.PP
+\fBSOLV_ERROR\fR
+.RS 4
+Used to report errors\&. Reports to stderr instead of stdout\&.
+.RE
+.PP
+\fBSOLV_WARN\fR
+.RS 4
+Used to report warnings\&.
+.RE
+.PP
+\fBSOLV_DEBUG_STATS\fR
+.RS 4
+Used to report statistical data\&.
+.RE
+.PP
+\fBSOLV_DEBUG_RULE_CREATION\fR
+.RS 4
+Used to report information about the solver\(cqs creation of rules\&.
+.RE
+.PP
+\fBSOLV_DEBUG_PROPAGATE\fR
+.RS 4
+Used to report information about the solver\(cqs unit rule propagation process\&.
+.RE
+.PP
+\fBSOLV_DEBUG_ANALYZE\fR
+.RS 4
+Used to report information about the solver\(cqs learnt rule generation mechanism\&.
+.RE
+.PP
+\fBSOLV_DEBUG_UNSOLVABLE\fR
+.RS 4
+Used to report information about the solver dealing with conflicting rules\&.
+.RE
+.PP
+\fBSOLV_DEBUG_SOLUTIONS\fR
+.RS 4
+Used to report information about the solver creating solutions to solve problems\&.
+.RE
+.PP
+\fBSOLV_DEBUG_POLICY\fR
+.RS 4
+Used to report information about the solver searching for an optimal solution\&.
+.RE
+.PP
+\fBSOLV_DEBUG_RESULT\fR
+.RS 4
+Used by the debug functions to output results\&.
+.RE
+.PP
+\fBSOLV_DEBUG_JOB\fR
+.RS 4
+Used to report information about the job rule generation process\&.
+.RE
+.PP
+\fBSOLV_DEBUG_SOLVER\fR
+.RS 4
+Used to report information about what the solver is currently doing\&.
+.RE
+.PP
+\fBSOLV_DEBUG_TRANSACTION\fR
+.RS 4
+Used to report information about the transaction generation and ordering process\&.
+.RE
+.PP
+\fBSOLV_DEBUG_TO_STDERR\fR
+.RS 4
+Write debug messages to stderr instead of stdout\&.
+.RE
+.SS "Functions"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_debug(Pool *\fR\fIpool\fR\fB, int\fR \fItype\fR\fB, const char *\fR\fIformat\fR\fB, \&.\&.\&.)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Report a message of the type \fItype\fR\&. You can filter debug messages by setting a debug mask\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setdebuglevel(Pool *\fR\fIpool\fR\fB, int\fR \fIlevel\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set a predefined debug mask\&. A higher level generally means more bits in the mask are set, thus more messages are printed\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setdebugmask(Pool *\fR\fIpool\fR\fB, int\fR \fImask\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the debug mask to filter debug messages\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_error(Pool *\fR\fIpool\fR\fB, int\fR \fIret\fR\fB, const char *\fR\fIformat\fR\fB, \&.\&.\&.)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the pool\(cqs error string\&. The \fIret\fR value is simply used as a return value of the function so that you can write code like return pool_error(\&...);\&. If the debug mask contains the \fBSOLV_ERROR\fR bit, pool_debug() is also called with the message and type \fBSOLV_ERROR\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBextern char *pool_errstr(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the current error string stored in the pool\&. Like with the libc\(cqs errno value, the string is only meaningful after a function returned an error\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setdebugcallback(Pool *\fR\fIpool\fR\fB, void (*\fR\fIdebugcallback\fR\fB)(Pool *, void *\fR\fIdata\fR\fB, int\fR \fItype\fR\fB, const char *\fR\fIstr\fR\fB), void *\fR\fIdebugcallbackdata\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set a custom debug callback function\&. Instead of writing to stdout or stderr, the callback function will be called\&.
+.SH "POOL CONFIGURATION"
+.SS "Constants"
+.PP
+\fBDISTTYPE_RPM\fR
+.RS 4
+Used for systems which use rpm as low level package manager\&.
+.RE
+.PP
+\fBDISTTYPE_DEB\fR
+.RS 4
+Used for systems which use dpkg as low level package manager\&.
+.RE
+.PP
+\fBDISTTYPE_ARCH\fR
+.RS 4
+Used for systems which use the arch linux package manager\&.
+.RE
+.PP
+\fBDISTTYPE_HAIKU\fR
+.RS 4
+Used for systems which use haiku packages\&.
+.RE
+.PP
+\fBPOOL_FLAG_PROMOTEEPOCH\fR
+.RS 4
+Promote the epoch of the providing dependency to the requesting dependency if it does not contain an epoch\&. Used at some time in old rpm versions, modern systems should never need this\&.
+.RE
+.PP
+\fBPOOL_FLAG_FORBIDSELFCONFLICTS\fR
+.RS 4
+Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them recently\&.
+.RE
+.PP
+\fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR
+.RS 4
+Make obsolete type dependency match against provides instead of just the name and version of packages\&. Very old versions of rpm used the name/version, then it got switched to provides and later switched back again to just name/version\&.
+.RE
+.PP
+\fBPOOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES\fR
+.RS 4
+An implicit obsoletes is the internal mechanism to remove the old package on an update\&. The default is to remove all packages with the same name, rpm\-5 switched to also removing packages providing the same name\&.
+.RE
+.PP
+\fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR
+.RS 4
+Rpm\(cqs multilib implementation (used in RedHat and Fedora) distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&.
+.RE
+.PP
+\fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR
+.RS 4
+Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the same name can be installed in parallel\&. For current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true (this is the default if FEDORA is defined when libsolv is compiled)\&.
+.RE
+.PP
+\fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR
+.RS 4
+New versions of rpm consider the obsoletes of installed packages when checking for dependency, thus you may not install a package that is obsoleted by some other installed package, unless you also erase the other package\&.
+.RE
+.PP
+\fBPOOL_FLAG_HAVEDISTEPOCH\fR
+.RS 4
+Mandriva added a new field called distepoch that gets checked in version comparison if the epoch/version/release of two packages are the same\&.
+.RE
+.PP
+\fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR
+.RS 4
+If a package is installed in multiversionmode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&.
+.RE
+.PP
+\fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR
+.RS 4
+Make the addfileprovides method only add files from the standard locations (i\&.e\&. the \(lqbin\(rq and \(lqetc\(rq directories)\&. This is useful if you have only few packages that use non\-standard file dependencies, but you still want the fast speed that addfileprovides() generates\&.
+.RE
+.SS "Functions"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_setdisttype(Pool *\fR\fIpool\fR\fB, int\fR \fIdisttype\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the package type of your system\&. The disttype is used for example to define package comparison semantics\&. Libsolv\(cqs default disttype should match the package manager of your system, so you only need to use this function if you want to use the library to solve packaging problems for different systems\&. The Function returns the old disttype on success, and \-1 if the new disttype is not supported\&. Note that any pool_setarch and pool_setarchpolicy calls need to come after the pool_setdisttype call, as they make use of the noarch/any/all architecture id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_set_flag(Pool *\fR\fIpool\fR\fB, int\fR \fIflag\fR\fB, int\fR \fIvalue\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set a flag to a new value\&. Returns the old value of the flag\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_get_flag(Pool *\fR\fIpool\fR\fB, int\fR \fIflag\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Get the value of a pool flag\&. See the constants section about the meaning of the flags\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_set_rootdir(Pool *\fR\fIpool\fR\fB, const char *\fR\fIrootdir\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set a specific root directory\&. Some library functions support a flag that tells the function to prepend the rootdir to file and directory names\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_get_rootdir(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the current value of the root directory\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *pool_prepend_rootdir(Pool *\fR\fIpool\fR\fB, const char *\fR\fIdir\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Prepend the root directory to the \fIdir\fR argument string\&. The returned string has been newly allocated and needs to be freed after use\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *pool_prepend_rootdir_tmp(Pool *\fR\fIpool\fR\fB, const char *\fR\fIdir\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as pool_prepend_rootdir, but uses the pool\(cqs temporary space for allocation\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_set_installed(Pool *\fR\fIpool\fR\fB, Repo *\fR\fIrepo\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set which repository should be treated as the \(lqinstalled\(rq repository, i\&.e\&. the one that holds information about the installed packages\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_set_languages(Pool *\fR\fIpool\fR\fB, const char **\fR\fIlanguages\fR\fB, int\fR \fInlanguages\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the language of your system\&. The library provides lookup functions that return localized strings, for example for package descriptions\&. You can set an array of languages to provide a fallback mechanism if one language is not available\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setarch(Pool *\fR\fIpool\fR\fB, const char *\fR\fIarch\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the architecture of your system\&. The architecture is used to determine which packages are installable and which packages cannot be installed\&. The \fIarch\fR argument is normally the \(lqmachine\(rq value of the \(lquname\(rq system call\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setarchpolicy(Pool *, const char *)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set the architecture policy for your system\&. This is the general version of pool_setarch (in fact pool_setarch calls pool_setarchpolicy internally)\&. See the section about architecture policies for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_addvendorclass(Pool *\fR\fIpool\fR\fB, const char **\fR\fIvendorclass\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a new vendor equivalence class to the system\&. A vendor equivalence class defines if an installed package of one vendor can be replaced by a package coming from a different vendor\&. The \fIvendorclass\fR argument must be a NULL terminated array of strings\&. See the section about vendor policies for more information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setvendorclasses(Pool *\fR\fIpool\fR\fB, const char **\fR\fIvendorclasses\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Set all allowed vendor equivalences\&. The vendorclasses argument must be an NULL terminated array consisting of all allowed classes concatenated\&. Each class itself must be NULL terminated, thus the last class ends with two NULL elements, one to finish the class and one to finish the list of classes\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_set_custom_vendorcheck(Pool *\fR\fIpool\fR\fB, int (*\fR\fIvendorcheck\fR\fB)(Pool *, Solvable *, Solvable *))\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Define a custom vendor check mechanism\&. You can use this if libsolv\(cqs internal vendor equivalence class mechanism does not match your needs\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setloadcallback(Pool *\fR\fIpool\fR\fB, int (*\fR\fIcb\fR\fB)(Pool *, Repodata *, void *), void *\fR\fIloadcbdata\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Define a callback function that gets called when repository metadata needs to be loaded on demand\&. See the section about on demand loading in the libsolv\-repodata manual\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_setnamespacecallback(Pool *\fR\fIpool\fR\fB, Id (*\fR\fIcb\fR\fB)(Pool *, void *,\fR \fIId\fR\fB,\fR \fIId\fR\fB), void *\fR\fInscbdata\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Define a callback function to implement custom namespace support\&. See the section about namespace dependencies\&.
+.SH "ID POOL MANAGEMENT"
+.SS "Constants"
+.PP
+\fBID_EMPTY\fR
+.RS 4
+The Id of the empty string, it is always Id 1\&.
+.RE
+.PP
+\fBREL_LT\fR
+.RS 4
+Represents a \(lq<\(rq relation\&.
+.RE
+.PP
+\fBREL_EQ\fR
+.RS 4
+Represents a \(lq=\(rq relation\&.
+.RE
+.PP
+\fBREL_GT\fR
+.RS 4
+Represents a \(lq>\(rq relation\&. You can use combinations of REL_GT, REL_EQ, and REL_LT or\-ed together to create any relation you like\&.
+.RE
+.PP
+\fBREL_AND\fR
+.RS 4
+A boolean AND operation, the \(lqname\(rq and \(lqevr\(rq parts of the relation can be two sub\-dependencies\&. Packages must match both parts of the dependency\&.
+.RE
+.PP
+\fBREL_OR\fR
+.RS 4
+A boolean OR operation, the \(lqname\(rq and \(lqevr\(rq parts of the relation can be two sub\-dependencies\&. Packages can match any part of the dependency\&.
+.RE
+.PP
+\fBREL_WITH\fR
+.RS 4
+Like REL_AND, but packages must match both dependencies simultaneously\&. See the section about boolean dependencies about more information\&.
+.RE
+.PP
+\fBREL_NAMESPACE\fR
+.RS 4
+A special namespace relation\&. See the section about namespace dependencies for more information\&.
+.RE
+.PP
+\fBREL_ARCH\fR
+.RS 4
+An architecture filter dependency\&. The \(lqname\(rq part of the relation is a sub\-dependency, the \(lqevr\(rq part is the Id of an architecture that the matching packages must have (note that this is an exact match ignoring architecture policies)\&.
+.RE
+.PP
+\fBREL_FILECONFLICT\fR
+.RS 4
+An internal file conflict dependency used to represent file conflicts\&. See the pool_add_fileconflicts_deps() function\&.
+.RE
+.PP
+\fBREL_COND\fR
+.RS 4
+A conditional dependency, the \(lqname\(rq sub\-dependency is only considered if the \(lqevr\(rq sub\-dependency is fulfilled\&. See the section about boolean dependencies about more information\&.
+.RE
+.PP
+\fBREL_UNLESS\fR
+.RS 4
+A conditional dependency, the \(lqname\(rq sub\-dependency is only considered if the \(lqevr\(rq sub\-dependency is not fulfilled\&. See the section about boolean dependencies about more information\&.
+.RE
+.PP
+\fBREL_COMPAT\fR
+.RS 4
+A compat dependency used in Haiku to represent version ranges\&. The \(lqname\(rq part is the actual version, the \(lqevr\(rq part is the backwards compatibility version\&.
+.RE
+.PP
+\fBREL_KIND\fR
+.RS 4
+A pseudo dependency that limits the solvables to a specific kind\&. The kind is expected to be a prefix of the solvable name, e\&.g\&. \(lqpatch:foo\(rq would be of kind \(lqpatch\(rq\&. \(lqREL_KIND\(rq is only supported in the selection functions\&.
+.RE
+.PP
+\fBREL_MULTIARCH\fR
+.RS 4
+A debian multiarch annotation\&. The most common value for the \(lqevr\(rq part is \(lqany\(rq\&.
+.RE
+.PP
+\fBREL_ELSE\fR
+.RS 4
+The else part of a \(lqREL_COND\(rq or \(lqREL_UNLESS\(rq dependency\&. See the section about boolean dependencies\&.
+.RE
+.PP
+\fBREL_ERROR\fR
+.RS 4
+An illegal dependency\&. This is useful to encode dependency parse errors\&.
+.RE
+.SS "Functions"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_str2id(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr\fR\fB, int\fR \fIcreate\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a string to the pool of unified strings, returning the Id of the string\&. If \fIcreate\fR is zero, new strings will not be added to the pool, instead Id 0 is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_strn2id(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr\fR\fB, unsigned int\fR \fIlen\fR\fB, int\fR \fIcreate\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as pool_str2id, but only \fIlen\fR characters of the string are used\&. This can be used to add substrings to the pool\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_rel2id(Pool *\fR\fIpool\fR\fB, Id\fR \fIname\fR\fB, Id\fR \fIevr\fR\fB, int\fR \fIflags\fR\fB, int\fR \fIcreate\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a relational dependency from to other dependencies, \fIname\fR and \fIevr\fR, and a \fIflag\fR\&. See the \fBREL_\fR constants for the supported flags\&. As with pool_str2id, \fIcreate\fR defines if new dependencies will get added or Id zero will be returned instead\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_id2langid(Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB, const char *\fR\fIlang\fR\fB, int\fR \fIcreate\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Attach a language suffix to a string Id\&. This function can be used to create language keyname Ids from keynames, it is functional equivalent to converting the \fIid\fR argument to a string, adding a \(lq:\(rq character and the \fIlang\fR argument to the string and then converting the result back into an Id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_id2str(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert an Id back into a string\&. If the Id is a relational Id, the \(lqname\(rq part will be converted instead\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_id2rel(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the relation string of a relational Id\&. Returns an empty string if the passed Id is not a relation\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_id2evr(const Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the \(lqevr\(rq part of a relational Id as string\&. Returns an empty string if the passed Id is not a relation\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_dep2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert an Id back into a string\&. If the passed Id belongs to a relation, a string representing the relation is returned\&. Note that in that case the string is allocated on the pool\(cqs temporary space\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_freeidhashes(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Free the hashes used to unify strings and relations\&. You can use this function to save memory if you know that you will no longer create new strings and relations\&.
+.SH "SOLVABLE FUNCTIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *pool_id2solvable(const Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a solvable Id into a pointer to the solvable data\&. Note that the pointer may become invalid if new solvables are created or old solvables deleted, because the array storing all solvables may get reallocated\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_solvable2id(const Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a pointer to the solvable data into a solvable Id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_solvid2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a string representing the solvable with the Id \fIp\fR\&. The string will be some canonical representation of the solvable, usually a combination of the name, the version, and the architecture\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_solvable2str(Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as pool_solvid2str, but instead of the Id, a pointer to the solvable is passed\&.
+.SH "DEPENDENCY MATCHING"
+.SS "Constants"
+.PP
+\fBEVRCMP_COMPARE\fR
+.RS 4
+Compare all parts of the version, treat missing parts as empty strings\&.
+.RE
+.PP
+\fBEVRCMP_MATCH_RELEASE\fR
+.RS 4
+A special mode for rpm version string matching\&. If a version misses a release part, it matches all releases\&. In that case the special values \(lq\-2\(rq and \(lq2\(rq are returned, depending on which of the two versions did not have a release part\&.
+.RE
+.PP
+\fBEVRCMP_MATCH\fR
+.RS 4
+A generic match, missing parts always match\&.
+.RE
+.PP
+\fBEVRCMP_COMPARE_EVONLY\fR
+.RS 4
+Only compare the epoch and the version parts, ignore the release part\&.
+.RE
+.SS "Functions"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_evrcmp(const Pool *\fR\fIpool\fR\fB, Id\fR \fIevr1id\fR\fB, Id\fR \fIevr2id\fR\fB, int\fR \fImode\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Compare two version Ids, return \-1 if the first version is less than the second version, 0 if they are identical, and 1 if the first version is bigger than the second one\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_evrcmp_str(const Pool *\fR\fIpool\fR\fB, const char *\fR\fIevr1\fR\fB, const char *\fR\fIevr2\fR\fB, int\fR \fImode\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as pool_evrcmp(), but uses strings instead of Ids\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_evrmatch(const Pool *\fR\fIpool\fR\fB, Id\fR \fIevrid\fR\fB, const char *\fR\fIepoch\fR\fB, const char *\fR\fIversion\fR\fB, const char *\fR\fIrelease\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Match a version Id against an epoch, a version and a release string\&. Passing NULL means that the part should match everything\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_match_dep(Pool *\fR\fIpool\fR\fB, Id\fR \fId1\fR\fB, Id\fR \fId2\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Returns \(lq1\(rq if the dependency \fId1\fR (the provider) is matched by the dependency \fId2\fR, otherwise \(lq0\(rq is returned\&. For two dependencies to match, both the \(lqname\(rq parts must match and the version range described by the \(lqevr\(rq parts must overlap\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_match_nevr(Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB, Id\fR \fId\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Like pool_match_dep, but the provider is the "self\-provides" dependency of the Solvable \fIs\fR, i\&.e\&. the dependency \(lqs→name = s→evr\(rq\&.
+.SH "WHATPROVIDES INDEX"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_createwhatprovides(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create an index that maps dependency Ids to sets of packages that provide the dependency\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_freewhatprovides(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Free the whatprovides index to save memory\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_whatprovides(Pool *\fR\fIpool\fR\fB, Id\fR \fId\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return an offset into the Pool\(cqs whatprovidesdata array\&. The solvables with the Ids stored starting at that offset provide the dependency \fId\fR\&. The solvable list is zero terminated\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId *pool_whatprovides_ptr(Pool *\fR\fIpool\fR\fB, Id\fR \fId\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Instead of returning the offset, return the pointer to the Ids stored at that offset\&. Note that this pointer has a very limit validity time, as any call that adds new values to the whatprovidesdata area may reallocate the array\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_queuetowhatprovides(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIq\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add the contents of the Queue \fIq\fR to the end of the whatprovidesdata array, returning the offset into the array\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_addfileprovides(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Some package managers like rpm allow dependencies on files contained in other packages\&. To allow libsolv to deal with those dependencies in an efficient way, you need to call the addfileprovides method after creating and reading all repositories\&. This method will scan all dependency for file names and then scan all packages for matching files\&. If a filename has been matched, it will be added to the provides list of the corresponding package\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_addfileprovides_queue(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIidq\fR\fB, Queue *\fR\fIidqinst\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as pool_addfileprovides, but the added Ids are returned in two Queues, \fIidq\fR for all repositories except the one containing the \(lqinstalled\(rq packages, \fIidqinst\fR for the latter one\&. This information can be stored in the meta section of the repositories to speed up the next time the repository is loaded and addfileprovides is called
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_set_whatprovides(\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB, Id\fR \fIoffset\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Manually set an entry in the whatprovides index\&. You\(cqll never do this for package dependencies, as those entries are created by calling the pool_createwhatprovides() function\&. But this function is useful for namespace provides if you do not want to use a namespace callback to lazily set the provides\&. The offset argument is a offset in the whatprovides array, thus you can use \(lq1\(rq as a false value and \(lq2\(rq as true value\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_flush_namespaceproviders(Pool *\fR\fIpool\fR\fB, Id\fR \fIns\fR\fB, Id\fR \fIevr\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Clear the cache of the providers for namespace dependencies matching namespace \fIns\fR\&. If the \fIevr\fR argument is non\-zero, the namespace dependency for exactly that dependency is cleared, otherwise all matching namespace dependencies are cleared\&. See the section about Namespace dependencies for further information\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_add_fileconflicts_deps(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIconflicts\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Some package managers like rpm report conflicts when a package installation overwrites a file of another installed package with different content\&. As file content information is not stored in the repository metadata, those conflicts can only be detected after the packages are downloaded\&. Libsolv provides a function to check for such conflicts, pool_findfileconflicts()\&. If conflicts are found, they can be added as special \fBREL_FILECONFLICT\fR provides dependencies, so that the solver will know about the conflict when it is re\-run\&.
+.SH "UTILITY FUNCTIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *pool_alloctmpspace(Pool *\fR\fIpool\fR\fB, int\fR \fIlen\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Allocate space on the pool\(cqs temporary space area\&. This space has a limited lifetime, it will be automatically freed after a fixed amount (currently 16) of other pool_alloctmpspace() calls are done\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_freetmpspace(Pool *\fR\fIpool\fR\fB, const char *\fR\fIspace\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Give the space allocated with pool_alloctmpspace back to the system\&. You do not have to use this function, as the space is automatically reclaimed, but it can be useful to extend the lifetime of other pointers to the pool\(cqs temporary space area\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_bin2hex(Pool *\fR\fIpool\fR\fB, const unsigned char *\fR\fIbuf\fR\fB, int\fR \fIlen\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert some binary data to hexadecimal, returning a string allocated in the pool\(cqs temporary space area\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *pool_tmpjoin(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr1\fR\fB, const char *\fR\fIstr2\fR\fB, const char *\fR\fIstr3\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Join three strings and return the result in the pool\(cqs temporary space area\&. You can use NULL arguments if you just want to join less strings\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBchar *pool_tmpappend(Pool *\fR\fIpool\fR\fB, const char *\fR\fIstr1\fR\fB, const char *\fR\fIstr2\fR\fB, const char *\fR\fIstr3\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Like pool_tmpjoin(), but if the first argument is the last allocated space in the pool\(cqs temporary space area, it will be replaced with the result of the join and no new temporary space slot will be used\&. Thus you can join more than three strings by a combination of one pool_tmpjoin() and multiple pool_tmpappend() calls\&. Note that the \fIstr1\fR pointer is no longer usable after the call\&.
+.SH "DATA LOOKUP"
+.SS "Constants"
+.PP
+\fBSOLVID_POS\fR
+.RS 4
+Use the data position stored in the pool for the lookup instead of looking up the data of a solvable\&.
+.RE
+.PP
+\fBSOLVID_META\fR
+.RS 4
+Use the data stored in the meta section of a repository (or repodata area) instead of looking up the data of a solvable\&. This constant does not work for the pool\(cqs lookup functions, use it for the repo\(cqs or repodata\(cqs lookup functions instead\&. It\(cqs just listed for completeness\&.
+.RE
+.SS "Functions"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_lookup_str(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the string value stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long pool_lookup_num(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the 64bit unsigned number stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. If no such number is found, the value of the \fInotfound\fR argument is returned instead\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBId pool_lookup_id(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the Id stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_lookup_idarray(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Queue *\fR\fIq\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Fill the queue \fIq\fR with the content of the Id array stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. Returns \(lq1\(rq if an array was found, otherwise the queue will be empty and \(lq0\(rq will be returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_lookup_void(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Returns \(lq1\(rq if a void value is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR, otherwise \(lq0\(rq\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_lookup_checksum(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id *\fR\fItypep\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the checksum that is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. The type of the checksum will be returned over the \fItypep\fR pointer\&. If no such checksum is found, NULL will be returned and the type will be set to zero\&. Note that the result is stored in the Pool\(cqs temporary space area\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst unsigned char *pool_lookup_bin_checksum(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id *\fR\fItypep\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return the checksum that is stored under the attribute \fIkeyname\fR in solvable \fIsolvid\fR\&. Returns the checksum as binary data, you can use the returned type to calculate the length of the checksum\&. No temporary space area is needed\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_lookup_deltalocation(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, unsigned int *\fR\fImedianrp\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This is a utility lookup function to return the delta location for a delta rpm\&. As solvables cannot store deltas, you have to use SOLVID_POS as argument and set the Pool\(cqs datapos pointer to point to valid delta rpm data\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_search(Pool *\fR\fIpool\fR\fB, Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB, int (*\fR\fIcallback\fR\fB)(void *\fR\fIcbdata\fR\fB, Solvable *\fR\fIs\fR\fB, Repodata *\fR\fIdata\fR\fB, Repokey *\fR\fIkey\fR\fB, KeyValue *\fR\fIkv\fR\fB), void *\fR\fIcbdata\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Perform a search on all data stored in the pool\&. You can limit the search area by using the \fIsolvid\fR and \fIkeyname\fR arguments\&. The values can be optionally matched against the \fImatch\fR argument, use NULL if you do not want this matching\&. See the Dataiterator manpage about the possible matches modes and the \fIflags\fR argument\&. For all (matching) values, the callback function is called with the \fIcbdata\fR callback argument and the data describing the value\&.
+.SH "JOB AND SELECTION FUNCTIONS"
+.sp
+A Job consists of two Ids, \fIhow\fR and \fIwhat\fR\&. The \fIhow\fR part describes the action, the job flags, and the selection method while the \fIwhat\fR part is in input for the selection\&. A Selection is a queue consisting of multiple jobs (thus the number of elements in the queue must be a multiple of two)\&. See the Solver manpage for more information about jobs\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_job2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB, Id\fR \fIflagmask\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a job into a string\&. Useful for debugging purposes\&. The \fIflagmask\fR can be used to mask the flags of the job, use \(lq0\(rq if you do not want to see such flags, \(lq\-1\(rq to see all flags, or a combination of the flags you want to see\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_job2solvables(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIpkgs\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return a list of solvables that the specified job selects\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBint pool_isemptyupdatejob(Pool *\fR\fIpool\fR\fB, Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return \(lq1\(rq if the job is an update job that does not work with any installed package, i\&.e\&. the job is basically a no\-op\&. You can use this to turn no\-op update jobs into install jobs (as done by package managers like \(lqzypper\(rq)\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *pool_selection2str(Pool *\fR\fIpool\fR\fB, Queue *\fR\fIselection\fR\fB, Id\fR \fIflagmask\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a selection into a string\&. Useful for debugging purposes\&. See the pool_job2str() function for the \fIflagmask\fR argument\&.
+.SH "ODDS AND ENDS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_freeallrepos(Pool *\fR\fIpool\fR\fB, int\fR \fIreuseids\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Free all repos from the pool (including all solvables)\&. If \fIreuseids\fR is true, all Ids of the solvables are free to be reused the next time solvables are created\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid pool_clear_pos(Pool *\fR\fIpool\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Clear the data position stored in the pool\&.
+.SH "ARCHITECTURE POLICIES"
+.sp
+An architecture policy defines a list of architectures that can be installed on the system, and also the relationship between them (i\&.e\&. the ordering)\&. Architectures can be delimited with three different characters:
+.PP
+\fB\*(Aq:\*(Aq\fR
+.RS 4
+No relationship between the architectures\&. A package of one architecture can not be replaced with one of the other architecture\&.
+.RE
+.PP
+\fB\*(Aq>\*(Aq\fR
+.RS 4
+The first architecture is better than the second one\&. An installed package of the second architecture may be replaced with one from the first architecture and vice versa\&. The solver will select the better architecture if the versions are the same\&.
+.RE
+.PP
+\fB\*(Aq=\*(Aq\fR
+.RS 4
+The two architectures are freely exchangeable\&. Used to define aliases for architectures\&.
+.RE
+.sp
+An example would be \*(Aqx86_64:i686=athlon>i586\*(Aq\&. This means that x86_64 packages can only be replaced by other x86_64 packages, i686 packages can be replaced by i686 and i586 packages (but i686 packages will be preferred) and athlon is another name for the i686 architecture\&.
+.sp
+You can turn off the architecture replacement checks with the Solver\(cqs SOLVER_FLAG_ALLOW_ARCHCHANGE flag\&.
+.SH "VENDOR POLICIES"
+.sp
+Different vendors often compile packages with different features, so Libsolv only replace installed packages of one vendor with packages coming from the same vendor\&. Also, while the version of a package is normally defined by the upstream project, the release part of the version is set by the vendor\(cqs package maintainer, so it\(cqs not meaningful to do version comparisons for packages coming from different vendors\&.
+.sp
+Vendor in this case means the SOLVABLE_VENDOR string stored in each solvable\&. Sometimes a vendor changes names, or multiple vendors form a group that coordinate their package building, so libsolv offers a way to define that a group of vendors are compatible\&. You do that be defining vendor equivalence classes, packages from a vendor from one class may be replaced with packages from all the other vendors in the class\&.
+.sp
+There can be multiple equivalence classes, the set of allowed vendor changes for an installed package is calculated by building the union of all of the equivalence classes the vendor of the installed package is part of\&.
+.sp
+You can turn off the architecture replacement checks with the Solver\(cqs SOLVER_FLAG_ALLOW_VENDORCHANGE flag\&.
+.SH "BOOLEAN DEPENDENCIES"
+.sp
+Boolean Dependencies allow to build complex expressions from simple dependencies\&. Note that depending on the package manager only a subset of those may be useful\&. For example, debian currently only allows an "OR" expression\&.
+.PP
+\fBREL_OR\fR
+.RS 4
+The expression is true if either the first dependency or the second one is true\&. This is useful for package dependencies like \(lqRequires\(rq, where you can specify that either one of the packages need to be installed\&.
+.RE
+.PP
+\fBREL_AND\fR
+.RS 4
+The expression is true if both dependencies are true\&. The packages fulfilling the dependencies may be different, i\&.e\&. \(lqSupplements: perl REL_AND python\(rq is true if both a package providing perl and a package providing python are installed\&.
+.RE
+.PP
+\fBREL_WITH\fR
+.RS 4
+The expression is true if both dependencies are true and are fulfilled by the same package\&. Thus \(lqSupplements: perl REL_WITH python\(rq would only be true if a package is installed that provides both dependencies (some kind of multi\-language interpreter)\&.
+.RE
+.PP
+\fBREL_COND\fR
+.RS 4
+The expression is true if the first dependency is true or the second dependency is false\&. \(lqA REL_COND B\(rq is equivalent to \(lqA REL_OR (NOT B)\(rq (except that libsolv does not expose \(lqNOT\(rq)\&.
+.RE
+.PP
+\fBREL_UNLESS\fR
+.RS 4
+The expression is true if the first dependency is true and the second dependency is false\&. \(lqA REL_UNLESS B\(rq is equivalent to \(lqA REL_AND (NOT B)\(rq (except that libsolv does not expose \(lqNOT\(rq)\&.
+.RE
+.PP
+\fBREL_ELSE\fR
+.RS 4
+The \(lqelse\(rq part of a \(lqREL_COND\(rq or \(lqREL_UNLESS\(rq dependency\&. It has to be directly in the evr part of the condition, e\&.g\&. \(lqfoo REL_COND (bar REL_ELSE baz)\(rq\&. For \(lqREL_COND\(rq this is equivalent to writing \(lq(foo REL_COND bar) REL_AND (bar REL_OR baz)\(rq\&. For \(lqREL_UNLESS\(rq this is equivalent to writing \(lq(foo REL_UNLESS bar) REL_OR (bar REL_AND baz)\(rq\&.
+.RE
+.sp
+Each sub\-dependency of a boolean dependency can in turn be a boolean dependency, so you can chain them to create complex dependencies\&.
+.SH "NAMESPACE DEPENDENCIES"
+.sp
+Namespace dependencies can be used to implement dependencies on attributes external to libsolv\&. An example would be a dependency on the language set by the user\&. This types of dependencies are usually only used for \(lqConflicts\(rq or \(lqSupplements\(rq dependencies, as the underlying package manager does not know how to deal with them\&.
+.sp
+If the library needs to evaluate a namespace dependency, it calls the namespace callback function set in the pool\&. The callback function can return a set of packages that \(lqprovide\(rq the dependency\&. If the dependency is provided by the system, the returned set should consist of just the system solvable (Solvable Id 1)\&.
+.sp
+The returned set of packages must be returned as offset into the whatprovidesdata array\&. You can use the pool_queuetowhatprovides function to convert a queue into such an offset\&. To ease programming the callback function, the return values \(lq0\(rq and \(lq1\(rq are not interpreted as an offset\&. \(lq0\(rq means that no package is in the return set, \(lq1\(rq means that just the system solvable is in the set\&.
+.sp
+The returned set is cached, so that for each namespace dependency the callback is just called once\&. If you need to flush the cache (maybe because the user has selected a different language), use the pool_flush_namespaceproviders() function\&.
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/libsolv.3 b/libsolv-0.7.2/doc/gen/libsolv.3
new file mode 100644 (file)
index 0000000..a6ac359
--- /dev/null
@@ -0,0 +1,64 @@
+'\" t
+.\"     Title: Libsolv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "LIBSOLV" "3" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libsolv \- package dependency solver library using a satisfiability algorithm
+.SH "DOCUMENTATION"
+.sp
+The libsolv documentation is split into multiple parts:
+.PP
+\fBlibsolv\-history\fR
+.RS 4
+how the libsolv library came into existence
+.RE
+.PP
+\fBlibsolv\-constantids\fR
+.RS 4
+fixed Ids for often used strings
+.RE
+.PP
+\fBlibsolv\-bindings\fR
+.RS 4
+access libsolv from perl/python/ruby
+.RE
+.PP
+\fBlibsolv\-pool\fR
+.RS 4
+libsolv\(cqs pool object
+.RE
+.SH "POINTER VALIDITY"
+.sp
+Note that all pointers to objects that have an Id have only a limited validity period, with the exception of Repo pointers\&. There are only guaranteed to be valid until a new object of that type is added or an object of that type is removed\&. Thus pointers to Solvable objects are only valid until another solvable is created, because adding a Solvable may relocate the Pool\(cqs Solvable array\&. This is also true for Pool strings, you should use solv_strdup() to create a copy of the string if you want to use it at some later time\&. You should use the Ids in the code and not the pointers, except for short times where you know that the pointer is safe\&.
+.sp
+Note also that the data lookup functions or the dataiterator also return values with limited lifetime, this is especially true for data stored in the paged data segment of solv files\&. This is normally data that consists of big strings like package descriptions or is not often needed like package checksums\&. Thus looking up a description of a solvable and then looking up the description of a different solvable or even the checksum of the same solvable may invalidate the first result\&. (The dataiterator supports a dataiterator_strdup() function to create a safe copy\&.)
+.sp
+The language bindings already deal with pointer validity, so you do not have to worry about this issue when using the bindings\&.
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/mdk2solv.1 b/libsolv-0.7.2/doc/gen/mdk2solv.1
new file mode 100644 (file)
index 0000000..ac593f1
--- /dev/null
@@ -0,0 +1,53 @@
+'\" t
+.\"     Title: mdk2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "MDK2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+mdk2solv \- convert files in Mandriva synthesis format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBmdk2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The mdk2solv tool reads Mandriva synthesis data (\fBhdlist\fR) from stdin, and writes it as solv file to standard output\&.
+.PP
+\fB\-i\fR \fIINFO\&.xml\fR
+.RS 4
+Also read the info file containing url, license, and src information from the specified xml file\&.
+.RE
+.PP
+\fB\-f\fR \fIFILES\&.xml\fR
+.RS 4
+Also read filelist information from the specified xml file\&.
+.RE
+.SH "SEE ALSO"
+.sp
+genhdlist2(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/mergesolv.1 b/libsolv-0.7.2/doc/gen/mergesolv.1
new file mode 100644 (file)
index 0000000..65fd756
--- /dev/null
@@ -0,0 +1,45 @@
+'\" t
+.\"     Title: mergesolv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "MERGESOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+mergesolv \- merge multiple files in solv format into a single one
+.SH "SYNOPSIS"
+.sp
+\fBmergesolv\fR [\fIOPTIONS\fR] \fIFILE1\&.solv\fR \fIFILE2\&.solv\fR \&...
+.SH "DESCRIPTION"
+.sp
+The mergesolv tool reads all solv files specified on the command line, and writes a merged version to standard output\&.
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/repo2solv.1 b/libsolv-0.7.2/doc/gen/repo2solv.1
new file mode 100644 (file)
index 0000000..0a8c3cf
--- /dev/null
@@ -0,0 +1,79 @@
+'\" t
+.\"     Title: repo2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 10/22/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "REPO2SOLV" "1" "10/22/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+repo2solv \- convert repository metadata into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBrepo2solv\fR [\fIOPTIONS\fR] \fIDIR\fR
+.SH "DESCRIPTION"
+.sp
+The repo2solv tool converts repository metadata in the directory \fIDIR\fR into a solv file written to standard output\&.
+.sp
+Note that repo2solv does not verify signatures or checksum, it is expected that this is done by the tool that downloads the metadata\&.
+.sp
+If no metadata is detected, repo2solv assumes the "plaindir" format and generates the solv file from all rpm files it finds\&.
+.PP
+\fB\-o\fR \fIOUTFILE\fR
+.RS 4
+Write the solv file to
+\fIOUTFILE\fR
+instead of stdout\&.
+.RE
+.PP
+\fB\-R\fR
+.RS 4
+Also recurse into subdirectories in "plaindir" mode\&.
+.RE
+.PP
+\fB\-F\fR
+.RS 4
+Put the complete filelist in the output\&. The default is to just include the "importent" parts of the file list, except for "plaindir" mode, which always includes all files\&.
+.RE
+.PP
+\fB\-C\fR
+.RS 4
+Add changelog entires to the output\&.
+.RE
+.PP
+\fB\-A\fR
+.RS 4
+Add appdata pseudo packages to the output\&. This is an experimental feature\&.
+.RE
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "SEE ALSO"
+.sp
+dumpsolv(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/repomdxml2solv.1 b/libsolv-0.7.2/doc/gen/repomdxml2solv.1
new file mode 100644 (file)
index 0000000..5d459cc
--- /dev/null
@@ -0,0 +1,57 @@
+'\" t
+.\"     Title: repomdxml2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "REPOMDXML2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+repomdxml2solv \- convert a repomd\&.xml file into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBrepomdxml2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The repomd\&.xml file is the index file of a rpm\-md repository, containing references to all data file with checksums\&. The repomdxml2solv tool reads the repomd\&.xml file from stdin and writes the parsed data as solv file to standard output\&. The data is stored as meta attributes in the result\&.
+.PP
+\fB\-q\fR \fIWHAT\fR
+.RS 4
+Data query mode: instead of writing a solv file, select the
+\fIWHAT\fR
+element in the input data and write it to standard output\&. Examples for
+\fIWHAT\fR
+are
+\fBtype\fR
+to get a list of all types, and
+\fBprimary:location\fR
+to get the location of the element with type
+\fBprimary\fR\&.
+.RE
+.SH "SEE ALSO"
+.sp
+rpmmd2solv(1), mergesolv(1), createrepo(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/rpmdb2solv.1 b/libsolv-0.7.2/doc/gen/rpmdb2solv.1
new file mode 100644 (file)
index 0000000..6f84a7f
--- /dev/null
@@ -0,0 +1,95 @@
+'\" t
+.\"     Title: rpmdb2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "RPMDB2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+rpmdb2solv \- convert the rpm database into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBrpmdb2solv\fR [\fIOPTIONS\fR] [\fIREFFILE\&.solv\fR]
+.SH "DESCRIPTION"
+.sp
+The rpmdb2solv tool reads rpm\(cqs installed packages database and writes it in solv file format to standard output\&. You can make use of an old version of the database by specifying a \fIREFFILE\&.solv\fR file\&.
+.PP
+\fB\-o\fR \fIOUTFILE\fR
+.RS 4
+Write the generated solv to
+\fIOUTFILE\fR
+instead of standard output\&.
+.RE
+.PP
+\fB\-P\fR
+.RS 4
+Print percentages as packages are being read in\&. The output format is like rpm\(cqs \-\-percent option\&.
+.RE
+.PP
+\fB\-r\fR \fIROOTDIR\fR
+.RS 4
+Use
+\fIROOTDIR\fR
+as root directory\&.
+.RE
+.PP
+\fB\-k\fR
+.RS 4
+Read pubkeys from the rpm database instead of installed packages\&. Note that many distributions stopped storing pubkeys in the database but use a directory like
+\fB/var/lib/rpm/pubkeys\fR
+instead\&.
+.RE
+.PP
+\fB\-A\fR
+.RS 4
+Also scan the
+\fB/usr/share/appdata\fR
+for installed appdata files and create pseudo packages for each file\&.
+.RE
+.PP
+\fB\-p\fR \fIPRODDIR\fR
+.RS 4
+Also read SUSE product files from directory
+\fIPRODDIR\fR\&. The standard directory is
+\fB/etc/products\&.d\fR\&.
+.RE
+.PP
+\fB\-n\fR
+.RS 4
+Do not read any packages from the rpm database\&. This is useful together with
+\fB\-p\fR
+to only convert SUSE products\&.
+.RE
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "SEE ALSO"
+.sp
+rpms2solv(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/rpmmd2solv.1 b/libsolv-0.7.2/doc/gen/rpmmd2solv.1
new file mode 100644 (file)
index 0000000..5149a1c
--- /dev/null
@@ -0,0 +1,48 @@
+'\" t
+.\"     Title: rpmmd2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "RPMMD2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+rpmmd2solv \- convert files in rpm\-md format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBrpmmd2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The rpmmd2solv tool reads rpm\-md xml data from stdin, and writes it as solv file to standard output\&. It understands the \fBprimary\fR, \fBfilelist\fR, \fBother\fR, and \fBsusedata\fR format\&.
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "SEE ALSO"
+.sp
+repomdxml2solv(1), mergesolv(1), createrepo(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/rpms2solv.1 b/libsolv-0.7.2/doc/gen/rpms2solv.1
new file mode 100644 (file)
index 0000000..75a89f3
--- /dev/null
@@ -0,0 +1,80 @@
+'\" t
+.\"     Title: rpms2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "RPMS2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+rpms2solv \- convert one or more rpms into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBrpms2solv\fR [\fIOPTIONS\fR] \fIRPM1\&.rpm\fR \&...
+.SH "DESCRIPTION"
+.sp
+The rpms2solv tool converts the header data from one or more rpms into the solv file written to standard output\&.
+.PP
+\fB\-m\fR \fIMANIFESTFILE\fR
+.RS 4
+Read the rpm file names from the specified
+\fIMANIFESTFILE\fR\&. You can use
+\fB\-\fR
+to read the manifest from standard input\&.
+.RE
+.PP
+\fB\-0\fR
+.RS 4
+Use a null byte as line terminator for manifest files instead of a newline\&. This is useful if the file names can contain newlines\&. See also the
+\fB\-print0\fR
+option in
+\fBfind\fR\&.
+.RE
+.PP
+\fB\-F\fR
+.RS 4
+Do not put all files from the headers into the file list, but instead use the filtering also found in
+\fBcreaterepo\fR\&.
+.RE
+.PP
+\fB\-k\fR
+.RS 4
+Read pubkeys instead of rpms\&.
+.RE
+.PP
+\fB\-K\fR
+.RS 4
+Read pubkey keyrings instead of rpms\&.
+.RE
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "SEE ALSO"
+.sp
+rpmdb2solv(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/solv.1 b/libsolv-0.7.2/doc/gen/solv.1
new file mode 100644 (file)
index 0000000..aae1c6d
--- /dev/null
@@ -0,0 +1,102 @@
+'\" t
+.\"     Title: solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 10/22/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "SOLV" "1" "10/22/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+solv \- example package manager based on libsolv
+.SH "SYNOPSIS"
+.sp
+\fBsolv\fR install [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR erase [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR list [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR info [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR search [OPTIONS] STRING\&...
+.sp
+\fBsolv\fR verify [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR update [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR dist\-upgrade [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR repolist [OPTIONS]
+.SH "DESCRIPTION"
+.sp
+The solv tool demos some features of the libsolv library\&. It is not meant to replace a real package manager, for example it does not cache downloaded packages\&.
+.PP
+\fB\-\-root\fR \fIROOTDIR\fR
+.RS 4
+Install packages using
+\fIROOTDIR\fR
+as root of the filesystem\&. This also means that the package database of
+\fIROOTDIR\fR
+will be used\&.
+.RE
+.PP
+\fB\-\-clean\fR
+.RS 4
+Also get rid of no longer needed packages when erasing, like libraries that have been used by the erased packages\&.
+.RE
+.PP
+\fB\-\-best\fR
+.RS 4
+Force usage of the best package (normally the one with the highest version) for install and update operations\&.
+.RE
+.PP
+\fB\-\-testcase\fR
+.RS 4
+Write a testcase after dependency solving\&.
+.RE
+.sp
+The following options can be used to filter the packages\&. If the same option is used multiple times, the result is ORed together\&.
+.PP
+\fB\-i\fR
+.RS 4
+Limit the packages to installed ones\&.
+.RE
+.PP
+\fB\-r\fR \fIREPO\fR
+.RS 4
+Limit the packages to the specified repository\&.
+.RE
+.PP
+\fB\-\-arch\fR \fIARCHITECTURE\fR
+.RS 4
+Limit the packages to the specified package architecture\&.
+.RE
+.PP
+\fB\-\-type\fR \fITYPE\fR
+.RS 4
+Limit the packages to the specified package type\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/susetags2solv.1 b/libsolv-0.7.2/doc/gen/susetags2solv.1
new file mode 100644 (file)
index 0000000..8dd83d4
--- /dev/null
@@ -0,0 +1,66 @@
+'\" t
+.\"     Title: susetags2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "SUSETAGS2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+susetags2solv \- convert the susetags repository format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBsusetags2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The susetags format is most as repository format on most products created by SUSE\&. The susetags2solv reads data from standard input, converts the format into a solv file, and writes it to standard output\&.
+.PP
+\fB\-c\fR \fICONTENTFILE\fR
+.RS 4
+Also parse the specified content file containing meta information about the repository\&.
+.RE
+.PP
+\fB\-q\fR \fIWHAT\fR
+.RS 4
+Data query mode: instead of writing a solv file, select the
+\fIWHAT\fR
+element in the input data and write it to standard output\&. An example for
+\fIWHAT\fR
+is
+\fBdefaultvendor\fR
+to get a default vendor for the repository\&.
+.RE
+.PP
+\fB\-M\fR \fIMERGEFILE\&.solv\fR
+.RS 4
+Merge the content of the specified solv file into the output\&.
+.RE
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/testsolv.1 b/libsolv-0.7.2/doc/gen/testsolv.1
new file mode 100644 (file)
index 0000000..50254f7
--- /dev/null
@@ -0,0 +1,62 @@
+'\" t
+.\"     Title: testsolv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "TESTSOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+testsolv \- run a libsolv testcase through the solver
+.SH "SYNOPSIS"
+.sp
+\fBtestsolv\fR [\fIOPTIONS\fR] \fITESTCASE\fR
+.SH "DESCRIPTION"
+.sp
+The testsolv tools can be used to run a testcase\&. Testcases can either be manually created to test specific features, or they can be written by libsolv\(cqs testcase_write function\&. This is useful to evaluate bug reports about the solver\&.
+.PP
+\fB\-v\fR
+.RS 4
+Increase the debug level of the solver\&. This option can be specified multiple times to further increase the amount of debug data\&.
+.RE
+.PP
+\fB\-r\fR
+.RS 4
+Write the output in testcase format instead of human readable text\&. The output can then be used in the result section of the test case\&. If the
+\fB\-r\fR
+option is given twice, the output is formated for verbatim inclusion\&.
+.RE
+.PP
+\fB\-l\fR \fIPKGSPEC\fR
+.RS 4
+Instead of running the solver, list packages in the repositories\&.
+.RE
+.PP
+\fB\-s\fR \fISOLUTIONSPEC\fR
+.RS 4
+This is used in the solver test suite to test the calculated solutions to encountered problems\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/gen/updateinfoxml2solv.1 b/libsolv-0.7.2/doc/gen/updateinfoxml2solv.1
new file mode 100644 (file)
index 0000000..aa60372
--- /dev/null
@@ -0,0 +1,43 @@
+'\" t
+.\"     Title: updateinfoxml2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 09/14/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "UPDATEINFOXML2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+updateinfoxml2solv \- convert rpm\-md\*(Aqs updateinfo\&.xml format into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBupdateinfoxml2solv\fR [\fIOPTIONS\fR]
+.SH "DESCRIPTION"
+.sp
+The updateinfoxml2solv tool reads rpm\-md\(cqs updateinfo xml data from stdin, and writes it as solv file to standard output\&. Update elements are converted into special \fBpatch:\fR pseudo packages\&.
+.SH "SEE ALSO"
+.sp
+mergesolv(1), createrepo(8)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/libsolv-0.7.2/doc/helix2solv.txt b/libsolv-0.7.2/doc/helix2solv.txt
new file mode 100644 (file)
index 0000000..40d523a
--- /dev/null
@@ -0,0 +1,28 @@
+helix2solv(1)
+=============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+helix2solv - convert legacy helixcode format into a solv file
+
+Synopsis
+--------
+*helix2solv*
+
+Description
+-----------
+The helix format was a metadata format used in the RedCarpet
+package manager. It's still used in libzypp testcases.
+The helix2solv tool reads data in helix format from standard
+input and writes it in solv file format to standard output.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/installcheck.txt b/libsolv-0.7.2/doc/installcheck.txt
new file mode 100644 (file)
index 0000000..5780772
--- /dev/null
@@ -0,0 +1,33 @@
+installcheck(1)
+===============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+installcheck - find out which packages cannot be installed
+
+Synopsis
+--------
+*installcheck* 'ARCH' 'REPO1' 'REPO2'... *--nocheck* 'NREPO1' 'NREPO2'...
+
+Description
+-----------
+The installcheck tool checks if all packages in 'REPO1'...'REPON' are
+installable. A package is installable if there is a set of packages
+from the repositories that satisfies its dependencies. The repositories
+after the *--nocheck* option are only used for dependency resolving,
+but the tool does not check if the packages in them are installable.
+
+A Repository can be a solv file, a rpmmd *primary.xml.gz* file, a SUSE
+*packages* or *packages.gz* file, or a Debian *Packages* or *Packages.gz*
+file.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/libsolv-bindings.txt b/libsolv-0.7.2/doc/libsolv-bindings.txt
new file mode 100644 (file)
index 0000000..e458246
--- /dev/null
@@ -0,0 +1,3720 @@
+Libsolv-Bindings(3)
+===================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+libsolv-bindings - access libsolv from perl/python/ruby
+
+
+Description
+-----------
+Libsolv's language bindings offer an abstract, object orientated interface
+to the library. The supported languages are currently perl, python, and ruby.
+All example code (except in the specifics sections, of course) lists first
+the ``C-ish'' interface, then the syntax for perl, python, and ruby (in that
+order).
+
+
+Perl Specifics
+--------------
+Libsolv's perl bindings can be loaded with the following statement:
+
+       use solv;
+
+Objects are either created by calling the new() method on a class or they
+are returned by calling methods on other objects.
+
+       my $pool = solv::Pool->new();
+       my $repo = $pool->add_repo("my_first_repo");
+
+Swig encapsulates all objects as tied hashes, thus the attributes can be
+accessed by treating the object as standard hash reference:
+
+       $pool->{appdata} = 42;
+       printf "appdata is %d\n", $pool->{appdata};
+
+A special exception to this are iterator objects, they are encapsulated as
+tied arrays so that it is possible to iterate with a for() statement:
+
+       my $iter = $pool->solvables_iter();
+       for my $solvable (@$iter) { ... };
+
+As a downside of this approach, iterator objects cannot have attributes.
+
+If an array needs to be passed to a method it is usually done by reference,
+if a method returns an array it returns it on the perl stack:
+
+       my @problems = $solver->solve(\@jobs);
+
+Due to a bug in swig, stringification does not work for libsolv's objects.
+Instead, you have to call the object's str() method.
+
+       print $dep->str() . "\n";
+
+Swig implements all constants as numeric variables (instead of the more
+natural constant subs), so don't forget the leading ``$'' when accessing a
+constant. Also do not forget to prepend the namespace of the constant:
+
+       $pool->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1);
+       
+
+Python Specifics
+----------------
+The python bindings can be loaded with:
+
+       import solv
+
+Objects are either created by calling the constructor method for a class or they
+are returned by calling methods on other objects.
+
+       pool = solv.Pool()
+       repo = pool.add_repo("my_first_repo")
+
+Attributes can be accessed as usual:
+
+       pool.appdata = 42
+       print "appdata is %d" % (pool.appdata)
+
+Iterators also work as expected:
+
+       for solvable in pool.solvables_iter():
+
+Arrays are passed and returned as list objects:
+
+       jobs = []
+       problems = solver.solve(jobs)
+
+The bindings define stringification for many classes, some also have a
+__repr__ method to ease debugging.
+
+       print dep
+       print repr(repo)
+
+Constants are attributes of the corresponding classes:
+
+       pool.set_flag(solv.Pool.POOL_FLAG_OBSOLETEUSESCOLORS, 1);
+
+
+Ruby Specifics
+--------------
+The ruby bindings can be loaded with:
+
+       require 'solv'
+
+Objects are either created by calling the new method on a class or they
+are returned by calling methods on other objects. Note that all classes start
+with an uppercase letter in ruby, so the class is called ``Solv''.
+
+       pool = Solv::Pool.new
+       repo = pool.add_repo("my_first_repo")
+
+Attributes can be accessed as usual:
+
+       pool.appdata = 42
+       puts "appdata is #{pool.appdata}"
+
+Iterators also work as expected:
+
+       for solvable in pool.solvables_iter() do ...
+
+Arrays are passed and returned as array objects:
+
+       jobs = []
+       problems = solver.solve(jobs)
+
+Most classes define a to_s method, so objects can be easily stringified.
+Many also define an inspect() method.
+
+       puts dep
+       puts repo.inspect
+
+Constants live in the namespace of the class they belong to:
+
+       pool.set_flag(Solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1);
+
+Note that boolean methods have an added trailing ``?'', to be consistent with
+other ruby modules:
+
+       puts "empty" if repo.isempty?
+
+
+Tcl Specifics
+-------------
+Libsolv's tcl bindings can be loaded with the following statement:
+
+       TCL package require solv
+
+Objects are either created by calling class name prefixed with ``new_'',
+or they are returned by calling methods on other objects.
+
+       TCL set pool [solv::new_Pool]
+       TCL set repo [$pool add_repo "my_first_repo"]
+
+Swig provides a ``cget'' method to read object attributes, and a
+``configure'' method to write them:
+
+       TCL $pool configure -appdata 42
+       TCL puts "appdata is [$pool cget -appdata]"
+
+The tcl bindings provide a little helper to work with iterators in
+a foreach style:
+
+       TCL set iter [$pool solvables_iter]
+       TCL solv::iter s $iter { ... }
+
+libsolv's arrays are mapped to tcl's lists:
+
+       TCL set jobs [list $job1 $job2]
+       TCL set problems [$solver solve $jobs]
+       TCL puts "We have [llength $problems] problems..."
+
+Stringification is done by calling the object's ``str'' method.
+
+       TCL puts [$dep str]
+
+There is one exception: you have to use ``stringify'' for Datamatch
+objects, as swig reports a clash with the ``str'' attribute.
+Some objects also support a ``=='' method for equality tests, and a
+``!='' method.
+
+Swig implements all constants as numeric variables, constants belonging
+to a libsolv class are prefixed with the class name:
+
+       TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS 1
+       TCL puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY]
+       
+
+The Solv Class
+--------------
+This is the main namespace of the library, you cannot create objects of this
+type but it contains some useful constants.
+
+=== CONSTANTS ===
+
+Relational flag constants, the first three can be or-ed together
+
+*REL_LT*::
+the ``less than'' bit
+
+*REL_EQ*::
+the ``equals to'' bit
+
+*REL_GT*::
+the ``greater than'' bit
+
+*REL_ARCH*::
+used for relations that describe an extra architecture filter, the
+version part of the relation is interpreted as architecture.
+
+Special Solvable Ids
+
+*SOLVID_META*::
+Access the meta section of a repository or repodata area. This is
+like an extra Solvable that has the Id SOLVID_META.
+
+*SOLVID_POS*::
+Use the data position stored inside of the pool instead of accessing
+some solvable by Id. The bindings have the Datapos objects as an
+abstraction mechanism, so you most likely do not need this constant.
+
+Constant string Ids
+
+*ID_NULL*::
+Always zero
+
+*ID_EMPTY*::
+Always one, describes the empty string
+
+*SOLVABLE_NAME*::
+The keyname Id of the name of the solvable.
+
+*...*::
+see the libsolv-constantids manpage for a list of fixed Ids.
+
+
+The Pool Class
+--------------
+The pool is libsolv's central resource manager. A pool consists of Solvables,
+Repositories, Dependencies, each indexed by Ids.
+
+=== CLASS METHODS ===
+
+       Pool *Pool()
+       my $pool = solv::Pool->new();
+       pool = solv.Pool()
+       pool = Solv::Pool.new()
+
+Create a new pool instance. In most cases you just need one pool.
+Note that the returned object "owns" the pool, i.e. if the object is 
+freed, the pool is also freed. You can use the disown method to
+break this ownership relation.
+
+=== ATTRIBUTES ===
+
+       void *appdata;                  /* read/write */
+       $pool->{appdata}
+       pool.appdata
+       pool.appdata
+
+Application specific data that may be used in any way by the code using the
+pool.
+
+       Solvable solvables[];           /* read only */
+       my $solvable = $pool->{solvables}->[$solvid];
+       solvable = pool.solvables[solvid]
+       solvable = pool.solvables[solvid]
+
+Look up a Solvable by its id.
+
+       Repo repos[];                   /* read only */
+       my $repo = $pool->{repos}->[$repoid];
+       repo = pool.repos[repoid]
+       repo = pool.repos[repoid]
+
+Look up a Repository by its id.
+
+       Repo *installed;                /* read/write */
+       $pool->{installed} = $repo;
+       pool.installed = repo
+       pool.installed = repo
+
+Define which repository contains all the installed packages.
+
+       const char *errstr;             /* read only */
+       my $err = $pool->{errstr};
+       err = pool.errstr
+       err = pool.errstr
+
+Return the last error string that was stored in the pool.
+
+=== CONSTANTS ===
+
+*POOL_FLAG_PROMOTEEPOCH*::
+Promote the epoch of the providing dependency to the requesting
+dependency if it does not contain an epoch. Used at some time
+in old rpm versions, modern systems should never need this.
+
+*POOL_FLAG_FORBIDSELFCONFLICTS*::
+Disallow the installation of packages that conflict with themselves.
+Debian always allows self-conflicting packages, rpm used to forbid
+them but switched to also allowing them since rpm-4.9.0.
+
+*POOL_FLAG_OBSOLETEUSESPROVIDES*::
+Make obsolete type dependency match against provides instead of
+just the name and version of packages. Very old versions of rpm
+used the name/version, then it got switched to provides and later
+switched back again to just name/version.
+
+*POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES*::
+An implicit obsoletes is the internal mechanism to remove the
+old package on an update. The default is to remove all packages
+with the same name, rpm-5 switched to also removing packages
+providing the same name.
+
+*POOL_FLAG_OBSOLETEUSESCOLORS*::
+Rpm's multilib implementation distinguishes between 32bit and 64bit
+packages (the terminology is that they have a different color).
+If obsoleteusescolors is set, packages with different colors will
+not obsolete each other.
+
+*POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*::
+Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if
+packages of the same name can be installed in parallel. For
+current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be
+false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true
+(this is the default if FEDORA is defined when libsolv is compiled).
+
+*POOL_FLAG_NOINSTALLEDOBSOLETES*::
+Since version 4.9.0 rpm considers the obsoletes of installed packages
+when checking for dependency conflicts, thus you may not install a
+package that is obsoleted by some other installed package unless you
+also erase the other package.
+
+*POOL_FLAG_HAVEDISTEPOCH*::
+Mandriva added a new field called distepoch that gets checked in
+version comparison if the epoch/version/release of two packages
+are the same.
+
+*POOL_FLAG_NOOBSOLETESMULTIVERSION*::
+If a package is installed in multiversion mode, rpm used to ignore
+both the implicit obsoletes and the obsolete dependency of a
+package. This was changed to ignoring just the implicit obsoletes,
+thus you may install multiple versions of the same name, but
+obsoleted packages still get removed.
+
+*POOL_FLAG_ADDFILEPROVIDESFILTERED*::
+Make the addfileprovides method only add files from the standard
+locations (i.e. the ``bin'' and ``etc'' directories). This is
+useful if you have only few packages that use non-standard file
+dependencies, but you still want the fast speed that addfileprovides()
+generates.
+
+=== METHODS ===
+
+       void free()
+       $pool->free();
+       pool.free()
+       pool.free()
+
+Force a free of the pool. After this call, you must not access any object
+that still references the pool.
+
+       void disown()
+       $pool->disown();
+       pool.disown()
+       pool.disown()
+
+Break the ownership relation between the binding object and the pool. After
+this call, the pool will not get freed even if the object goes out of
+scope. This also means that you must manually call the free method to free
+the pool data.
+
+       void setdebuglevel(int level)
+       $pool->setdebuglevel($level);
+       pool.setdebuglevel(level)
+       pool.setdebuglevel(level)
+
+Set the debug level. A value of zero means no debug output, the higher the
+value, the more output is generated.
+
+       int set_flag(int flag, int value)
+       my $oldvalue = $pool->set_flag($flag, $value);
+       oldvalue = pool.set_flag(flag, value)
+       oldvalue = pool.set_flag(flag, value)
+
+       int get_flag(int flag)
+       my $value = $pool->get_flag($flag);
+       value = pool.get_flag(flag)
+       value = pool.get_flag(flag)
+
+Set/get a pool specific flag. The flags define how the system works, e.g. how
+the package manager treats obsoletes. The default flags should be sane for most
+applications, but in some cases you may want to tweak a flag, for example if
+you want to solve package dependencies for some other system.
+
+       void set_rootdir(const char *rootdir)
+       $pool->set_rootdir(rootdir);
+       pool.set_rootdir(rootdir)
+       pool.set_rootdir(rootdir)
+
+       const char *get_rootdir()
+       my $rootdir = $pool->get_rootdir();
+       rootdir = pool.get_rootdir()
+       rootdir = pool.get_rootdir()
+
+Set/get the rootdir to use. This is useful if you want package management
+to work only in some directory, for example if you want to setup a chroot
+jail. Note that the rootdir will only be prepended to file paths if the
+*REPO_USE_ROOTDIR* flag is used.
+
+       void setarch(const char *arch = 0)
+       $pool->setarch();
+       pool.setarch()
+       pool.setarch()
+
+Set the architecture for your system. The architecture is used to determine
+which packages are installable. It defaults to the result of ``uname -m''.
+
+       Repo add_repo(const char *name)
+       $repo = $pool->add_repo($name);
+       repo = pool.add_repo(name)
+       repo = pool.add_repo(name)
+
+Add a Repository with the specified name to the pool. The repository is empty
+on creation, use the repository methods to populate it with packages.
+
+       Repoiterator repos_iter()
+       for my $repo (@{$pool->repos_iter()})
+       for repo in pool.repos_iter():
+       for repo in pool.repos_iter()
+
+Iterate over the existing repositories.
+
+       Solvableiterator solvables_iter()
+       for my $solvable (@{$pool->solvables_iter()})
+       for solvable in pool.solvables_iter():
+       for solvable in pool.solvables_iter()
+
+Iterate over the existing solvables.
+
+       Dep Dep(const char *str, bool create = 1)
+       my $dep = $pool->Dep($string);
+       dep = pool.Dep(string)
+       dep = pool.Dep(string)
+
+Create an object describing a string or dependency. If the string is currently
+not in the pool and _create_ is false, *undef*/*None*/*nil* is returned.
+
+       void addfileprovides()
+       $pool->addfileprovides();
+       pool.addfileprovides()
+       pool.addfileprovides()
+
+       Id *addfileprovides_queue()
+       my @ids = $pool->addfileprovides_queue();
+       ids = pool.addfileprovides_queue()
+       ids = pool.addfileprovides_queue()
+
+Some package managers like rpm allow dependencies on files contained in other
+packages. To allow libsolv to deal with those dependencies in an efficient way,
+you need to call the addfileprovides method after creating and reading all
+repositories. This method will scan all dependency for file names and then scan
+all packages for matching files. If a filename has been matched, it will be
+added to the provides list of the corresponding package. The
+addfileprovides_queue variant works the same way but returns an array
+containing all file dependencies. This information can be stored in the
+meta section of the repositories to speed up the next time the
+repository is loaded and addfileprovides is called.
+
+       void createwhatprovides()
+       $pool->createwhatprovides();
+       pool.createwhatprovides()
+       pool.createwhatprovides()
+
+Create the internal ``whatprovides'' hash over all of the provides of all
+installable packages. This method must be called before doing any lookups on
+provides.
+It's encouraged to do it right after all repos are set up, usually right after
+the call to addfileprovides().
+
+       Solvable *whatprovides(DepId dep)
+       my @solvables = $pool->whatprovides($dep);
+       solvables = pool.whatprovides(dep)
+       solvables = pool.whatprovides(dep)
+
+Return all solvables that provide the specified dependency. You can use either
+a Dep object or a simple Id as argument.
+
+       Id *matchprovidingids(const char *match, int flags)
+       my @ids = $pool->matchprovidingids($match, $flags);
+       ids = pool.matchprovidingids(match, flags)
+       ids = pool.matchprovidingids(match, flags)
+
+Search the names of all provides and return the ones matching the specified
+string. See the Dataiterator class for the allowed flags.
+
+       Id towhatprovides(Id *ids)
+       my $offset = $pool->towhatprovides(\@ids);
+       offset = pool.towhatprovides(ids)
+       offset = pool.towhatprovides(ids)
+
+``Internalize'' an array containing Ids. The returned value can be used to
+create solver jobs working on a specific set of packages. See the Solver class
+for more information.
+
+       void set_namespaceproviders(DepId ns, DepId evr, bool value = 1)
+       $pool->set_namespaceproviders($ns, $evr, 1);
+       pool.set_namespaceproviders(ns, evr, True)
+       pool.set_namespaceproviders(ns, evr, true)
+
+Manually set a namespace provides entry in the whatprovides index.
+
+       void flush_namespaceproviders(DepId ns, DepId evr)
+       $pool->flush_namespaceproviders($ns, $evr);
+       $pool.flush_namespaceproviders(ns, evr)
+       $pool.flush_namespaceproviders(ns, evr)
+
+Flush the cache of all namespaceprovides matching the specified namespace
+dependency. You can use zero as a wildcard argument.
+
+       bool isknownarch(DepId id)
+       my $bool = $pool->isknownarch($id);
+       bool = pool.isknownarch(id)
+       bool = pool.isknownarch?(id)
+
+Return true if the specified Id describes a known architecture.
+
+       Solver Solver()
+       my $solver = $pool->Solver();
+       solver = pool.Solver()
+       solver = pool.Solver()
+
+Create a new solver object.
+
+       Job Job(int how, Id what)
+       my $job = $pool->Job($how, $what);
+       job = pool.Job(how, what)
+       job = pool.Job(how, what)
+
+Create a new Job object. Kind of low level, in most cases you would
+instead use a Selection or Dep job constructor.
+
+       Selection Selection()
+       my $sel = $pool->Selection();
+       sel = pool.Selection()
+       sel = pool.Selection()
+
+Create an empty selection. Useful as a starting point for merging other
+selections.
+
+       Selection Selection_all()
+       my $sel = $pool->Selection_all();
+       sel = pool.Selection_all()
+       sel = pool.Selection_all()
+       
+Create a selection containing all packages. Useful as starting point for
+intersecting other selections or for update/distupgrade jobs.
+
+       Selection select(const char *name, int flags)
+       my $sel = $pool->select($name, $flags);
+       sel = pool.select(name, flags)
+       sel = pool.select(name, flags)
+
+Create a selection by matching packages against the specified string. See the
+Selection class for a list of flags and how to create solver jobs from a
+selection.
+
+       Selection matchdeps(const char *name, int flags, Id keyname, Id marker = -1)
+       my $sel = $pool->matchdeps($name, $flags, $keyname);
+       sel = pool.matchdeps(name, flags, keyname)
+       sel = pool.matchdeps(name, flags, keyname)
+
+Create a selection by matching package dependencies against the specified string.
+This can be used if you want to match other dependency types than ``provides''.
+
+       Selection matchdepid(DepId dep, int flags, Id keyname, Id marker = -1)
+       my $sel = $pool->matchdepid(dep, $flags, $keyname);
+       sel = pool.matchdepid(dep, flags, keyname)
+       sel = pool.matchdepid(dep, flags, keyname)
+
+Create a selection by matching package dependencies against the specified
+dependency. This may be faster than matchdeps and also works with complex
+dependencies. The downside is that you cannot use globs or case insensitive
+matching.
+
+       void setpooljobs(Jobs *jobs)
+       $pool->setpooljobs(\@jobs);
+       pool.setpooljobs(jobs)
+       pool.setpooljobs(jobs)
+
+       Job *getpooljobs()
+       @jobs = $pool->getpooljobs();
+       jobs = pool.getpooljobs()
+       jobs = pool.getpooljobs()
+
+Get/Set fixed jobs stored in the pool. Those jobs are automatically appended to
+all solver jobs, they are meant for fixed configurations like which packages
+can be multiversion installed, which packages were userinstalled, or which
+packages must not be erased.
+
+       void set_loadcallback(Callable *callback)
+       $pool->setloadcallback(\&callbackfunction);
+       pool.setloadcallback(callbackfunction)
+       pool.setloadcallback { |repodata| ... }
+
+Set the callback function called when repository metadata needs to be loaded on
+demand. To make use of this feature, you need to create repodata stubs that
+tell the library which data is available but not loaded. If later on the data
+needs to be accessed, the callback function is called with a repodata argument.
+You can then load the data (maybe fetching it first from a remote server).
+The callback should return true if the data has been made available.
+
+       /* bindings only */
+       $pool->appdata_disown()
+       pool.appdata_disown()
+       pool.appdata_disown()
+
+Decrement the reference count of the appdata object. This can be used to break
+circular references (e.g. if the pool's appdata value points to some meta data
+structure that contains a pool handle). If used incorrectly, this method can
+lead to application crashes, so beware. (This method is a no-op for ruby and tcl.)
+
+=== DATA RETRIEVAL METHODS ===
+
+In the following functions, the _keyname_ argument describes what to retrieve.
+For the standard cases you can use the available Id constants. For example,
+
+       $solv::SOLVABLE_SUMMARY
+       solv.SOLVABLE_SUMMARY
+       Solv::SOLVABLE_SUMMARY
+
+selects the ``Summary'' entry of a solvable. The _solvid_ argument selects the
+desired solvable by Id.
+
+       const char *lookup_str(Id solvid, Id keyname)
+       my $string = $pool->lookup_str($solvid, $keyname);
+       string = pool.lookup_str(solvid, keyname)
+       string = pool.lookup_str(solvid, keyname)
+
+       Id lookup_id(Id solvid, Id keyname)
+       my $id = $pool->lookup_id($solvid, $keyname);
+       id = pool.lookup_id(solvid, keyname)
+       id = pool.lookup_id(solvid, keyname)
+
+       unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0)
+       my $num = $pool->lookup_num($solvid, $keyname);
+       num = pool.lookup_num(solvid, keyname)
+       num = pool.lookup_num(solvid, keyname)
+
+       bool lookup_void(Id solvid, Id keyname)
+       my $bool = $pool->lookup_void($solvid, $keyname);
+       bool = pool.lookup_void(solvid, keyname)
+       bool = pool.lookup_void(solvid, keyname)
+
+       Id *lookup_idarray(Id solvid, Id keyname)
+       my @ids = $pool->lookup_idarray($solvid, $keyname);
+       ids = pool.lookup_idarray(solvid, keyname)
+       ids = pool.lookup_idarray(solvid, keyname)
+
+       Chksum lookup_checksum(Id solvid, Id keyname)
+       my $chksum = $pool->lookup_checksum($solvid, $keyname);
+       chksum = pool.lookup_checksum(solvid, keyname)
+       chksum = pool.lookup_checksum(solvid, keyname)
+
+Lookup functions. Return the data element stored in the specified solvable.
+You should probably use the methods of the Solvable class instead.
+
+       Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0)
+       my $di = $pool->Dataiterator($keyname, $match, $flags);
+       di = pool.Dataiterator(keyname, match, flags)
+       di = pool.Dataiterator(keyname, match, flags)
+
+       Dataiterator Dataiterator_solvid(Id solvid, Id keyname, const char *match = 0, int flags = 0)
+       my $di = $pool->Dataiterator($solvid, $keyname, $match, $flags);
+       di = pool.Dataiterator(solvid, keyname, match, flags)
+       di = pool.Dataiterator(solvid, keyname, match, flags)
+
+       for my $d (@$di)
+       for d in di:
+       for d in di
+
+Iterate over the matching data elements. See the Dataiterator class for more
+information. The Dataiterator method iterates over all solvables in the pool,
+whereas the Dataiterator_solvid only iterates over the specified solvable.
+
+=== ID METHODS ===
+
+The following methods deal with Ids, i.e. integers representing objects in the
+pool. They are considered ``low level'', in most cases you would not use them
+but instead the object orientated methods.
+
+       Repo id2repo(Id id)
+       $repo = $pool->id2repo($id);
+       repo = pool.id2repo(id)
+       repo = pool.id2repo(id)
+
+Lookup an existing Repository by id. You can also do this by using the *repos*
+attribute.
+
+       Solvable id2solvable(Id id)
+       $solvable = $pool->id2solvable($id);
+       solvable = pool.id2solvable(id)
+       solvable = pool.id2solvable(id)
+
+Lookup an existing Repository by id. You can also do this by using the
+*solvables* attribute.
+
+       const char *solvid2str(Id id)
+       my $str = $pool->solvid2str($id);
+       str = pool.solvid2str(id)
+       str = pool.solvid2str(id)
+
+Return a string describing the Solvable with the specified id. The string
+consists of the name, version, and architecture of the Solvable.
+
+       Id str2id(const char *str, bool create = 1)
+       my $id = pool->str2id($string);
+       id = pool.str2id(string)
+       id = pool.str2id(string)
+
+       const char *id2str(Id id)
+       $string = pool->id2str($id);
+       string = pool.id2str(id)
+       string = pool.id2str(id)
+
+Convert a string into an Id and back. If the string is currently not in the
+pool and _create_ is false, zero is returned.
+
+       Id rel2id(Id name, Id evr, int flags, bool create = 1)
+       my $id = pool->rel2id($nameid, $evrid, $flags);
+       id = pool.rel2id(nameid, evrid, flags)
+       id = pool.rel2id(nameid, evrid, flags)
+
+Create a ``relational'' dependency. Such dependencies consist of a name part,
+_flags_ describing the relation, and a version part. The flags are:
+
+       $solv::REL_EQ | $solv::REL_GT | $solv::REL_LT
+       solv.REL_EQ | solv.REL_GT | solv.REL_LT
+       Solv::REL_EQ | Solv::REL_GT | Solv::REL_LT
+
+Thus, if you want a ``\<='' relation, you would use *REL_LT | REL_EQ*.
+
+       Id id2langid(Id id, const char *lang, bool create = 1)
+       my $id = $pool->id2langid($id, $language);
+       id = pool.id2langid(id, language)
+       id = pool.id2langid(id, language)
+
+Create a language specific Id from some other id. This function simply converts
+the id into a string, appends a dot and the specified language to the string
+and converts the result back into an Id.
+
+       const char *dep2str(Id id)
+       $string = pool->dep2str($id);
+       string = pool.dep2str(id)
+       string = pool.dep2str(id)
+
+Convert a dependency id into a string. If the id is just a string, this
+function has the same effect as id2str(). For relational dependencies, the
+result is the correct ``name relation evr'' string.
+
+
+The Dependency Class
+--------------------
+The dependency class is an object orientated way to work with strings and
+dependencies. Internally, dependencies are represented as Ids, i.e. simple
+numbers. Dependency objects can be constructed by using the Pool's Dep()
+method.
+
+=== ATTRIBUTES ===
+
+       Pool *pool;             /* read only */
+       $dep->{pool}
+       dep.pool
+       dep.pool
+
+Back reference to the pool this dependency belongs to.
+
+       Id id;          /* read only */
+       $dep->{id}
+       dep.id
+       dep.id
+
+The id of this dependency.
+
+== Methods ==
+
+       Dep Rel(int flags, DepId evrid, bool create = 1)
+       my $reldep = $dep->Rel($flags, $evrdep);
+       reldep = dep.Rel(flags, evrdep)
+       reldep = dep.Rel(flags, evrdep)
+
+Create a relational dependency from the caller dependency, the flags,
+and a dependency describing the ``version'' part.
+See the pool's rel2id method for a description of the flags.
+
+       Selection Selection_name(int setflags = 0)
+       my $sel = $dep->Selection_name();
+       sel = dep.Selection_name()
+       sel = dep.Selection_name()
+
+Create a Selection from a dependency. The selection consists of all packages
+that have a name equal to the dependency. If the dependency is of a relational
+type, the packages version must also fulfill the dependency.
+
+       Selection Selection_provides(int setflags = 0)
+       my $sel = $dep->Selection_provides();
+       sel = dep.Selection_provides()
+       sel = dep.Selection_provides()
+
+Create a Selection from a dependency. The selection consists of all packages
+that have at least one provides matching the dependency.
+
+       const char *str()
+       my $str = $dep->str();
+       str = $dep.str()
+       str = $dep.str()
+
+Return a string describing the dependency.
+
+       <stringification>
+       my $str = $dep->str;
+       str = str(dep)
+       str = dep.to_s
+
+Same as calling the str() method.
+
+       <equality>
+       if ($dep1 == $dep2)
+       if dep1 == dep2:
+       if dep1 == dep2
+
+Two dependencies are equal if they are part of the same pool and have the same
+ids.
+
+
+The Repository Class
+--------------------
+A Repository describes a group of packages, normally coming from the same
+source. Repositories are created by the Pool's add_repo() method.
+
+=== ATTRIBUTES ===
+
+       Pool *pool;                     /* read only */
+       $repo->{pool}
+       repo.pool
+       repo.pool
+
+Back reference to the pool this dependency belongs to.
+
+       Id id;                          /* read only */
+       $repo->{id}
+       repo.id
+       repo.id
+
+The id of the repository.
+
+       const char *name;               /* read/write */
+       $repo->{name}
+       repo.name
+       repo.name
+       
+The repositories name. To libsolv, the name is just a string with no specific
+meaning.
+
+       int priority;                   /* read/write */
+       $repo->{priority}
+       repo.priority
+       repo.priority
+
+The priority of the repository. A higher number means that packages of this
+repository will be chosen over other repositories, even if they have a greater
+package version.
+
+       int subpriority;                /* read/write */
+       $repo->{subpriority}
+       repo.subpriority
+       repo.subpriority
+
+The sub-priority of the repository. This value is compared when the priorities
+of two repositories are the same. It is useful to make the library prefer
+on-disk repositories to remote ones.
+
+       int nsolvables;                 /* read only */
+       $repo->{nsolvables}
+       repo.nsolvables
+       repo.nsolvables
+
+The number of solvables in this repository.
+
+       void *appdata;                  /* read/write */
+       $repo->{appdata}
+       repo.appdata
+       repo.appdata
+
+Application specific data that may be used in any way by the code using the
+repository.
+
+       Datapos *meta;                  /* read only */
+       $repo->{meta}
+       repo.meta
+       repo.meta
+
+Return a Datapos object of the repodata's metadata. You can use the lookup
+methods of the Datapos class to lookup metadata attributes, like the repository
+timestamp.
+
+=== CONSTANTS ===
+
+*REPO_REUSE_REPODATA*::
+Reuse the last repository data area (``repodata'') instead of creating a
+new area.
+
+*REPO_NO_INTERNALIZE*::
+Do not internalize the added repository data. This is useful if
+you plan to add more data because internalization is a costly
+operation.
+
+*REPO_LOCALPOOL*::
+Use the repodata's pool for Id storage instead of the global pool. Useful
+if you don't want to pollute the global pool with many unneeded ids, like
+when storing the filelist.
+
+*REPO_USE_LOADING*::
+Use the repodata that is currently being loaded instead of creating a new
+one. This only makes sense if used in a load callback.
+
+*REPO_EXTEND_SOLVABLES*::
+Do not create new solvables for the new data, but match existing solvables
+and add the data to them. Repository metadata is often split into multiple
+parts, with one primary file describing all packages and other parts
+holding information that is normally not needed, like the changelog.
+
+*REPO_USE_ROOTDIR*::
+Prepend the pool's rootdir to the path when doing file operations.
+
+*REPO_NO_LOCATION*::
+Do not add a location element to the solvables. Useful if the solvables
+are not in the final position, so you can add the correct location later
+in your code.
+
+*SOLV_ADD_NO_STUBS*::
+Do not create stubs for repository parts that can be downloaded on demand.
+
+*SUSETAGS_RECORD_SHARES*::
+This is specific to the add_susetags() method. Susetags allows one to refer to
+already read packages to save disk space. If this data sharing needs to
+work over multiple calls to add_susetags, you need to specify this flag so
+that the share information is made available to subsequent calls.
+
+=== METHODS ===
+
+       void free(bool reuseids = 0)
+       $repo->free();
+       repo.free()
+       repo.free()
+
+Free the repository and all solvables it contains. If _reuseids_ is set to
+true, the solvable ids and the repository id may be reused by the library when
+added new solvables. Thus you should leave it false if you are not sure that
+somebody holds a reference.
+
+       void empty(bool reuseids = 0)
+       $repo->empty();
+       repo.empty()
+       repo.empty()
+
+Free all the solvables in a repository. The repository will be empty after this
+call. See the free() method for the meaning of _reuseids_.
+
+       bool isempty()
+       $repo->isempty()
+       repo.empty()
+       repo.empty?
+
+Return true if there are no solvables in this repository.
+
+       void internalize()
+       $repo->internalize();
+       repo.internalize()
+       repo.internalize()
+
+Internalize added data. Data must be internalized before it is available to the
+lookup and data iterator functions.
+
+       bool write(FILE *fp)
+       $repo->write($fp)
+       repo.write(fp)
+       repo.write(fp)
+
+Write a repo as a ``solv'' file. These files can be read very fast and thus are
+a good way to cache repository data. Returns false if there was some error
+writing the file.
+
+       Solvableiterator solvables_iter()
+       for my $solvable (@{$repo->solvables_iter()})
+       for solvable in repo.solvables_iter():
+       for solvable in repo.solvables_iter()
+
+Iterate over all solvables in a repository.
+
+       Repodata add_repodata(int flags = 0)
+       my $repodata = $repo->add_repodata();
+       repodata = repo.add_repodata()
+       repodata = repo.add_repodata()
+
+Add a new repodata area to the repository. This is normally automatically
+done by the repo_add methods, so you need this method only in very
+rare circumstances.
+
+       void create_stubs()
+       $repo->create_stubs();
+       repo.create_stubs()
+       repo.create_stubs()
+
+Calls the create_stubs() repodata method for the last repodata of the
+repository.
+
+       bool iscontiguous()
+       $repo->iscontiguous()
+       repo.iscontiguous()
+       repo.iscontiguous?
+
+Return true if the solvables of this repository are all in a single block with
+no holes, i.e. they have consecutive ids.
+
+       Repodata first_repodata()
+       my $repodata = $repo->first_repodata();
+       repodata = repo.first_repodata()
+       repodata = repo.first_repodata()
+
+Checks if all repodatas but the first repodata are extensions, and return the
+first repodata if this is the case. Useful if you want to do a store/retrieve
+sequence on the repository to reduce the memory using and enable paging, as
+this does not work if the repository contains multiple non-extension repodata
+areas.
+
+       Selection Selection(int setflags = 0)
+       my $sel = $repo->Selection();
+       sel = repo.Selection()
+       sel = repo.Selection()
+
+Create a Selection consisting of all packages in the repository.
+
+       Dataiterator Dataiterator(Id key, const char *match = 0, int flags = 0)
+       my $di = $repo->Dataiterator($keyname, $match, $flags);
+       di = repo.Dataiterator(keyname, match, flags)
+       di = repo.Dataiterator(keyname, match, flags)
+
+       Dataiterator Dataiterator_meta(Id key, const char *match = 0, int flags = 0)
+       my $di = $repo->Dataiterator_meta($keyname, $match, $flags);
+       di = repo.Dataiterator_meta(keyname, match, flags)
+       di = repo.Dataiterator_meta(keyname, match, flags)
+
+       for my $d (@$di)
+       for d in di:
+       for d in di
+
+Iterate over the matching data elements in this repository. See the
+Dataiterator class for more information. The Dataiterator() method
+iterates over all solvables in a repository, whereas the Dataiterator_meta
+method only iterates over the repository's meta data.
+
+       <stringification>
+       my $str = $repo->str;
+       str = str(repo)
+       str = repo.to_s
+
+Return the name of the repository, or "Repo#<id>" if no name is set.
+
+       <equality>
+       if ($repo1 == $repo2)
+       if repo1 == repo2:
+       if repo1 == repo2
+
+Two repositories are equal if they belong to the same pool and have the same id.
+
+=== DATA ADD METHODS ===
+
+       Solvable add_solvable()
+       $repo->add_solvable();
+       repo.add_solvable()
+       repo.add_solvable()
+
+Add a single empty solvable to the repository. Returns a Solvable object, see
+the Solvable class for more information.
+
+       bool add_solv(const char *name, int flags = 0)
+       $repo->add_solv($name);
+       repo.add_solv(name)
+       repo.add_solv(name)
+
+       bool add_solv(FILE *fp, int flags = 0)
+       $repo->add_solv($fp);
+       repo.add_solv(fp)
+       repo.add_solv(fp)
+
+Read a ``solv'' file and add its contents to the repository. These files can be
+written with the write() method and are normally used as fast cache for
+repository metadata.
+
+       bool add_rpmdb(int flags = 0)
+       $repo->add_rpmdb();
+       repo.add_rpmdb()
+       repo.add_rpmdb()
+
+       bool add_rpmdb_reffp(FILE *reffp, int flags = 0)
+       $repo->add_rpmdb_reffp($reffp);
+       repo.add_rpmdb_reffp(reffp)
+       repo.add_rpmdb_reffp(reffp)
+
+Add the contents of the rpm database to the repository. If a solv file
+containing an old version of the database is available, it can be passed as
+reffp to speed up reading.
+
+       Solvable add_rpm(const char *filename, int flags = 0)
+       my $solvable = $repo->add_rpm($filename);
+       solvable = repo.add_rpm(filename)
+       solvable = repo.add_rpm(filename)
+
+Add the metadata of a single rpm package to the repository.
+
+       bool add_rpmdb_pubkeys(int flags = 0)
+       $repo->add_rpmdb_pubkeys();
+       repo.add_rpmdb_pubkeys()
+       repo.add_rpmdb_pubkeys()
+
+Add all pubkeys contained in the rpm database to the repository. Note that
+newer rpm versions also allow to store the pubkeys in some directory instead
+of the rpm database.
+
+       Solvable add_pubkey(const char *keyfile, int flags = 0)
+       my $solvable = $repo->add_pubkey($keyfile);
+       solvable = repo.add_pubkey(keyfile)
+       solvable = repo.add_pubkey(keyfile)
+
+Add a pubkey from a file to the repository.
+
+       bool add_rpmmd(FILE *fp, const char *language, int flags = 0)
+       $repo->add_rpmmd($fp, undef);
+       repo.add_rpmmd(fp, None)
+       repo.add_rpmmd(fp, nil)
+
+Add metadata stored in the "rpm-md" format (i.e. from files in the ``repodata''
+directory) to a repository. Supported files are "primary", "filelists",
+"other", "suseinfo". Do not forget to specify the *REPO_EXTEND_SOLVABLES* for
+extension files like "filelists" and "other". Use the _language_ parameter if
+you have language extension files, otherwise simply use a *undef*/*None*/*nil*
+parameter.
+
+       bool add_repomdxml(FILE *fp, int flags = 0)
+       $repo->add_repomdxml($fp);
+       repo.add_repomdxml(fp)
+       repo.add_repomdxml(fp)
+
+Add the repomd.xml meta description from the "rpm-md" format to the repository.
+This file contains information about the repository like keywords, and also a
+list of all database files with checksums. The data is added to the "meta"
+section of the repository, i.e. no package gets created.
+
+       bool add_updateinfoxml(FILE *fp, int flags = 0)
+       $repo->add_updateinfoxml($fp);
+       repo.add_updateinfoxml(fp)
+       repo.add_updateinfoxml(fp)
+
+Add the updateinfo.xml file containing available maintenance updates to the
+repository. All updates are created as special packages that have a "patch:"
+prefix in their name.
+
+       bool add_deltainfoxml(FILE *fp, int flags = 0)
+       $repo->add_deltainfoxml($fp);
+       repo.add_deltainfoxml(fp)
+       repo.add_deltainfoxml(fp)
+
+Add the deltainfo.xml file (also called prestodelta.xml) containing available
+delta-rpms to the repository. The data is added to the "meta" section, i.e. no
+package gets created.
+
+       bool add_debdb(int flags = 0)
+       $repo->add_debdb();
+       repo.add_debdb()
+       repo.add_debdb()
+
+Add the contents of the debian installed package database to the repository.
+
+       bool add_debpackages(FILE *fp, int flags = 0)
+       $repo->add_debpackages($fp);
+       repo.add_debpackages($fp)
+       repo.add_debpackages($fp)
+
+Add the contents of the debian repository metadata (the "packages" file)
+to the repository.
+
+       Solvable add_deb(const char *filename, int flags = 0)
+       my $solvable = $repo->add_deb($filename);
+       solvable = repo.add_deb(filename)
+       solvable = repo.add_deb(filename)
+
+Add the metadata of a single deb package to the repository.
+
+       bool add_mdk(FILE *fp, int flags = 0)
+       $repo->add_mdk($fp);
+       repo.add_mdk(fp)
+       repo.add_mdk(fp)
+
+Add the contents of the mageia/mandriva repository metadata (the
+"synthesis.hdlist" file) to the repository.
+
+       bool add_mdk_info(FILE *fp, int flags = 0)
+       $repo->add_mdk_info($fp);
+       repo.add_mdk_info(fp)
+       repo.add_mdk_info(fp)
+
+Extend the packages from the synthesis file with the info.xml and files.xml
+data. Do not forget to specify *REPO_EXTEND_SOLVABLES*.
+
+       bool add_arch_repo(FILE *fp, int flags = 0)
+       $repo->add_arch_repo($fp);
+       repo.add_arch_repo(fp)
+       repo.add_arch_repo(fp)
+
+Add the contents of the archlinux repository metadata (the ".db.tar" file) to
+the repository.
+
+       bool add_arch_local(const char *dir, int flags = 0)
+       $repo->add_arch_local($dir);
+       repo.add_arch_local(dir)
+       repo.add_arch_local(dir)
+
+Add the contents of the archlinux installed package database to the repository.
+The _dir_ parameter is usually set to "/var/lib/pacman/local".
+
+       bool add_content(FILE *fp, int flags = 0)
+       $repo->add_content($fp);
+       repo.add_content(fp)
+       repo.add_content(fp)
+
+Add the ``content'' meta description from the susetags format to the repository.
+This file contains information about the repository like keywords, and also
+a list of all database files with checksums. The data is added to the "meta"
+section of the repository, i.e. no package gets created.
+
+       bool add_susetags(FILE *fp, Id defvendor, const char *language, int flags = 0)
+       $repo->add_susetags($fp, $defvendor, $language);
+       repo.add_susetags(fp, defvendor, language)
+       repo.add_susetags(fp, defvendor, language)
+
+Add repository metadata in the susetags format to the repository. Like with
+add_rpmmd, you can specify a language if you have language extension files. The
+_defvendor_ parameter provides a default vendor for packages with missing
+vendors, it is usually provided in the content file.
+
+       bool add_products(const char *dir, int flags = 0)
+       $repo->add_products($dir);
+       repo.add_products(dir)
+       repo.add_products(dir)
+
+Add the installed SUSE products database to the repository. The _dir_ parameter
+is usually "/etc/products.d".
+
+
+The Solvable Class
+------------------
+A solvable describes all the information of one package. Each solvable
+belongs to one repository, it can be added and filled manually but in
+most cases solvables will get created by the repo_add methods.
+
+=== ATTRIBUTES ===
+
+       Repo *repo;                     /* read only */
+       $solvable->{repo}
+       solvable.repo
+       solvable.repo
+
+The repository this solvable belongs to.
+
+       Pool *pool;                     /* read only */
+       $solvable->{pool}
+       solvable.pool
+       solvable.pool
+
+The pool this solvable belongs to, same as the pool of the repo.
+
+       Id id;                          /* read only */
+       $solvable->{id}
+       solvable.id
+       solvable.id
+
+The specific id of the solvable.
+
+       char *name;                     /* read/write */
+       $solvable->{name}
+       solvable.name
+       solvable.name
+
+       char *evr;                      /* read/write */
+       $solvable->{evr}
+       solvable.evr
+       solvable.evr
+
+       char *arch;                     /* read/write */
+       $solvable->{arch}
+       solvable.arch
+       solvable.arch
+
+       char *vendor;                   /* read/write */
+       $solvable->{vendor}
+       solvable.vendor
+       solvable.vendor
+
+Easy access to often used attributes of solvables. They are
+internally stored as Ids.
+
+       Id nameid;                      /* read/write */
+       $solvable->{nameid}
+       solvable.nameid
+       solvable.nameid
+
+       Id evrid;                       /* read/write */
+       $solvable->{evrid}
+       solvable.evrid
+       solvable.evrid
+
+       Id archid;                      /* read/write */
+       $solvable->{archid}
+       solvable.archid
+       solvable.archid
+
+       Id vendorid;                    /* read/write */
+       $solvable->{vendorid}
+       solvable.vendorid
+       solvable.vendorid
+
+Raw interface to the ids. Useful if you want to search for
+a specific id and want to avoid the string compare overhead.
+
+=== METHODS ===
+
+       const char *lookup_str(Id keyname)
+       my $string = $solvable->lookup_str($keyname);
+       string = solvable.lookup_str(keyname)
+       string = solvable.lookup_str(keyname)
+
+       Id lookup_id(Id keyname)
+       my $id = $solvable->lookup_id($keyname);
+       id = solvable.lookup_id(keyname)
+       id = solvable.lookup_id(keyname)
+
+       unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0)
+       my $num = $solvable->lookup_num($keyname);
+       num = solvable.lookup_num(keyname)
+       num = solvable.lookup_num(keyname)
+
+       bool lookup_void(Id keyname)
+       my $bool = $solvable->lookup_void($keyname);
+       bool = solvable.lookup_void(keyname)
+       bool = solvable.lookup_void(keyname)
+
+       Chksum lookup_checksum(Id keyname)
+       my $chksum = $solvable->lookup_checksum($keyname);
+       chksum = solvable.lookup_checksum(keyname)
+       chksum = solvable.lookup_checksum(keyname)
+
+       Id *lookup_idarray(Id keyname, Id marker = -1)
+       my @ids = $solvable->lookup_idarray($keyname);
+       ids = solvable.lookup_idarray(keyname)
+       ids = solvable.lookup_idarray(keyname)
+
+       Dep *lookup_deparray(Id keyname, Id marker = -1)
+       my @deps = $solvable->lookup_deparray($keyname);
+       deps = solvable.lookup_deparray(keyname)
+       deps = solvable.lookup_deparray(keyname)
+       
+Generic lookup methods. Retrieve data stored for the specific keyname.
+The lookup_idarray() method will return an array of Ids, use
+lookup_deparray if you want an array of Dependency objects instead.
+Some Id arrays contain two parts of data divided by a specific marker,
+for example the provides array uses the SOLVABLE_FILEMARKER id to
+store both the ids provided by the package and the ids added by
+the addfileprovides method. The default, -1, translates to the
+correct marker for the keyname and returns the first part of the
+array, use 1 to select the second part or 0 to retrieve all ids
+including the marker.
+
+       const char *lookup_location(unsigned int *OUTPUT);
+       my ($location, $mediano) = $solvable->lookup_location();
+       location, mediano = solvable.lookup_location()
+       location, mediano = solvable.lookup_location()
+
+Return a tuple containing the on-media location and an optional
+media number for multi-part repositories (e.g. repositories
+spawning multiple DVDs).
+
+       const char *lookup_sourcepkg();
+       my $sourcepkg = $solvable->lookup_sourcepkg();
+       sourcepkg = solvable.lookup_sourcepkg()
+       sourcepkg = solvable.lookup_sourcepkg()
+
+Return a sourcepkg name associated with solvable.
+
+       Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0)
+       my $di = $solvable->Dataiterator($keyname, $match, $flags);
+       di = solvable.Dataiterator(keyname, match, flags)
+       di = solvable.Dataiterator(keyname, match, flags)
+
+       for my $d (@$di)
+       for d in di:
+       for d in di
+
+Iterate over the matching data elements. See the Dataiterator class for more
+information.
+
+       void add_deparray(Id keyname, DepId dep, Id marker = -1);
+       $solvable->add_deparray($keyname, $dep);
+       solvable.add_deparray(keyname, dep)
+       solvable.add_deparray(keyname, dep)
+
+Add a new dependency to the attributes stored in keyname.
+
+       void unset(Id keyname);
+       $solvable->unset($keyname);
+       solvable.unset(keyname)
+       solvable.unset(keyname)
+
+Delete data stored for the specific keyname.
+
+       bool installable();
+       $solvable->installable()
+       solvable.installable()
+       solvable.installable?
+
+Return true if the solvable is installable on the system. Solvables
+are not installable if the system does not support their architecture.
+
+       bool isinstalled();
+       $solvable->isinstalled()
+       solvable.isinstalled()
+       solvable.isinstalled?
+
+Return true if the solvable is installed on the system.
+
+       bool identical(Solvable *other)
+       $solvable->identical($other)
+       solvable.identical(other)
+       solvable.identical?(other)
+
+Return true if the two solvables are identical.
+
+       int evrcmp(Solvable *other)
+       $solvable->evrcmp($other)
+       solvable.evrcmp(other)
+       solvable.evrcmp(other)
+
+Returns -1 if the epoch/version/release of the solvable is less than the
+one from the other solvable, 1 if it is greater, and 0 if they are equal.
+Note that "equal" does not mean that the evr is identical.
+
+       int matchesdep(Id keyname, DepId id, Id marker = -1)
+       $solvable->matchesdep($keyname, $dep)
+       solvable.matchesdep(keyname, dep)
+       solvable.matchesdep?(keyname, dep)
+
+Return true if the dependencies stored in keyname match the specified dependency.
+
+       Selection Selection(int setflags = 0)
+       my $sel = $solvable->Selection();
+       sel = solvable.Selection()
+       sel = solvable.Selection()
+
+Create a Selection containing just the single solvable.
+
+       const char *str()
+       my $str = $solvable->str();
+       str = $solvable.str()
+       str = $solvable.str()
+
+Return a string describing the solvable. The string consists of the name,
+version, and architecture of the Solvable.
+
+       <stringification>
+       my $str = $solvable->str;
+       str = str(solvable)
+       str = solvable.to_s
+
+Same as calling the str() method.
+
+       <equality>
+       if ($solvable1 == $solvable2)
+       if solvable1 == solvable2:
+       if solvable1 == solvable2
+
+Two solvables are equal if they are part of the same pool and have the same
+ids.
+
+
+The Dataiterator Class
+----------------------
+Dataiterators can be used to do complex string searches or
+to iterate over arrays. They can be created via the
+constructors in the Pool, Repo, and Solvable classes. The
+Repo and Solvable constructors will limit the search to
+the repository or the specific package.
+
+=== CONSTANTS ===
+
+*SEARCH_STRING*::
+Return a match if the search string matches the value.
+
+*SEARCH_STRINGSTART*::
+Return a match if the value starts with the search string.
+
+*SEARCH_STRINGEND*::
+Return a match if the value ends with the search string.
+
+*SEARCH_SUBSTRING*::
+Return a match if the search string can be matched somewhere in the value.
+
+*SEARCH_GLOB*::
+Do a glob match of the search string against the value.
+
+*SEARCH_REGEX*::
+Do a regular expression match of the search string against the value.
+
+*SEARCH_NOCASE*::
+Ignore case when matching strings. Works for all the above match types.
+
+*SEARCH_FILES*::
+Match the complete filenames of the file list, not just the base name.
+
+*SEARCH_COMPLETE_FILELIST*::
+When matching the file list, check every file of the package not just the
+subset from the primary metadata.
+
+*SEARCH_CHECKSUMS*::
+Allow the matching of checksum entries.
+
+=== METHODS ===
+
+       void prepend_keyname(Id keyname);
+       $di->prepend_keyname($keyname);
+       di.prepend_keyname(keyname)
+       di.prepend_keyname(keyname)
+
+Do a sub-search in the array stored in keyname.
+
+       void skip_solvable();
+       $di->skip_solvable();
+       di.skip_solvable()
+       di.skip_solvable()
+
+Stop matching the current solvable and advance to the next
+one.
+
+       <iteration>
+       for my $d (@$di)
+       for d in di:
+       for d in di
+
+Iterate through the matches. If there is a match, the object
+in d will be of type Datamatch.
+
+The Datamatch Class
+-------------------
+Objects of this type will be created for every value matched
+by a dataiterator.
+
+=== ATTRIBUTES ===
+
+       Pool *pool;                             /* read only */
+       $d->{pool}
+       d.pool
+       d.pool
+
+Back pointer to pool.
+
+       Repo *repo;                             /* read only */
+       $d->{repo}
+       d.repo
+       d.repo
+
+The repository containing the matched object.
+
+       Solvable *solvable;                     /* read only */
+       $d->{solvable}
+       d.solvable
+       d.solvable
+
+The solvable containing the value that was matched.
+
+       Id solvid;                              /* read only */
+       $d->{solvid}
+       d.solvid
+       d.solvid
+
+The id of the solvable that matched.
+
+       Id key_id;
+       $d->{key_id}
+       d.key_id
+       d.key_id
+
+       const char *key_idstr;
+       $d->{key_idstr}
+       d.key_idstr
+       d.key_idstr
+
+The keyname that matched, either as id or string.
+
+       Id type_id;
+       $d->{type_id}
+       d.type_id
+       d.type_id
+
+       const char *type_idstr;
+       $d->{type_idstr};
+       d.type_idstr
+       d.type_idstr
+
+The key type of the value that was matched, either as id or string.
+
+       Id id;
+       $d->{id}
+       d.id
+       d.id
+
+       Id idstr;
+       $d->{idstr}
+       d.idstr
+       d.idstr
+
+The Id of the value that was matched (only valid for id types),
+either as id or string.
+
+       const char *str;
+       $d->{str}
+       d.str
+       d.str
+
+The string value that was matched (only valid for string types).
+
+       unsigned long long num;
+       $d->{num}
+       d.num
+       d.num
+
+The numeric value that was matched (only valid for numeric types).
+
+       unsigned int num2;
+       $d->{num2}
+       d.num2
+       d.num2
+
+The secondary numeric value that was matched (only valid for types
+containing two values).
+
+       unsigned int binary;
+       $d->{binary}
+       d.binary
+       d.binary
+
+The value in binary form, useful for checksums and other data
+that cannot be represented as a string.
+
+=== METHODS ===
+
+       Datapos pos();
+       my $pos = $d->pos();
+       pos = d.pos()
+       pos = d.pos()
+
+The position object of the current match. It can be used to do
+sub-searches starting at the match (if it is of an array type).
+See the Datapos class for more information.
+
+       Datapos parentpos();
+       my $pos = $d->parentpos();
+       pos = d.parentpos()
+       pos = d.parentpos()
+
+The position object of the array containing the current match.
+It can be used to do sub-searches, see the Datapos class for more
+information.
+
+       <stringification>
+       my $str = $d->str;
+       str = str(d)
+       str = d.to_s
+
+Return the stringification of the matched value. Stringification
+depends on the search flags, for file list entries it will return
+just the base name unless SEARCH_FILES is used, for checksums
+it will return an empty string unless SEARCH_CHECKSUMS is used.
+Numeric values are currently stringified to an empty string.
+
+
+The Selection Class
+-------------------
+Selections are a way to easily deal with sets of packages.
+There are multiple constructors to create them, the most useful
+is probably the select() method in the Pool class.
+
+=== CONSTANTS ===
+
+*SELECTION_NAME*::
+Create the selection by matching package names.
+
+*SELECTION_PROVIDES*::
+Create the selection by matching package provides.
+
+*SELECTION_FILELIST*::
+Create the selection by matching package files.
+
+*SELECTION_CANON*::
+Create the selection by matching the canonical representation
+of the package. This is normally a combination of the name,
+the version, and the architecture of a package.
+
+*SELECTION_DOTARCH*::
+Allow an ".<architecture>" suffix when matching names or
+provides.
+*SELECTION_REL*::
+Allow the specification of a relation when matching names
+or dependencies, e.g. "name >= 1.2".
+
+*SELECTION_GLOB*::
+Allow glob matching for package names, package provides, and file names.
+
+*SELECTION_NOCASE*::
+Ignore case when matching package names, package provides, and file names.
+
+*SELECTION_FLAT*::
+Return only one selection element describing the selected packages.
+The default is to create multiple elements for all globbed packages.
+Multiple elements are useful if you want to turn the selection into
+an install job, in that case you want an install job for every
+globbed package.
+
+*SELECTION_SKIP_KIND*::
+Remove a "packagekind:" prefix from the package names.
+
+*SELECTION_MATCH_DEPSTR*::
+When matching dependencies, do a string match on the result of dep2str
+instead of using the normal dependency intersect algorithm.
+
+*SELECTION_INSTALLED_ONLY*::
+Limit the package search to installed packages.
+
+*SELECTION_SOURCE_ONLY*::
+Limit the package search to source packages only.
+
+*SELECTION_WITH_SOURCE*::
+Extend the package search to also match source packages. The default is
+only to match binary packages.
+
+*SELECTION_WITH_DISABLED*::
+Extend the package search to also include disabled packages.
+
+*SELECTION_WITH_BADARCH*::
+Extend the package search to also include packages that are not installable
+on the configured architecture.
+
+*SELECTION_WITH_ALL*::
+Shortcut for selecting the three modifiers above.
+
+*SELECTION_ADD*::
+Add the result of the match to the current selection instead of replacing it.
+
+*SELECTION_SUBTRACT*::
+Remove the result of the match to the current selection instead of replacing it.
+
+*SELECTION_FILTER*::
+Intersect the result of the match to the current selection instead of replacing it.
+
+=== ATTRIBUTES ===
+
+       Pool *pool;                             /* read only */
+       $d->{pool}
+       d.pool
+       d.pool
+
+Back pointer to pool.
+
+       int flags;                              /* read only */
+       $sel->{flags}
+       flags = sel.flags
+       flags = sel.flags
+
+The result flags of the selection. The flags are a subset
+of the ones used when creating the selection, they describe which
+method was used to get the result. For example, if you create the
+selection with ``SELECTION_NAME | SELECTION_PROVIDES'', the resulting
+flags will either be SELECTION_NAME or SELECTION_PROVIDES depending
+if there was a package that matched the name or not. If there was
+no match at all, the flags will be zero.
+
+=== METHODS ===
+
+       bool isempty()
+       $sel->isempty()
+       sel.isempty()
+       sel.isempty?
+
+Return true if the selection is empty, i.e. no package could be matched.
+
+       Selection clone(int flags = 0)
+       my $cloned = $sel->clone();
+       cloned = sel.clone()
+       cloned = sel.clone()
+
+Return a copy of a selection.
+
+       void filter(Selection *other)
+       $sel->filter($other);
+       sel.filter(other)
+       sel.filter(other)
+
+Intersect two selections. Packages will only stay in the selection if there
+are also included in the other selecting. Does an in-place modification.
+
+       void add(Selection *other)
+       $sel->add($other);
+       sel.add(other)
+       sel.add(other)
+
+Build the union of two selections. All packages of the other selection will
+be added to the set of packages of the selection object. Does an in-place
+modification. Note that the selection flags are no longer meaningful after the
+add operation.
+
+       void subtract(Selection *other)
+       $sel->subtract($other);
+       sel.subtract(other)
+       sel.subtract(other)
+
+Remove the packages of the other selection from the packages of the selection
+object. Does an in-place modification.
+
+       void add_raw(Id how, Id what)
+       $sel->add_raw($how, $what);
+       sel.add_raw(how, what)
+       sel.add_raw(how, what)
+
+Add a raw element to the selection. Check the Job class for information about
+the how and what parameters. Note that the selection flags are no longer meaningful
+after the add_raw operation.
+
+       Job *jobs(int action)
+       my @jobs = $sel->jobs($action);
+       jobs = sel.jobs(action)
+       jobs = sel.jobs(action)
+
+Convert a selection into an array of Job objects. The action parameter is or-ed
+to the ``how'' part of the job, it describes the type of job (e.g. install,
+erase). See the Job class for the action and action modifier constants.
+
+       Solvable *solvables()
+       my @solvables = $sel->solvables();
+       solvables = sel.solvables()
+       solvables = sel.solvables()
+
+Convert a selection into an array of Solvable objects.
+
+       void select(const char *name, int flags)
+       $sel->select($name, $flags);
+       sel.select(name, flags)
+       sel.select(name, flags)
+
+Do a select operation and combine the result with the current selection. You
+can choose the desired combination method by using either the SELECTION_ADD,
+SELECTION_SUBTRACT, or SELECTION_FILTER flag. If none of the flags are
+used, SELECTION_FILTER|SELECTION_WITH_ALL is assumed.
+
+       void matchdeps(const char *name, int flags, Id keyname, Id marker = -1)
+       $sel->matchdeps($name, $flags, $keyname);
+       sel.matchdeps(name, flags, keyname)
+       sel.matchdeps(name, flags, keyname)
+
+Do a matchdeps operation and combine the result with the current selection.
+
+       void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1)
+       $sel->matchdepid($dep, $flags, $keyname);
+       sel.matchdepid(dep, flags, keyname)
+       sel.matchdepid(dep, flags, keyname)
+
+Do a matchdepid operation and combine the result with the current selection.
+
+       <stringification>
+       my $str = $sel->str;
+       str = str(sel)
+       str = sel.to_s
+
+Return a string describing the selection.
+
+The Job Class
+-------------
+Jobs are the way to specify to the dependency solver what to do.
+Most of the times jobs will get created by calling the jobs() method
+on a Selection object, but there is also a Job() constructor in the
+Pool class.
+
+=== CONSTANTS ===
+
+Selection constants:
+
+*SOLVER_SOLVABLE*::
+The ``what'' part is the id of a solvable.
+
+*SOLVER_SOLVABLE_NAME*::
+The ``what'' part is the id of a package name.
+
+*SOLVER_SOLVABLE_PROVIDES*::
+The ``what'' part is the id of a package provides.
+
+*SOLVER_SOLVABLE_ONE_OF*::
+The ``what'' part is an offset into the ``whatprovides'' data, created
+by calling the towhatprovides() pool method.
+
+*SOLVER_SOLVABLE_REPO*::
+The ``what'' part is the id of a repository.
+
+*SOLVER_SOLVABLE_ALL*::
+The ``what'' part is ignored, all packages are selected.
+
+*SOLVER_SOLVABLE_SELECTMASK*::
+A mask containing all the above selection bits.
+
+Action constants:
+
+*SOLVER_NOOP*::
+Do nothing.
+
+*SOLVER_INSTALL*::
+Install a package of the specified set of packages. It tries to install
+the best matching package (i.e. the highest version of the packages from
+the repositories with the highest priority).
+
+*SOLVER_ERASE*::
+Erase all of the packages from the specified set. If a package is not
+installed, erasing it will keep it from getting installed.
+
+*SOLVER_UPDATE*::
+Update the matching installed packages to their best version. If none
+of the specified packages are installed, try to update the installed
+packages to the specified versions. See the section about targeted
+updates about more information.
+*SOLVER_WEAKENDEPS*::
+Allow to break the dependencies of the matching packages. Handle with care.
+
+*SOLVER_MULTIVERSION*::
+Mark the matched packages for multiversion install. If they get to be
+installed because of some other job, the installation will keep the old
+version of the package installed (for rpm this is done by using ``-i''
+instead of ``-U'').
+
+*SOLVER_LOCK*::
+Do not change the state of the matched packages, i.e. when they are
+installed they stay installed, if not they are not selected for
+installation.
+
+*SOLVER_DISTUPGRADE*::
+Update the matching installed packages to the best version included in one
+of the repositories. After this operation, all come from one of the available
+repositories except orphaned packages. Orphaned packages are packages that
+have no relation to the packages in the repositories, i.e. no package in the
+repositories have the same name or obsolete the orphaned package.
+This action brings the installed packages in sync with the ones in the
+repository. By default it also turns of arch/vendor/version locking for the
+affected packages to simulate a fresh installation. This means that distupgrade can
+actually downgrade packages if only lower versions of a package are available
+in the repositories. You can tweak this behavior with the SOLVER_FLAG_DUP_
+solver flags.
+
+*SOLVER_DROP_ORPHANED*::
+Erase all the matching installed packages if they are orphaned. This only makes
+sense if there is a ``distupgrade all packages'' job. The default is to erase
+orphaned packages only if they block the installation of other packages.
+
+*SOLVER_VERIFY*::
+Fix dependency problems of matching installed packages. The default is to ignore
+dependency problems for installed packages.
+
+*SOLVER_USERINSTALLED*::
+The matching installed packages are considered to be installed by a user,
+thus not installed to fulfill some dependency. This is needed input for
+the calculation of unneeded packages for jobs that have the
+SOLVER_CLEANDEPS flag set.
+
+*SOLVER_ALLOWUNINSTALL*::
+Allow the solver to deinstall the matching installed packages if they get
+into the way of resolving a dependency. This is like the
+SOLVER_FLAG_ALLOW_UNINSTALL flag, but limited to a specific set of packages.
+
+*SOLVER_FAVOR*::
+Prefer the specified packages if the solver encounters an alternative. If
+a job contains multiple matching favor/disfavor elements, the last one takes
+precedence.
+
+*SOLVER_DISFAVOR*::
+Avoid the specified packages if the solver encounters an alternative. This
+can also be used to block recommended or supplemented packages from being
+installed.
+
+*SOLVER_JOBMASK*::
+A mask containing all the above action bits.
+
+Action modifier constants:
+
+*SOLVER_WEAK*::
+Makes the job a weak job. The solver tries to fulfill weak jobs, but does
+not report a problem if it is not possible to do so.
+
+*SOLVER_ESSENTIAL*::
+Makes the job an essential job. If there is a problem with the job, the
+solver will not propose to remove the job as one solution (unless all
+other solutions are also to remove essential jobs).
+
+*SOLVER_CLEANDEPS*::
+The solver will try to also erase all packages dragged in through
+dependencies when erasing the package. This needs SOLVER_USERINSTALLED
+jobs to maximize user satisfaction.
+
+*SOLVER_FORCEBEST*::
+Insist on the best package for install, update, and distupgrade jobs. If
+this flag is not used, the solver will use the second-best package if the
+best package cannot be installed for some reason. When this flag is used,
+the solver will generate a problem instead.
+
+*SOLVER_TARGETED*::
+Forces targeted operation update and distupgrade jobs. See the section
+about targeted updates about more information.
+
+Set constants.
+
+*SOLVER_SETEV*::
+The job specified the exact epoch and version of the package set.
+
+*SOLVER_SETEVR*::
+The job specified the exact epoch, version, and release of the package set.
+
+*SOLVER_SETARCH*::
+The job specified the exact architecture of the packages from the set.
+
+*SOLVER_SETVENDOR*::
+The job specified the exact vendor of the packages from the set.
+
+*SOLVER_SETREPO*::
+The job specified the exact repository of the packages from the set.
+
+*SOLVER_SETNAME*::
+The job specified the exact name of the packages from the set.
+
+*SOLVER_NOAUTOSET*::
+Turn of automatic set flag generation for SOLVER_SOLVABLE jobs.
+
+*SOLVER_SETMASK*::
+A mask containing all the above set bits.
+
+See the section about set bits for more information.
+
+=== ATTRIBUTES ===
+
+       Pool *pool;                             /* read only */
+       $job->{pool}
+       d.pool
+       d.pool
+
+Back pointer to pool.
+
+       Id how;                                 /* read/write */
+       $job->{how}
+       d.how
+       d.how
+
+Union of the selection, action, action modifier, and set flags.
+The selection part describes the semantics of the ``what'' Id.
+
+       Id what;                                /* read/write */
+       $job->{what}
+       d.what
+       d.what
+
+Id describing the set of packages, the meaning depends on the
+selection part of the ``how'' attribute.
+
+=== METHODS ===
+
+       Solvable *solvables()
+       my @solvables = $job->solvables();
+       solvables = job.solvables()
+       solvables = job.solvables()
+
+Return the set of solvables of the job as an array of Solvable
+objects.
+
+       bool isemptyupdate();
+       $job->isemptyupdate()
+       job.isemptyupdate()
+       job.isemptyupdate?
+
+Convenience function to find out if the job describes an update
+job with no matching packages, i.e. a job that does nothing.
+Some package managers like ``zypper'' like to turn those jobs
+into install jobs, i.e. an update of a not-installed package
+will result into the installation of the package.
+
+       <stringification>
+       my $str = $job->str;
+       str = str(job)
+       str = job.to_s
+
+Return a string describing the job.
+
+       <equality>
+       if ($job1 == $job2)
+       if job1 == job2:
+       if job1 == job2
+
+Two jobs are equal if they belong to the same pool and both the
+``how'' and the ``what'' attributes are the same.
+
+=== TARGETED UPDATES ===
+Libsolv has two modes for upgrades and distupgrade: targeted and
+untargeted. Untargeted mode means that the installed packages from
+the specified set will be updated to the best version. Targeted means
+that packages that can be updated to a package in the specified set
+will be updated to the best package of the set.
+
+Here's an example to explain the subtle difference. Suppose that
+you have package A installed in version "1.1", "A-1.2" is available
+in one of the repositories and there is also package "B" that
+obsoletes package A.
+
+An untargeted update of "A" will update the installed "A-1.1" to
+package "B", because that is the newest version (B obsoletes A and
+is thus newer).
+
+A targeted update of "A" will update "A-1.1" to "A-1.2", as the
+set of packages contains both "A-1.1" and "A-1.2", and "A-1.2" is
+the newer one.
+
+An untargeted update of "B" will do nothing, as "B" is not installed.
+
+An targeted update of "B" will update "A-1.1" to "B".
+
+Note that the default is to do "auto-targeting", thus if the specified
+set of packages does not include an installed package, the solver
+will assume targeted operation even if SOLVER_TARGETED is not used.
+
+This mostly matches the intent of the user, with one exception: In
+the example above, an update of "A-1.2" will update "A-1.1" to
+"A-1.2" (targeted mode), but a second update of "A-1.2" will suddenly
+update to "B", as untargeted mode is chosen because "A-1.2" is now
+installed.
+
+If you want to have full control over when targeting mode is chosen,
+turn off auto-targeting with the SOLVER_FLAG_NO_AUTOTARGET solver option.
+In that case, all updates are considered to be untargeted unless they
+include the SOLVER_TARGETED flag.
+
+=== SET BITS ===
+Set bits specify which parts of the specified packages where specified
+by the user. It is used by the solver when checking if an operation is
+allowed or not. For example, the solver will normally not allow the
+downgrade of an installed package. But it will not report a problem if
+the SOLVER_SETEVR flag is used, as it then assumes that the user specified
+the exact version and thus knows what he is doing.
+
+So if a package "screen-1-1" is installed for the x86_64 architecture and
+version "2-1" is only available for the i586 architecture, installing
+package "screen-2.1" will ask the user for confirmation because of the
+different architecture. When using the Selection class to create jobs
+the set bits are automatically added, e.g. selecting ``screen.i586'' will
+automatically add SOLVER_SETARCH, and thus no problem will be reported.
+
+The Solver Class
+----------------
+Dependency solving is what this library is about. A solver object is needed
+for solving to store the result of the solver run. The solver object can be
+used multiple times for different jobs, reusing it allows the solver to
+re-use the dependency rules it already computed.
+
+=== CONSTANTS ===
+
+Flags to modify some of the solver's behavior:
+
+*SOLVER_FLAG_ALLOW_DOWNGRADE*::
+Allow the solver to downgrade packages without asking for confirmation
+(i.e. reporting a problem).
+
+*SOLVER_FLAG_ALLOW_ARCHCHANGE*::
+Allow the solver to change the architecture of an installed package
+without asking for confirmation. Note that changes to/from noarch
+are always considered to be allowed.
+
+*SOLVER_FLAG_ALLOW_VENDORCHANGE*::
+Allow the solver to change the vendor of an installed package
+without asking for confirmation. Each vendor is part of one or more
+vendor equivalence classes, normally installed packages may only
+change their vendor if the new vendor shares at least one equivalence
+class.
+
+*SOLVER_FLAG_ALLOW_NAMECHANGE*::
+Allow the solver to change the name of an installed package, i.e.
+install a package with a different name that obsoletes the installed
+package. This option is on by default.
+
+*SOLVER_FLAG_ALLOW_UNINSTALL*::
+Allow the solver to erase installed packages to fulfill the jobs.
+This flag also includes the above flags. You may want to set this
+flag if you only have SOLVER_ERASE jobs, as in that case it's
+better for the user to check the transaction overview instead of
+approving every single package that needs to be erased.
+
+*SOLVER_FLAG_DUP_ALLOW_DOWNGRADE*::
+Like SOLVER_FLAG_ALLOW_DOWNGRADE, but used in distupgrade mode.
+
+*SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE*::
+Like SOLVER_FLAG_ALLOW_ARCHCHANGE, but used in distupgrade mode.
+
+*SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE*::
+Like SOLVER_FLAG_ALLOW_VENDORCHANGE, but used in distupgrade mode.
+
+*SOLVER_FLAG_DUP_ALLOW_NAMECHANGE*::
+Like SOLVER_FLAG_ALLOW_NAMECHANGE, but used in distupgrade mode.
+
+*SOLVER_FLAG_NO_UPDATEPROVIDE*::
+If multiple packages obsolete an installed package, the solver checks
+the provides of every such package and ignores all packages that
+do not provide the installed package name. Thus, you can have an
+official update candidate that provides the old name, and other
+packages that also obsolete the package but are not considered for
+updating. If you cannot use this feature, you can turn it off
+by setting this flag.
+
+*SOLVER_FLAG_NEED_UPDATEPROVIDE*::
+This is somewhat the opposite of SOLVER_FLAG_NO_UPDATEPROVIDE: Only
+packages that provide the installed package names are considered
+for updating.
+
+*SOLVER_FLAG_SPLITPROVIDES*::
+Make the solver aware of special provides of the form
+``<packagename>:<path>'' used in SUSE systems to support package
+splits.
+
+*SOLVER_FLAG_IGNORE_RECOMMENDED*::
+Do not process optional (aka weak) dependencies.
+
+*SOLVER_FLAG_ADD_ALREADY_RECOMMENDED*::
+Install recommended or supplemented packages even if they have no
+connection to the current transaction. You can use this feature
+to implement a simple way for the user to install new recommended
+packages that were not available in the past.
+
+*SOLVER_FLAG_NO_INFARCHCHECK*::
+Turn off the inferior architecture checking that is normally done
+by the solver. Normally, the solver allows only the installation
+of packages from the "best" architecture if a package is available
+for multiple architectures.
+
+*SOLVER_FLAG_BEST_OBEY_POLICY*::
+Make the SOLVER_FORCEBEST job option consider only packages that
+meet the policies for installed packages, i.e. no downgrades,
+no architecture change, no vendor change (see the first flags
+of this section). If the flag is not specified, the solver will
+enforce the installation of the best package ignoring the
+installed packages, which may conflict with the set policy.
+
+*SOLVER_FLAG_NO_AUTOTARGET*::
+Do not enable auto-targeting up update and distupgrade jobs. See
+the section on targeted updates for more information.
+
+*SOLVER_FLAG_KEEP_ORPHANS*::
+Do not allow orphaned packages to be deinstalled if they get
+in the way of resolving other packages.
+
+*SOLVER_FLAG_BREAK_ORPHANS*::
+Ignore dependencies of orphaned packages that get in the way
+of resolving non-orphaned ones. Setting the flag might result
+in no longer working packages in case they are orphaned.
+
+*SOLVER_FLAG_FOCUS_INSTALLED*::
+Resolve installed packages before resolving the given jobs.
+Setting this flag means that the solver will prefer picking
+a package version that fits the other installed packages
+over updating installed packages.
+
+*SOLVER_FLAG_FOCUS_BEST*::
+First resolve the given jobs, then the dependencies of the
+resulting packages, then resolve all already installed
+packages. This will result in more packages being updated
+as when the flag is not used.
+
+*SOLVER_FLAG_INSTALL_ALSO_UPDATES*::
+Update the package if a job is already fulfilled by an installed
+package.
+
+*SOLVER_FLAG_YUM_OBSOLETES*::
+Turn on yum-like package split handling. See the yum documentation
+for more details.
+
+*SOLVER_FLAG_URPM_REORDER*::
+Turn on urpm like package reordering for kernel packages. See
+the urpm documentation for more details.
+
+
+
+Basic rule types:
+
+*SOLVER_RULE_UNKNOWN*::
+A rule of an unknown class. You should never encounter those.
+
+*SOLVER_RULE_PKG*::
+A package dependency rule.
+
+*SOLVER_RULE_UPDATE*::
+A rule to implement the update policy of installed packages. Every
+installed package has an update rule that consists of the packages
+that may replace the installed package.
+
+*SOLVER_RULE_FEATURE*::
+Feature rules are fallback rules used when an update rule is disabled. They
+include all packages that may replace the installed package ignoring the
+update policy, i.e. they contain downgrades, arch changes and so on.
+Without them, the solver would simply erase installed packages if their
+update rule gets disabled.
+
+*SOLVER_RULE_JOB*::
+Job rules implement the job given to the solver.
+
+*SOLVER_RULE_DISTUPGRADE*::
+These are simple negative assertions that make sure that only packages
+are kept that are also available in one of the repositories.
+
+*SOLVER_RULE_INFARCH*::
+Infarch rules are also negative assertions, they disallow the installation
+of packages when there are packages of the same name but with a better
+architecture.
+
+*SOLVER_RULE_CHOICE*::
+Choice rules are used to make sure that the solver prefers updating to
+installing different packages when some dependency is provided by
+multiple packages with different names. The solver may always break
+choice rules, so you will not see them when a problem is found.
+
+*SOLVER_RULE_LEARNT*::
+These rules are generated by the solver to keep it from running into
+the same problem multiple times when it has to backtrack. They are
+the main reason why a sat solver is faster than other dependency solver
+implementations.
+
+Special dependency rule types:
+
+*SOLVER_RULE_PKG_NOT_INSTALLABLE*::
+This rule was added to prevent the installation of a package of an
+architecture that does not work on the system.
+
+*SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP*::
+The package contains a required dependency which was not provided by
+any package.
+
+*SOLVER_RULE_PKG_REQUIRES*::
+Similar to SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, but in this case
+some packages provided the dependency but none of them could be
+installed due to other dependency issues.
+
+*SOLVER_RULE_PKG_SELF_CONFLICT*::
+The package conflicts with itself. This is not allowed by older rpm
+versions.
+
+*SOLVER_RULE_PKG_CONFLICTS*::
+To fulfill the dependencies two packages need to be installed, but
+one of the packages contains a conflict with the other one.
+
+*SOLVER_RULE_PKG_SAME_NAME*::
+The dependencies can only be fulfilled by multiple versions of
+a package, but installing multiple versions of the same package
+is not allowed.
+
+*SOLVER_RULE_PKG_OBSOLETES*::
+To fulfill the dependencies two packages need to be installed, but
+one of the packages obsoletes the other one.
+
+*SOLVER_RULE_PKG_IMPLICIT_OBSOLETES*::
+To fulfill the dependencies two packages need to be installed, but
+one of the packages has provides a dependency that is obsoleted
+by the other one. See the POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES
+flag.
+
+*SOLVER_RULE_PKG_INSTALLED_OBSOLETES*::
+To fulfill the dependencies a package needs to be installed that is
+obsoleted by an installed package. See the POOL_FLAG_NOINSTALLEDOBSOLETES
+flag.
+
+*SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP*::
+The user asked for installation of a package providing a specific
+dependency, but no available package provides it.
+
+*SOLVER_RULE_JOB_UNKNOWN_PACKAGE*::
+The user asked for installation of a package with a specific name,
+but no available package has that name.
+
+*SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM*::
+The user asked for the erasure of a dependency that is provided by the
+system (i.e. for special hardware or language dependencies), this
+cannot be done with a job.
+
+*SOLVER_RULE_JOB_UNSUPPORTED*::
+The user asked for something that is not yet implemented, e.g. the
+installation of all packages at once.
+
+Policy error constants
+
+*POLICY_ILLEGAL_DOWNGRADE*::
+The solver ask for permission before downgrading packages.
+
+*POLICY_ILLEGAL_ARCHCHANGE*::
+The solver ask for permission before changing the architecture of installed
+packages.
+
+*POLICY_ILLEGAL_VENDORCHANGE*::
+The solver ask for permission before changing the vendor of installed
+packages.
+
+*POLICY_ILLEGAL_NAMECHANGE*::
+The solver ask for permission before replacing an installed packages with
+a package that has a different name.
+
+Solution element type constants
+
+*SOLVER_SOLUTION_JOB*::
+The problem can be solved by removing the specified job.
+
+*SOLVER_SOLUTION_POOLJOB*::
+The problem can be solved by removing the specified job that is defined
+in the pool.
+
+*SOLVER_SOLUTION_INFARCH*::
+The problem can be solved by allowing the installation of the specified
+package with an inferior architecture.
+
+*SOLVER_SOLUTION_DISTUPGRADE*::
+The problem can be solved by allowing to keep the specified package
+installed.
+
+*SOLVER_SOLUTION_BEST*::
+The problem can be solved by allowing to install the specified package
+that is not the best available package.
+
+*SOLVER_SOLUTION_ERASE*::
+The problem can be solved by allowing to erase the specified package.
+
+*SOLVER_SOLUTION_REPLACE*::
+The problem can be solved by allowing to replace the package with some
+other package.
+
+*SOLVER_SOLUTION_REPLACE_DOWNGRADE*::
+The problem can be solved by allowing to replace the package with some
+other package that has a lower version.
+
+*SOLVER_SOLUTION_REPLACE_ARCHCHANGE*::
+The problem can be solved by allowing to replace the package with some
+other package that has a different architecture.
+
+*SOLVER_SOLUTION_REPLACE_VENDORCHANGE*::
+The problem can be solved by allowing to replace the package with some
+other package that has a different vendor.
+
+*SOLVER_SOLUTION_REPLACE_NAMECHANGE*::
+The problem can be solved by allowing to replace the package with some
+other package that has a different name.
+
+
+Reason constants
+
+*SOLVER_REASON_UNRELATED*::
+The package status did not change as it was not related to any job.
+
+*SOLVER_REASON_UNIT_RULE*::
+The package was installed/erased/kept because of a unit rule, i.e. a rule
+where all literals but one were false.
+
+*SOLVER_REASON_KEEP_INSTALLED*::
+The package was chosen when trying to keep as many packages installed as
+possible.
+
+*SOLVER_REASON_RESOLVE_JOB*::
+The decision happened to fulfill a job rule.
+
+*SOLVER_REASON_UPDATE_INSTALLED*::
+The decision happened to fulfill a package update request.
+
+*SOLVER_REASON_CLEANDEPS_ERASE*::
+The package was erased when cleaning up dependencies from other erased
+packages.
+
+*SOLVER_REASON_RESOLVE*::
+The package was installed to fulfill package dependencies.
+
+*SOLVER_REASON_WEAKDEP*::
+The package was installed because of a weak dependency (Recommends or
+Supplements).
+
+*SOLVER_REASON_RESOLVE_ORPHAN*::
+The decision about the package was made when deciding the fate of orphaned
+packages.
+
+*SOLVER_REASON_RECOMMENDED*::
+This is a special case of SOLVER_REASON_WEAKDEP.
+
+*SOLVER_REASON_SUPPLEMENTED*::
+This is a special case of SOLVER_REASON_WEAKDEP.
+
+
+=== ATTRIBUTES ===
+
+       Pool *pool;                             /* read only */
+       $job->{pool}
+       d.pool
+       d.pool
+
+Back pointer to pool.
+
+=== METHODS ===
+
+       int set_flag(int flag, int value)
+       my $oldvalue = $solver->set_flag($flag, $value);
+       oldvalue = solver.set_flag(flag, value)
+       oldvalue = solver.set_flag(flag, value)
+
+       int get_flag(int flag)
+       my $value = $solver->get_flag($flag);
+       value = solver.get_flag(flag)
+       value = solver.get_flag(flag)
+
+Set/get a solver specific flag. The flags define the policies the solver has
+to obey. The flags are explained in the CONSTANTS section of this class.
+
+       Problem *solve(Job *jobs)
+       my @problems = $solver->solve(\@jobs);
+       problems = solver.solve(jobs)
+       problems = solver.solve(jobs)
+
+Solve a problem specified in the job list (plus the jobs defined in the pool).
+Returns an array of problems that need user interaction, or an empty array
+if no problems were encountered. See the Problem class on how to deal with
+problems.
+
+       Transaction transaction()
+       my $trans = $solver->transaction();
+       trans = solver.transaction()
+       trans = solver.transaction()
+
+Return the transaction to implement the calculated package changes. A transaction
+is available even if problems were found, this is useful for interactive user
+interfaces that show both the job result and the problems.
+
+       int reason = describe_decision(Solvable *s, Rule *OUTPUT)
+       my ($reason, $rule) = $solver->describe_decision($solvable);
+       (reason, rule) = solver.describe_decision(solvable)
+       (reason, rule) = solver.describe_decision(solvable)
+
+Return the reason why a specific solvable was installed or erased. For most of
+the reasons the rule that triggered the decision is also returned.
+
+       Solvable *get_recommended(bool noselected=0);
+       my @solvables = $solver->get_recommended();
+       solvables = solver.get_recommended()
+       solvables = solver.get_recommended()
+
+Return all solvables that are recommended by the solver run result. This includes
+solvables included in the result, set noselected if you want to filter those.
+
+       Solvable *get_suggested(bool noselected=0);
+       my @solvables = $solver->get_suggested();
+       solvables = solver.get_suggested()
+       solvables = solver.get_suggested()
+
+Return all solvables that are suggested by the solver run result. This includes
+solvables included in the result, set noselected if you want to filter those.
+
+
+The Problem Class
+-----------------
+Problems are the way of the solver to interact with the user. You can simply list
+all problems and terminate your program, but a better way is to present solutions to
+the user and let him pick the ones he likes.
+
+=== ATTRIBUTES ===
+
+       Solver *solv;                           /* read only */
+       $problem->{solv}
+       problem.solv
+       problem.solv
+
+Back pointer to solver object.
+
+       Id id;                                  /* read only */
+       $problem->{id}
+       problem.id
+       problem.id
+
+Id of the problem. The first problem has Id 1, they are numbered consecutively.
+
+=== METHODS ===
+
+       Rule findproblemrule()
+       my $probrule = $problem->findproblemrule();
+       probrule = problem.findproblemrule()
+       probrule = problem.findproblemrule()
+
+Return the rule that caused the problem. Of course in most situations there is no
+single responsible rule, but many rules that interconnect with each created the
+problem. Nevertheless, the solver uses some heuristic approach to find a rule
+that somewhat describes the problem best to the user.
+
+       Rule *findallproblemrules(bool unfiltered = 0)
+       my @probrules = $problem->findallproblemrules();
+       probrules = problem.findallproblemrules()
+       probrules = problem.findallproblemrules()
+
+Return all rules responsible for the problem. The returned set of rules contains
+all the needed information why there was a problem, but it's hard to present
+them to the user in a sensible way. The default is to filter out all update and
+job rules (unless the returned rules only consist of those types).
+
+       Solution *solutions()
+       my @solutions = $problem->solutions();
+       solutions = problem.solutions()
+       solutions = problem.solutions()
+
+Return an array containing multiple possible solutions to fix the problem. See
+the solution class for more information.
+
+       int solution_count()
+       my $cnt = $problem->solution_count();
+       cnt = problem.solution_count()
+       cnt = problem.solution_count()
+
+Return the number of solutions without creating solution objects.
+
+       <stringification>
+       my $str = $problem->str;
+       str = str(problem)
+       str = problem.to_s
+
+Return a string describing the problem. This is a convenience function, it is
+a shorthand for calling findproblemrule(), then ruleinfo() on the problem
+rule and problemstr() on the ruleinfo object.
+
+The Rule Class
+--------------
+Rules are the basic block of sat solving. Each package dependency gets translated
+into one or multiple rules.
+
+=== ATTRIBUTES ===
+
+       Solver *solv;                           /* read only */
+       $rule->{solv}
+       rule.solv
+       rule.solv
+
+Back pointer to solver object.
+
+       Id id;                                  /* read only */
+       $rule->{id}
+       rule.id
+       rule.id
+
+The id of the rule.
+
+       int type;                               /* read only */
+       $rule->{type}
+       rule.type
+       rule.type
+
+The basic type of the rule. See the constant section of the solver class for the type list.
+
+=== METHODS ===
+
+       Ruleinfo info()
+       my $ruleinfo = $rule->info();
+       ruleinfo = rule.info()
+       ruleinfo = rule.info()
+
+Return a Ruleinfo object that contains information about why the rule was created. But
+see the allinfos() method below.
+
+       Ruleinfo *allinfos()
+       my @ruleinfos = $rule->allinfos();
+       ruleinfos = rule.allinfos()
+       ruleinfos = rule.allinfos()
+
+As the same dependency rule can get created because of multiple dependencies, one
+Ruleinfo is not enough to describe the reason. Thus the allinfos() method returns
+an array of all infos about a rule.
+
+       <equality>
+       if ($rule1 == $rule2)
+       if rule1 == rule2:
+       if rule1 == rule2
+
+Two rules are equal if they belong to the same solver and have the same id.
+
+The Ruleinfo Class
+------------------
+A Ruleinfo describes one reason why a rule was created.
+
+=== ATTRIBUTES ===
+
+       Solver *solv;                           /* read only */
+       $ruleinfo->{solv}
+       ruleinfo.solv
+       ruleinfo.solv
+
+Back pointer to solver object.
+
+       int type;                               /* read only */
+       $ruleinfo->{type}
+       ruleinfo.type
+       ruleinfo.type
+
+The type of the ruleinfo. See the constant section of the solver class for the
+rule type list and the special type list.
+
+       Dep *dep;                               /* read only */
+       $ruleinfo->{dep}
+       ruleinfo.dep
+       ruleinfo.dep
+
+The dependency leading to the creation of the rule.
+
+       Dep *dep_id;                            /* read only */
+       $ruleinfo->{'dep_id'}
+       ruleinfo.dep_id
+       ruleinfo.dep_id
+
+The Id of the dependency leading to the creation of the rule, or zero.
+
+       Solvable *solvable;                     /* read only */
+       $ruleinfo->{solvable}
+       ruleinfo.solvable
+       ruleinfo.solvable
+
+The involved Solvable, e.g. the one containing the dependency.
+
+       Solvable *othersolvable;                /* read only */
+       $ruleinfo->{othersolvable}
+       ruleinfo.othersolvable
+       ruleinfo.othersolvable
+
+The other involved Solvable (if any), e.g. the one containing providing
+the dependency for conflicts.
+
+       const char *problemstr();
+       my $str = $ruleinfo->problemstr();
+       str = ruleinfo.problemstr()
+       str = ruleinfo.problemstr()
+
+A string describing the ruleinfo from a problem perspective. This probably
+only makes sense if the rule is part of a problem.
+
+The Solution Class
+------------------
+A solution solves one specific problem. It consists of multiple solution elements
+that all need to be executed.
+
+=== ATTRIBUTES ===
+
+       Solver *solv;                           /* read only */
+       $solution->{solv}
+       solution.solv
+       solution.solv
+
+Back pointer to solver object.
+
+       Id problemid;                           /* read only */
+       $solution->{problemid}
+       solution.problemid
+       solution.problemid
+
+Id of the problem the solution solves.
+
+       Id id;                                  /* read only */
+       $solution->{id}
+       solution.id
+       solution.id
+
+Id of the solution. The first solution has Id 1, they are numbered consecutively.
+
+=== METHODS ===
+
+       Solutionelement *elements(bool expandreplaces = 0)
+       my @solutionelements = $solution->elements();
+       solutionelements = solution.elements()
+       solutionelements = solution.elements()
+
+Return an array containing the elements describing what needs to be done to
+implement the specific solution. If expandreplaces is true, elements of type
+SOLVER_SOLUTION_REPLACE will be replaced by one or more elements replace
+elements describing the policy mismatches.
+
+       int element_count()
+       my $cnt = $solution->solution_count();
+       cnt = solution.element_count()
+       cnt = solution.element_count()
+
+Return the number of solution elements without creating objects. Note that the
+count does not match the number of objects returned by the elements() method
+of expandreplaces is set to true.
+
+
+The Solutionelement Class
+-------------------------
+A solution element describes a single action of a solution. The action is always
+either to remove one specific job or to add a new job that installs or erases
+a single specific package.
+
+=== ATTRIBUTES ===
+
+       Solver *solv;                           /* read only */
+       $solutionelement->{solv}
+       solutionelement.solv
+       solutionelement.solv
+
+Back pointer to solver object.
+
+       Id problemid;                           /* read only */
+       $solutionelement->{problemid}
+       solutionelement.problemid
+       solutionelement.problemid
+
+Id of the problem the element (partly) solves.
+
+       Id solutionid;                          /* read only */
+       $solutionelement->{solutionid}
+       solutionelement.solutionid
+       solutionelement.solutionid
+
+Id of the solution the element is a part of.
+
+       Id id;                                  /* read only */
+       $solutionelement->{id}
+       solutionelement.id
+       solutionelement.id
+
+Id of the solution element. The first element has Id 1, they are numbered consecutively.
+
+       Id type;                                /* read only */
+       $solutionelement->{type}
+       solutionelement.type
+       solutionelement.type
+
+Type of the solution element. See the constant section of the solver class for the
+existing types.
+
+       Solvable *solvable;                     /* read only */
+       $solutionelement->{solvable}
+       solutionelement.solvable
+       solutionelement.solvable
+
+The installed solvable that needs to be replaced for replacement elements.
+
+       Solvable *replacement;                  /* read only */
+       $solutionelement->{replacement}
+       solutionelement.replacement
+       solutionelement.replacement
+
+The solvable that needs to be installed to fix the problem.
+
+       int jobidx;                             /* read only */
+       $solutionelement->{jobidx}
+       solutionelement.jobidx
+       solutionelement.jobidx
+
+The index of the job that needs to be removed to fix the problem, or -1 if the
+element is of another type. Note that it's better to change the job to SOLVER_NOOP
+type so that the numbering of other elements does not get disturbed. This
+method works both for types SOLVER_SOLUTION_JOB and SOLVER_SOLUTION_POOLJOB.
+
+=== METHODS ===
+
+       Solutionelement *replaceelements()
+       my @solutionelements = $solutionelement->replaceelements();
+       solutionelements = solutionelement.replaceelements()
+       solutionelements = solutionelement.replaceelements()
+
+If the solution element is of type SOLVER_SOLUTION_REPLACE, return an array of
+elements describing the policy mismatches, otherwise return a copy of the
+element. See also the ``expandreplaces'' option in the solution's elements()
+method.
+
+       int illegalreplace()
+       my $illegal = $solutionelement->illegalreplace();
+       illegal = solutionelement.illegalreplace()
+       illegal = solutionelement.illegalreplace()
+
+Return an integer that contains the policy mismatch bits or-ed together, or
+zero if there was no policy mismatch. See the policy error constants in
+the solver class.
+
+       Job Job()
+       my $job = $solutionelement->Job();
+       illegal = solutionelement.Job()
+       illegal = solutionelement.Job()
+
+Create a job that implements the solution element. Add this job to the array
+of jobs for all elements of type different to SOLVER_SOLUTION_JOB and
+SOLVER_SOLUTION_POOLJOB. For the latter two, a SOLVER_NOOB Job is created,
+you should replace the old job with the new one.
+
+       const char *str()
+       my $str = $solutionelement->str();
+       str = solutionelement.str()
+       str = solutionelement.str()
+
+A string describing the change the solution element consists of.
+
+The Transaction Class
+---------------------
+Transactions describe the output of a solver run. A transaction contains
+a number of transaction elements, each either the installation of a new
+package or the removal of an already installed package. The Transaction
+class supports a classify() method that puts the elements into different
+groups so that a transaction can be presented to the user in a meaningful
+way.
+
+=== CONSTANTS ===
+
+Transaction element types, both active and passive
+
+*SOLVER_TRANSACTION_IGNORE*::
+This element does nothing. Used to map element types that do not match
+the view mode.
+
+*SOLVER_TRANSACTION_INSTALL*::
+This element installs a package.
+
+*SOLVER_TRANSACTION_ERASE*::
+This element erases a package.
+
+*SOLVER_TRANSACTION_MULTIINSTALL*::
+This element installs a package with a different version keeping the other
+versions installed.
+
+*SOLVER_TRANSACTION_MULTIREINSTALL*::
+This element reinstalls an installed package keeping the other versions
+installed.
+
+Transaction element types, active view
+
+*SOLVER_TRANSACTION_REINSTALL*::
+This element re-installs a package, i.e. installs the same package again.
+
+*SOLVER_TRANSACTION_CHANGE*::
+This element installs a package with same name, version, architecture but
+different content.
+
+*SOLVER_TRANSACTION_UPGRADE*::
+This element installs a newer version of an installed package.
+
+*SOLVER_TRANSACTION_DOWNGRADE*::
+This element installs an older version of an installed package.
+
+*SOLVER_TRANSACTION_OBSOLETES*::
+This element installs a package that obsoletes an installed package.
+
+Transaction element types, passive view
+
+*SOLVER_TRANSACTION_REINSTALLED*::
+This element re-installs a package, i.e. installs the same package again.
+
+*SOLVER_TRANSACTION_CHANGED*::
+This element replaces an installed package with one of the same name,
+version, architecture but different content.
+
+*SOLVER_TRANSACTION_UPGRADED*::
+This element replaces an installed package with a new version.
+
+*SOLVER_TRANSACTION_DOWNGRADED*::
+This element replaces an installed package with an old version.
+
+*SOLVER_TRANSACTION_OBSOLETED*::
+This element replaces an installed package with a package that obsoletes
+it.
+
+Pseudo element types for showing extra information used by classify()
+
+*SOLVER_TRANSACTION_ARCHCHANGE*::
+This element replaces an installed package with a package of a different
+architecture.
+
+*SOLVER_TRANSACTION_VENDORCHANGE*::
+This element replaces an installed package with a package of a different
+vendor.
+
+Transaction mode flags
+
+*SOLVER_TRANSACTION_SHOW_ACTIVE*::
+Filter for active view types. The default is to return passive view type,
+i.e. to show how the installed packages get changed.
+
+*SOLVER_TRANSACTION_SHOW_OBSOLETES*::
+Do not map the obsolete view type into INSTALL/ERASE elements.
+
+*SOLVER_TRANSACTION_SHOW_ALL*::
+If multiple packages replace an installed package, only the best of them
+is kept as OBSOLETE element, the other ones are mapped to INSTALL/ERASE
+elements. This is because most applications want to show just one package
+replacing the installed one. The SOLVER_TRANSACTION_SHOW_ALL makes the
+library keep all OBSOLETE elements.
+
+*SOLVER_TRANSACTION_SHOW_MULTIINSTALL*::
+The library maps MULTIINSTALL elements to simple INSTALL elements. This
+flag can be used to disable the mapping.
+
+*SOLVER_TRANSACTION_CHANGE_IS_REINSTALL*::
+Use this flag if you want to map CHANGE elements to the REINSTALL type.
+
+*SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE*::
+Use this flag if you want to map OBSOLETE elements to the UPGRADE type.
+
+*SOLVER_TRANSACTION_MERGE_ARCHCHANGES*::
+Do not add extra categories for every architecture change, instead cumulate
+them in one category.
+
+*SOLVER_TRANSACTION_MERGE_VENDORCHANGES*::
+Do not add extra categories for every vendor change, instead cumulate
+them in one category.
+
+*SOLVER_TRANSACTION_RPM_ONLY*::
+Special view mode that just returns IGNORE, ERASE, INSTALL, MULTIINSTALL
+elements. Useful if you want to find out what to feed to the underlying
+package manager.
+
+Transaction order flags
+
+*SOLVER_TRANSACTION_KEEP_ORDERDATA*::
+Do not throw away the dependency graph used for ordering the transaction.
+This flag is needed if you want to do manual ordering.
+
+=== ATTRIBUTES ===
+
+       Pool *pool;                             /* read only */
+       $trans->{pool}
+       trans.pool
+       trans.pool
+
+Back pointer to pool.
+
+=== METHODS ===
+
+       bool isempty();
+       $trans->isempty()
+       trans.isempty()
+       trans.isempty?
+
+Returns true if the transaction does not do anything, i.e. has no elements.
+
+       Solvable *newsolvables();
+       my @newsolvables = $trans->newsolvables();
+       newsolvables = trans.newsolvables()
+       newsolvables = trans.newsolvables()
+
+Return all packages that are to be installed by the transaction. These are
+the packages that need to be downloaded from the repositories.
+
+       Solvable *keptsolvables();
+       my @keptsolvables = $trans->keptsolvables();
+       keptsolvables = trans.keptsolvables()
+       keptsolvables = trans.keptsolvables()
+
+Return all installed packages that the transaction will keep installed.
+
+       Solvable *steps();
+       my @steps = $trans->steps();
+       steps = trans.steps()
+       steps = trans.steps()
+
+Return all solvables that need to be installed (if the returned solvable
+is not already installed) or erased (if the returned solvable is installed).
+A step is also called a transaction element.
+
+       int steptype(Solvable *solvable, int mode)
+       my $type = $trans->steptype($solvable, $mode);
+       type = trans.steptype(solvable, mode)
+       type = trans.steptype(solvable, mode)
+
+Return the transaction type of the specified solvable. See the CONSTANTS
+sections for the mode argument flags and the list of returned types.
+
+       TransactionClass *classify(int mode = 0)
+       my @classes = $trans->classify();
+       classes = trans.classify()
+       classes = trans.classify()
+
+Group the transaction elements into classes so that they can be displayed
+in a structured way. You can use various mapping mode flags to tweak
+the result to match your preferences, see the mode argument flag in
+the CONSTANTS section. See the TransactionClass class for how to deal
+with the returned objects.
+
+       Solvable othersolvable(Solvable *solvable);
+       my $other = $trans->othersolvable($solvable);
+       other = trans.othersolvable(solvable)
+       other = trans.othersolvable(solvable)
+
+Return the ``other'' solvable for a given solvable. For installed packages
+the other solvable is the best package with the same name that replaces
+the installed package, or the best package of the obsoleting packages if
+the package does not get replaced by one with the same name.
+
+For to be installed packages, the ``other'' solvable is the best installed
+package with the same name that will be replaced, or the best packages
+of all the packages that are obsoleted if the new package does not replace
+a package with the same name.
+
+Thus, the ``other'' solvable is normally the package that is also shown
+for a given package.
+
+       Solvable *allothersolvables(Solvable *solvable);
+       my @others = $trans->allothersolvables($solvable);
+       others = trans.allothersolvables(solvable)
+       others = trans.allothersolvables(solvable)
+
+For installed packages, returns all of the packages that replace us. For to
+be installed packages, returns all of the packages that the new package
+replaces. The special ``other'' solvable is always the first entry of the
+returned array.
+
+       long long calc_installsizechange();
+       my $change = $trans->calc_installsizechange();
+       change = trans.calc_installsizechange()
+       change = trans.calc_installsizechange()
+
+Return the size change of the installed system in kilobytes (kibibytes).
+
+       void order(int flags = 0);
+       $trans->order();
+       trans.order()
+       trans.order()
+
+Order the steps in the transactions so that dependent packages are updated
+before packages that depend on them. For rpm, you can also use rpmlib's
+ordering functionality, debian's dpkg does not provide a way to order a
+transaction.
+
+=== ACTIVE/PASSIVE VIEW ===
+
+Active view lists what new packages get installed, while passive view shows
+what happens to the installed packages. Most often there's not much
+difference between the two modes, but things get interesting if multiple
+packages get replaced by one new package. Say you have installed packages
+A-1-1 and B-1-1, and now install A-2-1 which has a new dependency that
+obsoletes B. The transaction elements will be
+
+  updated   A-1-1 (other: A-2-1)
+  obsoleted B-1-1 (other: A-2-1)
+
+in passive mode, but
+
+  update A-2-1 (other: A-1-1)
+  erase  B
+
+in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the 
+passive mode list will be unchanged but the active mode list will just
+contain A-2-1.
+
+The Transactionclass Class
+--------------------------
+Objects of this type are returned by the classify() Transaction method.
+
+=== ATTRIBUTES ===
+
+       Transaction *transaction;               /* read only */
+       $class->{transaction}
+       class.transaction
+       class.transaction
+
+Back pointer to transaction object.
+
+       int type;                               /* read only */
+       $class->{type}
+       class.type
+       class.type
+
+The type of the transaction elements in the class.
+
+       int count;                              /* read only */
+       $class->{count}
+       class.count
+       class.count
+
+The number of elements in the class.
+
+       const char *fromstr;
+       $class->{fromstr}
+       class.fromstr
+       class.fromstr
+
+The old vendor or architecture.
+
+       const char *tostr;
+       $class->{tostr}
+       class.tostr
+       class.tostr
+
+The new vendor or architecture.
+
+       Id fromid;
+       $class->{fromid}
+       class.fromid
+       class.fromid
+
+The id of the old vendor or architecture.
+
+       Id toid;
+       $class->{toid}
+       class.toid
+       class.toid
+
+The id of the new vendor or architecture.
+
+=== METHODS ===
+
+       void solvables();
+       my @solvables = $class->solvables();
+       solvables = class.solvables()
+       solvables = class.solvables()
+
+Return the solvables for all transaction elements in the class.
+
+Checksums
+---------
+Checksums (also called hashes) are used to make sure that downloaded data is
+not corrupt and also as a fingerprint mechanism to check if data has changed.
+
+=== CLASS METHODS ===
+
+       Chksum Chksum(Id type)
+       my $chksum = solv::Chksum->new($type);
+       chksum = solv.Chksum(type)
+       chksum = Solv::Chksum.new(type)
+
+Create a checksum object. Currently the following types are supported:
+
+       REPOKEY_TYPE_MD5
+       REPOKEY_TYPE_SHA1
+       REPOKEY_TYPE_SHA256
+
+These keys are constants in the *solv* class.
+
+       Chksum Chksum(Id type, const char *hex)
+       my $chksum = solv::Chksum->new($type, $hex);
+       chksum = solv.Chksum(type, hex)
+       chksum = Solv::Chksum.new(type, hex)
+
+Create an already finalized checksum object from a hex string.
+
+       Chksum Chksum_from_bin(Id type, char *bin)
+       my $chksum = solv::Chksum->from_bin($type, $bin);
+       chksum = solv.Chksum.from_bin(type, bin)
+       chksum = Solv::Chksum.from_bin(type, bin)
+
+Create an already finalized checksum object from a binary checksum.
+
+=== ATTRIBUTES ===
+
+       Id type;                        /* read only */
+       $chksum->{type}
+       chksum.type
+       chksum.type
+
+Return the type of the checksum object.
+
+=== METHODS ===
+
+       void add(const char *str)
+       $chksum->add($str);
+       chksum.add(str)
+       chksum.add(str)
+
+Add a (binary) string to the checksum.
+
+       void add_fp(FILE *fp)
+       $chksum->add_fp($file);
+       chksum.add_fp(file)
+       chksum.add_fp(file)
+
+Add the contents of a file to the checksum.
+       
+       void add_stat(const char *filename)
+       $chksum->add_stat($filename);
+       chksum.add_stat(filename)
+       chksum.add_stat(filename)
+
+Stat the file and add the dev/ino/size/mtime member to the checksum. If the
+stat fails, the members are zeroed.
+
+       void add_fstat(int fd)
+       $chksum->add_fstat($fd);
+       chksum.add_fstat(fd)
+       chksum.add_fstat(fd)
+
+Same as add_stat, but instead of the filename a file descriptor is used.
+
+       unsigned char *raw()
+       my $raw = $chksum->raw();
+       raw = chksum.raw()
+       raw = chksum.raw()
+
+Finalize the checksum and return the result as raw bytes. This means that the
+result can contain NUL bytes or unprintable characters.
+
+       const char *hex()
+       my $raw = $chksum->hex();
+       raw = chksum.hex()
+       raw = chksum.hex()
+
+Finalize the checksum and return the result as hex string.
+
+       const char *typestr()
+       my $typestr = $chksum->typestr();
+       typestr = chksum.typestr
+       typestr = chksum.typestr
+
+Return the type of the checksum as a string, e.g. "sha256".
+
+       <equality>
+       if ($chksum1 == $chksum2)
+       if chksum1 == chksum2:
+       if chksum1 == chksum2
+
+Checksums are equal if they are of the same type and the finalized results are
+the same.
+
+       <stringification>
+       my $str = $chksum->str;
+       str = str(chksum)
+       str = chksum.to_s
+
+If the checksum is finished, the checksum is returned as "<type>:<hex>" string.
+Otherwise "<type>:unfinished" is returned.
+
+
+File Management
+---------------
+This functions were added because libsolv uses standard *FILE* pointers to
+read/write files, but languages like perl have their own implementation of
+files. The libsolv functions also support decompression and compression, the
+algorithm is selected by looking at the file name extension.
+
+       FILE *xfopen(char *fn, char *mode = "r")
+       my $file = solv::xfopen($path);
+       file = solv.xfopen(path)
+       file = Solv::xfopen(path)
+
+Open a file at the specified path. The `mode` argument is passed on to the
+stdio library.
+
+       FILE *xfopen_fd(char *fn, int fileno)
+       my $file = solv::xfopen_fd($path, $fileno);
+       file = solv.xfopen_fd(path, fileno)
+       file = Solv::xfopen_fd(path, fileno)
+
+Create a file handle from the specified file descriptor. The path argument is
+only used to select the correct (de-)compression algorithm, use an empty path
+if you want to make sure to read/write raw data. The file descriptor is dup()ed
+before the file handle is created.
+
+=== METHODS ===
+
+       int fileno()
+       my $fileno = $file->fileno();
+       fileno = file.fileno()
+       fileno = file.fileno()
+
+Return file file descriptor of the file. If the file is not open, `-1` is
+returned.
+
+       void cloexec(bool state)
+       $file->cloexec($state)
+       file.cloexec(state)
+       file.cloexec(state)
+
+Set the close-on-exec flag of the file descriptor. The xfopen function
+returns files with close-on-exec turned on, so if you want to pass
+a file to some other process you need to call cloexec(0) before calling
+exec.
+
+       int dup()
+       my $fileno = $file->dup();
+       fileno = file.dup()
+       fileno = file.dup()
+
+Return a copy of the descriptor of the file. If the file is not open, `-1` is
+returned.
+
+       bool flush()
+       $file->flush();
+       file.flush()
+       file.flush()
+
+Flush the file. Returns false if there was an error. Flushing a closed file
+always returns true.
+
+       bool close()
+       $file->close();
+       file.close()
+       file.close()
+
+Close the file. This is needed for languages like Ruby that do not destruct
+objects right after they are no longer referenced. In that case, it is good
+style to close open files so that the file descriptors are freed right away.
+Returns false if there was an error.
+
+
+The Repodata Class
+------------------
+The Repodata stores attributes for packages and the repository itself, each
+repository can have multiple repodata areas. You normally only need to
+directly access them if you implement lazy downloading of repository data.
+Repodata areas are created by calling the repository's add_repodata() method 
+or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING
+flag.
+
+=== ATTRIBUTES ===
+
+       Repo *repo;                     /* read only */
+       $data->{repo}
+       data.repo
+       data.repo
+
+Back pointer to repository object.
+
+       Id id;                                  /* read only */
+       $data->{id}
+       data.id
+       data.id
+
+The id of the repodata area. Repodata ids of different repositories overlap.
+
+=== METHODS ===
+
+       internalize();
+       $data->internalize();
+       data.internalize()
+       data.internalize()
+
+Internalize newly added data. The lookup functions will only see the new data
+after it has been internalized.
+
+       bool write(FILE *fp);
+       $data->write($fp);
+       data.write(fp)
+       data.write(fp)
+
+Write the contents of the repodata area as solv file.
+
+       Id str2dir(const char *dir, bool create = 1)
+       my $did = data->str2dir($dir);
+       did = data.str2dir(dir)
+       did = data.str2dir(dir)
+
+       const char *dir2str(Id did, const char *suffix = 0)
+       $dir = pool->dir2str($did);
+       dir = pool.dir2str(did)
+       dir = pool.dir2str(did)
+
+Convert a string (directory) into an Id and back. If the string is currently not in the
+pool and _create_ is false, zero is returned.
+
+       void add_dirstr(Id solvid, Id keyname, Id dir, const char *str)
+       $data->add_dirstr($solvid, $keyname, $dir, $string)
+       data.add_dirstr(solvid, keyname, dir, string)
+       data.add_dirstr(solvid, keyname, dir, string)
+
+Add a file path consisting of a dirname Id and a basename string.
+
+       bool add_solv(FILE *fp, int flags = 0);
+       $data->add_solv($fp);
+       data.add_solv(fp)
+       data.add_solv(fp)
+
+Replace a stub repodata object with the data from a solv file. This method
+automatically adds the REPO_USE_LOADING flag. It should only be used from
+a load callback.
+
+       void create_stubs();
+       $data->create_stubs()
+       data.create_stubs()
+       data.create_stubs()
+
+Create stub repodatas from the information stored in the repodata meta
+area.
+
+       void extend_to_repo();
+       $data->extend_to_repo();
+       data.extend_to_repo()
+       data.extend_to_repo()
+
+Extend the repodata so that it has the same size as the repo it belongs to.
+This method is needed when setting up a new extension repodata so that it
+matches the repository size. It is also needed when switching to a just written
+repodata extension to make the repodata match the written extension (which is
+always of the size of the repo).
+
+       <equality>
+       if ($data1 == $data2)
+       if data1 == data2:
+       if data1 == data2
+
+Two repodata objects are equal if they belong to the same repository and have
+the same id.
+
+=== DATA RETRIEVAL METHODS ===
+
+       const char *lookup_str(Id solvid, Id keyname)
+       my $string = $data->lookup_str($solvid, $keyname);
+       string = data.lookup_str(solvid, keyname)
+       string = data.lookup_str(solvid, keyname)
+
+       const char *lookup_id(Id solvid, Id keyname)
+       my $string = $data->lookup_id($solvid, $keyname);
+       string = data.lookup_id(solvid, keyname)
+       string = data.lookup_id(solvid, keyname)
+
+       unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0)
+       my $num = $data->lookup_num($solvid, $keyname);
+       num = data.lookup_num(solvid, keyname)
+       num = data.lookup_num(solvid, keyname)
+
+       bool lookup_void(Id solvid, Id keyname)
+       my $bool = $data->lookup_void($solvid, $keyname);
+       bool = data.lookup_void(solvid, keyname)
+       bool = data.lookup_void(solvid, keyname)
+
+       Id *lookup_idarray(Id solvid, Id keyname)
+       my @ids = $data->lookup_idarray($solvid, $keyname);
+       ids = data.lookup_idarray(solvid, keyname)
+       ids = data.lookup_idarray(solvid, keyname)
+
+       Chksum lookup_checksum(Id solvid, Id keyname)
+       my $chksum = $data->lookup_checksum($solvid, $keyname);
+       chksum = data.lookup_checksum(solvid, keyname)
+       chksum = data.lookup_checksum(solvid, keyname)
+
+Lookup functions. Return the data element stored in the specified solvable.
+The methods probably only make sense to retrieve data from the special
+SOLVID_META solvid that stores repodata meta information.
+
+=== DATA STORAGE METHODS ===
+
+       void set_str(Id solvid, Id keyname, const char *str);
+       $data->set_str($solvid, $keyname, $str);
+       data.set_str(solvid, keyname, str)
+       data.set_str(solvid, keyname, str)
+
+       void set_id(Id solvid, Id keyname, DepId id);
+       $data->set_id($solvid, $keyname, $id);
+       data.set_id(solvid, keyname, id)
+       data.set_id(solvid, keyname, id)
+
+       void set_num(Id solvid, Id keyname, unsigned long long num);
+       $data->set_num($solvid, $keyname, $num);
+       data.set_num(solvid, keyname, num)
+       data.set_num(solvid, keyname, num)
+
+       void set_void(Id solvid, Id keyname);
+       $data->set_void($solvid, $keyname);
+       data.set_void(solvid, keyname)
+       data.set_void(solvid, keyname)
+
+       void set_poolstr(Id solvid, Id keyname, const char *str);
+       $data->set_poolstr($solvid, $keyname, $str);
+       data.set_poolstr(solvid, keyname, str)
+       data.set_poolstr(solvid, keyname, str)
+
+       void set_checksum(Id solvid, Id keyname, Chksum *chksum);
+       $data->set_checksum($solvid, $keyname, $chksum);
+       data.set_checksum(solvid, keyname, chksum)
+       data.set_checksum(solvid, keyname, chksum)
+
+       void set_sourcepkg(Id solvid, const char *sourcepkg);
+       $data.set_sourcepkg($solvid, $sourcepkg);
+       data.set_sourcepkg(solvid, sourcepkg)
+       data.set_sourcepkg(solvid, sourcepkg)
+
+       void set_location(Id solvid, unsigned int mediano, const char *location);
+       $data.set_location($solvid, $mediano, $location);
+       data.set_location(solvid, mediano, location)
+       data.set_location(solvid, mediano, location)
+
+       void add_idarray(Id solvid, Id keyname, DepId id);
+       $data->add_idarray($solvid, $keyname, $id);
+       data.add_idarray(solvid, keyname, id)
+       data.add_idarray(solvid, keyname, id)
+
+       Id new_handle();
+       my $handle = $data->new_handle();
+       handle = data.new_handle()
+       handle = data.new_handle()
+
+       void add_flexarray(Id solvid, Id keyname, Id handle);
+       $data->add_flexarray($solvid, $keyname, $handle);
+       data.add_flexarray(solvid, keyname, handle)
+       data.add_flexarray(solvid, keyname, handle)
+
+       void unset(Id solvid, Id keyname);
+       $data->unset($solvid, $keyname);
+       data.unset(solvid, keyname)
+       data.unset(solvid, keyname)
+
+Data storage methods. Probably only useful to store data in the special
+SOLVID_META solvid that stores repodata meta information. Note that
+repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag),
+so be careful if you need to store ids. Arrays are created by calling
+the add function for every element. A flexarray is an array of
+sub-structures, call new_handle to create a new structure, use the
+handle as solvid to fill the structure with data and call add_flexarray
+to put the structure in an array.
+
+
+The Datapos Class
+-----------------
+Datapos objects describe a specific position in the repository data area.
+Thus they are only valid until the repository is modified in some way.
+Datapos objects can be created by the pos() and parentpos() methods of
+a Datamatch object or by accessing the ``meta'' attribute of a repository.
+
+=== ATTRIBUTES ===
+
+       Repo *repo;                     /* read only */
+       $data->{repo}
+       data.repo
+       data.repo
+
+Back pointer to repository object.
+
+=== METHODS ===
+
+       Dataiterator(Id keyname, const char *match, int flags)
+       my $di = $datapos->Dataiterator($keyname, $match, $flags);
+       di = datapos.Dataiterator(keyname, match, flags)
+       di = datapos.Dataiterator(keyname, match, flags)
+
+Create a Dataiterator at the position of the datapos object.
+
+       const char *lookup_deltalocation(unsigned int *OUTPUT);
+       my ($location, $mediano) = $datapos->lookup_deltalocation();
+       location, mediano = datapos.lookup_deltalocation()
+       location, mediano = datapos.lookup_deltalocation()
+
+Return a tuple containing the on-media location and an optional media number
+for a delta rpm. This obviously only works if the data position points to
+structure describing a delta rpm.
+
+       const char *lookup_deltaseq();
+       my $seq = $datapos->lookup_deltaseq();
+       seq = datapos.lookup_deltaseq();
+       seq = datapos.lookup_deltaseq();
+
+Return the delta rpm sequence from the structure describing a delta rpm.
+
+=== DATA RETRIEVAL METHODS ===
+
+       const char *lookup_str(Id keyname)
+       my $string = $datapos->lookup_str($keyname);
+       string = datapos.lookup_str(keyname)
+       string = datapos.lookup_str(keyname)
+
+       Id lookup_id(Id solvid, Id keyname)
+       my $id = $datapos->lookup_id($keyname);
+       id = datapos.lookup_id(keyname)
+       id = datapos.lookup_id(keyname)
+
+       unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0)
+       my $num = $datapos->lookup_num($keyname);
+       num = datapos.lookup_num(keyname)
+       num = datapos.lookup_num(keyname)
+
+       bool lookup_void(Id keyname)
+       my $bool = $datapos->lookup_void($keyname);
+       bool = datapos.lookup_void(keyname)
+       bool = datapos.lookup_void(keyname)
+
+       Id *lookup_idarray(Id keyname)
+       my @ids = $datapos->lookup_idarray($keyname);
+       ids = datapos.lookup_idarray(keyname)
+       ids = datapos.lookup_idarray(keyname)
+
+       Chksum lookup_checksum(Id keyname)
+       my $chksum = $datapos->lookup_checksum($keyname);
+       chksum = datapos.lookup_checksum(keyname)
+       chksum = datapos.lookup_checksum(keyname)
+
+Lookup functions. Note that the returned Ids are always translated into
+the Ids of the global pool even if the repodata area contains its own pool.
+
+       Dataiterator Dataiterator(Id keyname, const char *match = 0, int flags = 0)
+       my $di = $datapos->Dataiterator($keyname, $match, $flags);
+       di = datapos.Dataiterator(keyname, match, flags)
+       di = datapos.Dataiterator(keyname, match, flags)
+
+       for my $d (@$di)
+       for d in di:
+       for d in di
+
+Iterate over the matching data elements. See the Dataiterator class for more
+information.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/libsolv-constantids.txt b/libsolv-0.7.2/doc/libsolv-constantids.txt
new file mode 100644 (file)
index 0000000..907a7e5
--- /dev/null
@@ -0,0 +1,683 @@
+Libsolv-Constantids(3)
+======================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+libsolv-constantids - fixed Ids for often used strings
+
+
+Description
+-----------
+Constant Ids are Ids of strings that are often needed. They are defined
+to ease programming and reduce the number of pool_str2id calls. The
+constant Ids are part of the binary ABI of libsolv, a minor version 
+update will only add new constants and not change existing Ids to
+maintain compatible. The on-disk solv format works does not use the
+fixed Ids, but instead references the strings, so solv files can still
+be read when the ABI is broken.
+
+
+Special Strings
+---------------
+*ID_EMPTY ""*::
+  The empty string. It will always have Id 1.
+
+*SYSTEM_SYSTEM "system:system"*::
+  The name of the always installed "system" solvable.
+
+
+Solvable Attributes
+-------------------
+These are Ids for keyname of attributes. They can be used in the
+lookup and storage functions to select the correct attribute in the
+solvable. The descriptions below describe the intended semantics
+of the values stored in the attribute with the keyname.
+
+*SOLVABLE_NAME "solvable:name"*::
+  The name of the package.
+
+*SOLVABLE_ARCH "solvable:arch"*::
+  The architecture of the package. See the Solvable Architecture section
+  for predefined architecture Id values.
+
+*SOLVABLE_EVR "solvable:evr"*::
+  The version of the package. It usually consists of some combination of
+  the Epoch, the Version, and the Release of the solvable.
+
+*SOLVABLE_VENDOR "solvable:vendor"*::
+  A vendor string. Usually the company or group that created the binary
+  package.
+
+*SOLVABLE_PROVIDES "solvable:provides"*::
+  Stores an array of dependency Ids that describe the capabilities
+  that the package provides.
+
+*SOLVABLE_OBSOLETES "solvable:obsoletes"*::
+  Stores an array of dependency Ids that describe the packages that this
+  package replaces.
+
+*SOLVABLE_CONFLICTS "solvable:conflicts"*::
+  Stores an array of dependency Ids that describe the capabilities that
+  this package conflicts with, i.e. that can't be installed together with
+  this package.
+
+*SOLVABLE_REQUIRES "solvable:requires"*::
+  Stores an array of dependency Ids that describe the capabilities that
+  also must be installed when this package is installed.
+
+*SOLVABLE_RECOMMENDS "solvable:recommends"*::
+  Stores an array of dependency Ids that describe the capabilities that
+  also should be installed when this package is installed. It's not an
+  error if not all capabilities can be met.
+
+*SOLVABLE_SUGGESTS "solvable:suggests"*::
+  Stores an array of dependency Ids that describe the capabilities that
+  also useful to have installed when this package is installed. This is
+  intended to provide a hint to the user about other packages.
+
+*SOLVABLE_SUPPLEMENTS "solvable:supplements"*::
+  Stores an array of dependency Ids that define that this package should
+  be installed if one of the capabilities is met. This is like the
+  recommends attribute, but works in the reverse way.
+
+*SOLVABLE_ENHANCES "solvable:enhances"*::
+  Stores an array of dependency Ids that define that this package is
+  useful to have installed if one of the capabilities is met. This is like
+  the suggests attribute, but works in the reverse way.
+
+*SOLVABLE_SUMMARY "solvable:summary"*::
+  The summary should be a short string without any newlines that describes
+  what a package does.
+
+*SOLVABLE_DESCRIPTION "solvable:description"*::
+  The description should be a more verbose description about what a
+  package does. It may consist of multiple lines.
+
+*SOLVABLE_DISTRIBUTION "solvable:distribution"*::
+  The distribution is a short string that describes the OS and OS version
+  this package is built for.
+
+*SOLVABLE_AUTHORS "solvable:authors"*::
+  A list of authors of this package. This attribute was used in SUSE
+  packages.
+
+*SOLVABLE_PACKAGER "solvable:packager"*::
+  The person who created the binary package, see also the vendor attribute.
+
+*SOLVABLE_GROUP "solvable:group"*::
+  The package group that this package belongs to. See also the keywords
+  attribute.
+
+*SOLVABLE_URL "solvable:url"*::
+  An URL that points to more information about the package.
+
+*SOLVABLE_KEYWORDS "solvable:keywords"*::
+  list of keyword string IDs used for tagging this package.
+
+*SOLVABLE_LICENSE "solvable:license"*::
+  The license(s) of this package.
+
+*SOLVABLE_BUILDTIME "solvable:buildtime"*::
+  The seconds since the unix epoch when the binary package was created.
+
+*SOLVABLE_BUILDHOST "solvable:buildhost"*::
+  The name of the host on which the binary package was created.
+
+*SOLVABLE_EULA "solvable:eula"*::
+  If this attribute is present the user should be asked to accept the end
+  user license agreement before the package gets installed.
+
+*SOLVABLE_CPEID "solvable:cpeid"*::
+  A Common Platform Enumeration string describes the platform this package
+  is intended for. See also the distribution attribute.
+
+*SOLVABLE_MESSAGEINS "solvable:messageins"*::
+  A message that should be displayed to the user when the package gets
+  installed.
+
+*SOLVABLE_MESSAGEDEL "solvable:messagedel"*::
+  A message that should be displayed to the user when the package gets
+  erased.
+
+*SOLVABLE_INSTALLSIZE "solvable:installsize"*::
+  The disk space in bytes needed when installing the package.
+
+*SOLVABLE_DISKUSAGE "solvable:diskusage"*::
+  A SUSE extension that stores for each directory the needed amount of
+  disk space in kilobytes and inodes.
+
+*SOLVABLE_FILELIST "solvable:filelist"*::
+  A list of files that the package contains.
+
+*SOLVABLE_INSTALLTIME "solvable:installtime"*::
+  The seconds since the unix epoch when the binary package was installed
+  on the system.
+
+*SOLVABLE_MEDIADIR "solvable:mediadir"*::
+  The directory on the repository that contains the package. If this
+  attribute is set to void, the package architecture is used as
+  directory.
+
+*SOLVABLE_MEDIAFILE "solvable:mediafile"*::
+  The filename on the repository that contains the package. If this
+  attribute is set to void, the canonical file name of the package is
+  used (i.e.  a combination of the name, version, architecture).
+
+*SOLVABLE_MEDIANR "solvable:medianr"*::
+  The media number. This is an integer describing on which of a multi-part
+  media set this package is on.
+
+*SOLVABLE_MEDIABASE "solvable:mediabase"*::
+  This attribute can be used to overwrite the repositories base url.
+
+*SOLVABLE_DOWNLOADSIZE "solvable:downloadsize"*::
+  The size of the binary package in bytes.
+
+*SOLVABLE_SOURCEARCH "solvable:sourcearch"*::
+  The architecture of the source package that this package belongs to.
+
+*SOLVABLE_SOURCENAME "solvable:sourcename"*::
+  The name of the source package that this package belongs to. If set
+  to void, the package name attribute is used instead.
+
+*SOLVABLE_SOURCEEVR "solvable:sourceevr"*::
+  The version of the source package that this package belongs to. If set
+  to void, the package version attribute is used instead.
+
+*SOLVABLE_TRIGGERS "solvable:triggers"*::
+  A list of package triggers for this package. Used in the transaction
+  ordering code.
+
+*SOLVABLE_CHECKSUM "solvable:checksum"*::
+  The checksum of the binary package. See the Data Types section for
+  a list of supported algorithms.
+
+*SOLVABLE_PKGID "solvable:pkgid"*::
+  A string identifying a package. For rpm packages, this is the md5sum
+  over the package header and the payload.
+
+*SOLVABLE_HDRID "solvable:hdrid"*::
+  A string identifying a package. For rpm packages, this is the sha1sum
+  over just the package header.
+
+*SOLVABLE_LEADSIGID "solvable:leadsigid"*::
+  A string identifying the signature part of a package. For rpm packages,
+  this is the md5sum from the start of the file up to the package header
+  (i.e. it includes the lead, the signature header, and the padding).
+
+*SOLVABLE_HEADEREND "solvable:headerend"*::
+  The offset of the payload in rpm binary packages. You can use this
+  information to download just the header if you want to display
+  information not included in the repository metadata.
+
+*SOLVABLE_CHANGELOG "solvable:changelog"*::
+  The array containing all the changelog structures.
+
+*SOLVABLE_CHANGELOG_AUTHOR "solvable:changelog:author"*::
+  The author of a changelog entry.
+
+*SOLVABLE_CHANGELOG_TIME "solvable:changelog:time"*::
+  The seconds since the unix epoch when the changelog entry was written.
+
+*SOLVABLE_CHANGELOG_TEXT "solvable:changelog:text"*::
+  The text of a changelog entry.
+
+
+Special Solvable Attributes
+---------------------------
+*RPM_RPMDBID "rpm:dbid"*::
+  The rpm database id of this (installed) package. Usually a small
+  integer number.
+
+*SOLVABLE_PATCHCATEGORY "solvable:patchcategory"*::
+  The category field for patch solvables. Should be named
+  ``update:category'' instead.
+
+*UPDATE_REBOOT "update:reboot"*::
+  If this attribute is present the system should be rebooted after
+  the update is installed.
+
+*UPDATE_RESTART "update:restart"*::
+  If this attribute is present the software manager should be run
+  again after the update is installed.  
+
+*UPDATE_RELOGIN "update:relogin"*::
+  If this attribute is present the user should log off and on again
+  after the update is installed.
+
+*UPDATE_MESSAGE "update:message"*::
+  A message that should be shown to the user to warn him about anything
+  non-standard.
+
+*UPDATE_SEVERITY "update:severity"*::
+  The severity of the update.
+
+*UPDATE_RIGHTS "update:rights"*::
+  Any legal or other rights of the update.
+
+*UPDATE_COLLECTION "update:collection"*::
+  The array containing the package list of the update.
+  
+*UPDATE_COLLECTION_NAME "update:collection:name"*::
+  The name of the updated package.
+
+*UPDATE_COLLECTION_EVR "update:collection:evr"*::
+  The version of the updated package.
+
+*UPDATE_COLLECTION_ARCH "update:collection:arch"*::
+  The architecture of the updated package.
+
+*UPDATE_COLLECTION_FILENAME "update:collection:filename"*::
+  The file name of the updated package.
+
+*UPDATE_REFERENCE "update:reference"*::
+  The array containing the reference list of the update.
+
+*UPDATE_REFERENCE_TYPE "update:reference:type"*::
+  The type of the reference, e.g. bugzilla.
+
+*UPDATE_REFERENCE_HREF "update:reference:href"*::
+  The URL of the reference.
+
+*UPDATE_REFERENCE_ID "update:reference:id"*::
+  The identification string of the reference, e.g. the bug number.
+
+*UPDATE_REFERENCE_TITLE "update:reference:title"*::
+  The title of the reference, e.g. the bug summary.
+
+*PRODUCT_REFERENCEFILE "product:referencefile"*::
+  The basename of the product file in the package.
+
+*PRODUCT_SHORTLABEL "product:shortlabel"*::
+  An identification string of the product.
+
+*PRODUCT_DISTPRODUCT "product:distproduct"*::
+  Obsolete, do not use. Was a SUSE Code-10 product name.
+
+*PRODUCT_DISTVERSION "product:distversion"*::
+  Obsolete, do not use. Was a SUSE Code-10 product version.
+
+*PRODUCT_TYPE "product:type"*::
+  The type of the product, e.g. ``base''.
+
+*PRODUCT_URL "product:url"*::
+  An array of product URLs.
+
+*PRODUCT_URL_TYPE "product:url:type"*::
+  An array of product URL types.
+
+*PRODUCT_FLAGS "product:flags"*::
+  An array of product flags.
+
+*PRODUCT_PRODUCTLINE "product:productline"*::
+  A product line string used for product registering.
+
+*PRODUCT_REGISTER_TARGET "product:regtarget"*::
+  A target for product registering.
+
+*PRODUCT_REGISTER_RELEASE "product:regrelease"*::
+  A release string for product registering.
+
+*PUBKEY_KEYID "pubkey:keyid"*::
+  The keyid of a pubkey, consisting of 8 bytes in hex.
+
+*PUBKEY_FINGERPRINT "pubkey:fingerprint"*::
+  The fingerprint of a pubkey, usually a sha1sum in hex. Old V3 RSA keys
+  use a md5sum instead.
+
+*PUBKEY_EXPIRES "pubkey:expires"*::
+  The seconds since the unix epoch when the pubkey expires.
+
+*PUBKEY_SUBKEYOF "pubkey:subkeyof"*::
+  The keyid of the master pubkey for subkeys.
+
+*PUBKEY_DATA "pubkey:data"*::
+  The MPI data of the pubkey.
+
+*SOLVABLE_ISVISIBLE "solvable:isvisible"*::
+  An attribute describing if the package should be listed to the user
+  or not. Used for SUSE patterns.
+
+*SOLVABLE_CATEGORY "solvable:category"*::
+  The category of a pattern.
+
+*SOLVABLE_INCLUDES "solvable:includes"*::
+  A list of other patterns that this pattern includes.
+
+*SOLVABLE_EXTENDS "solvable:extends"*::
+  A list of other patterns that this pattern extends.
+
+*SOLVABLE_ICON "solvable:icon"*::
+  The icon name of a pattern.
+
+*SOLVABLE_ORDER "solvable:order"*::
+  An ordering clue of a pattern.
+
+*SUSETAGS_SHARE_NAME "susetags:share:name"*::
+  Internal attribute to implement susetags shared records. Holds the
+  name of the solvable used for sharing attributes.
+
+*SUSETAGS_SHARE_EVR "susetags:share:evr"*::
+  Internal attribute to implement susetags shared records. Holds the
+  version of the solvable used for sharing attributes.
+
+*SUSETAGS_SHARE_ARCH "susetags:share:arch"*::
+  Internal attribute to implement susetags shared records. Holds the
+  architecture of the solvable used for sharing attributes.
+
+
+Solvable Architectures
+----------------------
+Predefined architecture values for commonly used architectures.
+
+*ARCH_SRC "src"*::
+  Used for binary packages that contain the package sources.
+
+*ARCH_NOSRC "nosrc"*::
+  Used for binary packages that contain some of the package sources,
+  but not all files (because of restrictions).
+
+*ARCH_NOARCH "noarch"*::
+  This package can be installed on any architecture. Used for rpm.
+
+*ARCH_ALL "all"*::
+  This package can be installed on any architecture. Used for Debian.
+
+*ARCH_ANY "any"*::
+  This package can be installed on any architecture. Used for Archlinux
+  and Haiku.
+
+
+Dependency Ids
+--------------
+Namespaces are special modifiers that change the meaning of a dependency.
+Namespace dependencies are created with the REL_NAMESPACE flag. To make
+custom namespaces work you have to implement a namespace callback function.
+
+The dependency markers partition the dependency array in two parts with
+different semantics.
+
+*NAMESPACE_MODALIAS "namespace:modalias"*::
+  The dependency is a special modalias dependency that matches installed
+  hardware.
+
+*NAMESPACE_SPLITPROVIDES "namespace:splitprovides"*::
+  The dependency is a special splitprovides dependency used to implement
+  updates that include a package split. A splitprovides dependency contains
+  a filename and a package name, it is matched if a package with the
+  provided package name is installed that contains the filename.
+  This namespace is implemented in libsolv, so you do not need a callback.
+
+*NAMESPACE_LANGUAGE "namespace:language"*::
+  The dependency describes a language. The callback should return true
+  if the language was selected by the user.
+
+*NAMESPACE_FILESYSTEM "namespace:filesystem"*::
+  The dependency describes a filesystem. The callback should return true
+  if the filesystem is needed.
+
+*NAMESPACE_OTHERPROVIDERS "namespace:otherproviders"*::
+  This is a hack to allow self-conflicting packages. It is not needed
+  with current rpm version, so do not use this namespace.
+
+*SOLVABLE_PREREQMARKER "solvable:prereqmarker"*::
+  This marker partitions the normal require dependencies from the
+  prerequires. It is not needed for dependency solving, but it is
+  used by the transaction ordering algorithm when a dependency cycle
+  needs to be broken (non-prereq deps get broken first).
+
+*SOLVABLE_FILEMARKER "solvable:filemarker"*::
+  This marker partitions the package provides dependencies from the
+  synthetic file provides dependencies added by pool_addfileprovides().
+
+
+Data Types
+----------
+Each attribute data is stored with a type, so that the lookup functions
+know how to interpret the data. The following types are available:
+*REPOKEY_TYPE_VOID "repokey:type:void"*::
+  No data is stored with this attribute. Thus you can only test if
+  the attribute exists or not. Useful to store boolean values.
+
+*REPOKEY_TYPE_CONSTANT "repokey:type:constant"*::
+  The data is a constant 32bit number. The number is stored in the key
+  area, so using it does not cost extra storage space (but you need the
+  extra key space).
+
+*REPOKEY_TYPE_CONSTANTID "repokey:type:constantid"*::
+  The data is a constant Id. The Id is stored in the key area,
+  so using it does not cost extra storage space (but you need the
+  extra key space).
+
+*REPOKEY_TYPE_ID "repokey:type:id"*::
+  The data is an Id.
+
+*REPOKEY_TYPE_NUM "repokey:type:num"*::
+  The data is an unsigned 64bit number.
+
+*REPOKEY_TYPE_U32 "repokey:type:num32"*::
+  The data is an unsigned 32bit number. Obsolete, do not use.
+
+*REPOKEY_TYPE_DIR "repokey:type:dir"*::
+  The data is an Id of a directory.
+
+*REPOKEY_TYPE_STR "repokey:type:str"*::
+  The data is a regular string.
+
+*REPOKEY_TYPE_BINARY "repokey:type:binary"*::
+  The data is a binary blob.
+
+*REPOKEY_TYPE_IDARRAY "repokey:type:idarray"*::
+  The data is an array of non-zero Ids.
+
+*REPOKEY_TYPE_REL_IDARRAY "repokey:type:relidarray"*::
+  The data is an array of non-zero Ids ordered so that it needs less
+  space.
+
+*REPOKEY_TYPE_DIRSTRARRAY "repokey:type:dirstrarray"*::
+  The data is a tuple consisting of a directory Id and a basename.
+  Used to store file names.
+
+*REPOKEY_TYPE_DIRNUMNUMARRAY "repokey:type:dirnumnumarray"*::
+  The data is a triple consisting of a directory Id and two 32bit
+  unsigned integers. Used to store disk usage information.
+
+*REPOKEY_TYPE_MD5 "repokey:type:md5"*::
+  The data is a binary md5sum.
+
+*REPOKEY_TYPE_SHA1 "repokey:type:sha1"*::
+  The data is a binary sha1sum.
+
+*REPOKEY_TYPE_SHA256 "repokey:type:sha256"*::
+  The data is a binary sha256sum.
+
+*REPOKEY_TYPE_FIXARRAY "repokey:type:fixarray"*::
+  The data is an array of structures that have all the same layout
+  (i.e. the same keynames and keytypes in the same order).
+
+*REPOKEY_TYPE_FLEXARRAY "repokey:type:flexarray"*::
+  The data is an array of structures that have a different layout.
+
+*REPOKEY_TYPE_DELETED "repokey:type:deleted"*::
+  The data does not exist. Used to mark an attribute that was deleted.
+
+
+Repository Metadata
+-------------------
+This attributes contain meta information about the repository.
+
+*REPOSITORY_SOLVABLES "repository:solvables"*::
+  This attribute holds the array including all of the solvables. It is
+  only used in the on-disk solv files, internally the solvables are
+  stored in the pool's solvable array for fast access.
+
+*REPOSITORY_DELTAINFO "repository:deltainfo"*::
+  This attribute holds the array including all of the delta packages.
+
+*REPOSITORY_EXTERNAL "repository:external"*::
+  This attribute holds the array including all of the data to construct
+  stub repodata areas to support on-demand loading of metadata.
+
+*REPOSITORY_KEYS "repository:keys"*::
+  This should really be named "repository:external:keys", it contains an
+  array if Ids that consists of (keyname, keytype) pairs that describe the
+  keys of the stub.
+
+*REPOSITORY_LOCATION "repository:location"*::
+  This is used to provide a file name in the stub.
+
+*REPOSITORY_ADDEDFILEPROVIDES "repository:addedfileprovides"*::
+  This attribute holds an array of filename Ids, that tell the library,
+  that all of the Ids were already added to the solvable provides.
+
+*REPOSITORY_RPMDBCOOKIE "repository:rpmdbcookie"*::
+  An attribute that stores a sha256sum over the file stats of the
+  Packages database. It's used to detect rebuilds of the database,
+  as in that case the database Ids of every package are newly
+  distributed.
+
+*REPOSITORY_TIMESTAMP "repository:timestamp"*::
+  The seconds since the unix epoch when the repository was created.
+
+*REPOSITORY_EXPIRE "repository:expire"*::
+  The seconds after the timestamp when the repository will expire.
+
+*REPOSITORY_UPDATES "repository:updates"*::
+  An array of structures describing what this repository updates.
+
+*REPOSITORY_DISTROS "repository:distros"*::
+  Also an array of structures describing what this repository updates.
+  Seems to be the newer name of REPOSITORY_UPDATES.
+
+*REPOSITORY_PRODUCT_LABEL "repository:product:label"*::
+  Should really be called "repository:updates:label". What distribution
+  is updated with this repository.
+
+*REPOSITORY_PRODUCT_CPEID "repository:product:cpeid"*::
+  The cpeid of the platform updated by this repository. Is both used
+  in REPOSITORY_UPDATES and REPOSITORY_DISTROS to maximize confusion.
+
+*REPOSITORY_REPOID "repository:repoid"*::
+  An array of Id strings describing keywords/tags about the repository
+  itself.
+
+*REPOSITORY_KEYWORDS "repository:keywords"*::
+  An array of Id strings describing keywords/tags about the content of
+  the repository.
+
+*REPOSITORY_REVISION "repository:revision"*::
+  An arbitrary string describing the revision of the repository.
+
+*REPOSITORY_TOOLVERSION "repository:toolversion"*::
+  Some string describing somewhat the version of libsolv used to create
+  the solv file.
+
+
+Repository Metadata for Susetags Repos
+--------------------------------------
+Attributes describing repository files in a susetags repository.
+*SUSETAGS_DATADIR "susetags:datadir"*::
+  The directory that contains the packages.
+
+*SUSETAGS_DESCRDIR "susetags:descrdir"*::
+  The directory that contains the repository file resources.
+
+*SUSETAGS_DEFAULTVENDOR "susetags:defaultvendor"*::
+  The default vendor used when a package does not specify a vendor.
+
+*SUSETAGS_FILE "susetags:file"*::
+  An array of file resources of the repository.
+
+*SUSETAGS_FILE_NAME "susetags:file:name"*::
+  The filename of the resource.
+
+*SUSETAGS_FILE_TYPE "susetags:file:type"*::
+  The type of the resource, e.g. ``META''.
+
+*SUSETAGS_FILE_CHECKSUM "susetags:file:checksum"*::
+  The file checksum of the resource.
+
+
+Repository Metadata for RpmMD Repos
+-----------------------------------
+*REPOSITORY_REPOMD "repository:repomd"*::
+  An array of file resources of the repository.
+
+*REPOSITORY_REPOMD_TYPE "repository:repomd:type"*::
+  The type of the resource, e.g. ``primary''.
+
+*REPOSITORY_REPOMD_LOCATION "repository:repomd:location"*::
+  The location (aka filename) of the resource
+
+*REPOSITORY_REPOMD_TIMESTAMP "repository:repomd:timestamp"*::
+  The seconds since the unix epoch when the resource was created.
+
+*REPOSITORY_REPOMD_CHECKSUM "repository:repomd:checksum"*::
+  The file checksum of the resource.
+
+*REPOSITORY_REPOMD_OPENCHECKSUM "repository:repomd:openchecksum"*::
+  The checksum over the uncompressed contents of the resource.
+
+*REPOSITORY_REPOMD_SIZE "repository:repomd:size"*::
+  The size of the resource file.
+
+
+Delta Package Attributes
+------------------------
+*DELTA_PACKAGE_NAME "delta:pkgname"*::
+  The target package name for the delta package. Applying the delta
+  will recreate the target package.
+
+*DELTA_PACKAGE_EVR "delta:pkgevr"*::
+  The version of the target package.
+
+*DELTA_PACKAGE_ARCH "delta:pkgarch"*::
+  The architecture of the target package.
+
+*DELTA_LOCATION_DIR "delta:locdir"*::
+  The directory in the repository that contains the delta package.
+
+*DELTA_LOCATION_NAME "delta:locname"*::
+  The first part of the file name of the delta package.
+
+*DELTA_LOCATION_EVR "delta:locevr"*::
+  The version part of the file name of the delta package.
+
+*DELTA_LOCATION_SUFFIX "delta:locsuffix"*::
+  The suffix part of the file name of the delta package.
+
+*DELTA_LOCATION_BASE "delta:locbase"*::
+  This attribute can be used to overwrite the repositories base url for
+  the delta.
+
+*DELTA_DOWNLOADSIZE "delta:downloadsize"*::
+  The size of the delta rpm file.
+
+*DELTA_CHECKSUM "delta:checksum"*::
+  The checksum of the delta rpm file.
+
+*DELTA_BASE_EVR "delta:baseevr"*::
+  The version of the package the delta was built against.
+
+*DELTA_SEQ_NAME "delta:seqname"*::
+  The first part of the delta sequence, the base package name.
+
+*DELTA_SEQ_EVR "delta:seqevr"*::
+  The evr part of the delta sequence, the base package evr. Identical
+  to the DELTA_BASE_EVR attribute.
+
+*DELTA_SEQ_NUM "delta:seqnum"*::
+  The last part of the delta sequence, the content selection string.
+
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/libsolv-history.txt b/libsolv-0.7.2/doc/libsolv-history.txt
new file mode 100644 (file)
index 0000000..d0a5e62
--- /dev/null
@@ -0,0 +1,117 @@
+Libsolv-History(3)
+==================
+:man manual: LIBSOLV
+:man source: libsolv
+
+Name
+----
+libsolv-history - how the libsolv library came into existence
+
+History
+-------
+This project was started in May 2007 when the zypp folks decided to switch
+to a database to speed up installation. As I am not a big fan of databases,
+I (mls) wondered if there would be really some merit of using one for solving,
+as package dependencies of all packages have to be read in anyway.
+
+Back in 2002, I researched that using a dictionary approach for storing
+dependencies can reduce the packages file to 1/3 of its size. Extending
+this idea a bit more, I decided to store all strings and relations
+as unique 32-bit numbers. This has three big advantages:
+
+- because of the unification, testing whether two strings are equal is the
+  same as testing the equality of two numbers, thus very fast
+- much space is saved, as numbers do not take up as much space as strings
+  the internal memory representation does not take more space on a
+  64-bit system where a pointer is twice the size of a 32-bit number
+
+Thus, the solv format was created, which stores a repository as a string
+dictionary, a relation dictionary and then all packages dependencies.
+Tests showed that reading and merging multiple solv repositories takes
+just some milliseconds.
+
+=== Early solver experiments ===
+Having a new repository format was one big step, but the other area
+where libzypp needed improvement was the solver. Libzypp's solver was
+a port from the Red Carpet solver, which was written to update packages
+in an already installed system. Using it for the complete installation
+progress brought it to its limits. Also, the added extensions like
+support for weak dependencies and patches made it fragile and
+unpredictable.
+
+As I was not very pleased with the way the solver worked, I looked at
+other solver algorithms. I checked smart, yum and apt, but could not
+find a convincing algorithm. My own experiments also were not very
+convincing, they worked fine for some problems but failed miserably
+for other corner cases.
+
+=== Using SAT for solving ===
+SUSE's hack week at the end of June 2007 turned out to be a turning point
+for the solver. Googling for solver algorithms, I stumbled over some note
+saying that some people are trying to use SAT algorithms to improve
+solving on Debian. Looking at the SAT entry in Wikipedia, it was easy
+to see that this indeed was the missing piece: SAT algorithms are well
+researched and there are quite some open source implementations.
+I decided to look at the minisat code, as it is one of the fastest
+solvers while consisting of too many lines of code.
+
+Of course, directly using minisat would not work, as a package solver
+does not need to find just one correct solution, but it also has to
+optimize some metrics, i.e. keep as many packages installed as possible.
+Thus, I needed to write my own solver incorporation the ideas and
+algorithms used in minisat. This wasn't very hard, and at the end of
+the hack week the solver calculated the first right solutions.
+
+=== Selling it to libzypp ===
+With those encouraging results, I went to Klaus Kaempf, the system
+management architect at SUSE. We spoke about how to convince the
+team to make libzypp switch to the new solver. Fortunately, libzypp comes
+with a plethora of solver test cases, so we decided to make the solver pass
+most of the test cases first. Klaus wrote a "deptestomatic" implementation
+to check the test cases. Together with Stephan Kulow, who is responsible for the
+openSUSE distribution, we tweaked and extended the solver until most of
+the test cases looked good.
+
+Duncan Mac-Vicar Prett, the team lead of the YaST team, also joined
+development by creating Ruby bindings for the solver. Later, Klaus
+improved the bindings and ported them to some other languages.
+
+=== The attribute store ===
+The progress with the repository format and the solver attracted another
+hacker to the project: Michael Matz from the compiler team. He started
+with improving the repository parsers so that patches and content files
+also generate solvables. After that, he concentrated on storing all
+of the other metadata of the repositories that are not used for solving,
+like the package summaries and descriptions. At the end of October, a first
+version of this "attribute store" was checked in. Its design goals were:
+
+- space efficient storage of attributes
+- paging/on demand loading of data
+- page compression
+
+The first version of the attribute store used a different format for
+storing information, we later merged this format with the solv file
+format.
+
+=== libzypp integration ===
+Integration of the sat-solver into libzypp also started in October 2007 by
+Stefan Schubert and Michael Andres from the YaST team. The first
+versions supported both the old solver and the new one by using the
+old repository read functions and converting the old package data
+in-memory into a sat solver pool. Solvers could be switched with
+the environment variable ZYPP_SAT_SOLVER. The final decision to
+move to the new solver was made in January of 2008, first just by
+making the new solver the default one, later by completely throwing out
+the old solver code. This had the advantage that the internal solvable
+storage could also be done by using the solver pool, something Michael
+Matz already played with in a proof of concept implementation showing
+some drastic speed gains. The last traces of the old database code
+were removed in February.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/libsolv-pool.txt b/libsolv-0.7.2/doc/libsolv-pool.txt
new file mode 100644 (file)
index 0000000..0b9bc41
--- /dev/null
@@ -0,0 +1,934 @@
+Libsolv-Pool(3)
+===============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+libsolv-pool - Libsolv's pool object
+
+
+Public Attributes
+-----------------
+
+*void *appdata*::
+A no-purpose pointer free to use for the library user. Freeing the pool
+simply discards the pointer.
+
+*Stringpool ss*::
+The pool of unified strings.
+
+*Reldep *rels*::
+The pool of unified relation dependencies.
+
+*int nrels*::
+Number of allocated relation dependencies.
+
+*Repo **repos*::
+The array of repository pointers, indexed by repository Id.
+
+*int nrepos*::
+Number of allocated repository array elements, i.e. the size
+of the repos array.
+
+*int urepos*::
+Number of used (i.e. non-zero) repository array elements.
+
+*Repo *installed*::
+Pointer to the repo holding the installed packages. You are free to read
+this attribute, but you should use pool_set_installed() if you want to
+change it.
+
+*Solvable *solvables*::
+The array of Solvable objects.
+
+*int nsolvables*::
+Number of Solvable objects, i.e. the size of the solvables array. Note
+that the array may contain freed solvables, in that case the repo pointer
+of the solvable will be zero.
+
+*int disttype*::
+The distribution type of your system, e.g. DISTTYPE_DEB. You are free to
+read this attribute, but you should use pool_setdisttype() if you want to
+change it.
+
+*Id *whatprovidesdata*::
+Multi-purpose Id storage holding zero terminated arrays of Ids.
+pool_whatprovides() returns an offset into this data.
+
+*Map *considered*::
+Optional bitmap that can make the library ignore solvables. If a bitmap is
+set, only solvables that have a set bit in the bitmap at their Id are
+considered usable.
+
+*int debugmask*::
+A mask that defines which debug events should be reported.
+pool_setdebuglevel() sets this mask.
+
+*Datapos pos*::
+An object storing some position in the repository data. Functions like
+dataiterator_set_pos() set this object, accessing data with a pseudo
+solvable Id of SOLVID_POS uses it.
+
+*Queue pooljobs*::
+A queue where fixed solver jobs can be stored. This jobs are automatically
+added when solver_solve() is called, they are useful to store configuration
+data like which packages should be multiversion installed.
+
+Creation and Destruction
+------------------------
+
+       Pool *pool_create();
+
+Create a new instance of a pool.
+
+       void pool_free(Pool *pool);
+
+Free a pool and all of the data it contains, e.g. the solvables, 
+repositories, strings.
+
+
+Debugging and error reporting
+-----------------------------
+
+=== Constants ===
+
+*SOLV_FATAL*::
+Report the error and call ``exit(1)'' afterwards. You cannot mask this
+level. Reports to stderr instead of stdout.
+
+*SOLV_ERROR*::
+Used to report errors. Reports to stderr instead of stdout.
+
+*SOLV_WARN*::
+Used to report warnings.
+
+*SOLV_DEBUG_STATS*::
+Used to report statistical data.
+
+*SOLV_DEBUG_RULE_CREATION*::
+Used to report information about the solver's creation of rules.
+
+*SOLV_DEBUG_PROPAGATE*::
+Used to report information about the solver's unit rule propagation
+process.
+
+*SOLV_DEBUG_ANALYZE*::
+Used to report information about the solver's learnt rule generation
+mechanism.
+
+*SOLV_DEBUG_UNSOLVABLE*::
+Used to report information about the solver dealing with conflicting
+rules.
+
+*SOLV_DEBUG_SOLUTIONS*::
+Used to report information about the solver creating solutions to solve
+problems.
+
+*SOLV_DEBUG_POLICY*::
+Used to report information about the solver searching for an optimal
+solution.
+
+*SOLV_DEBUG_RESULT*::
+Used by the debug functions to output results.
+
+*SOLV_DEBUG_JOB*::
+Used to report information about the job rule generation process.
+
+*SOLV_DEBUG_SOLVER*::
+Used to report information about what the solver is currently
+doing.
+
+*SOLV_DEBUG_TRANSACTION*::
+Used to report information about the transaction generation and
+ordering process.
+
+*SOLV_DEBUG_TO_STDERR*::
+Write debug messages to stderr instead of stdout.
+
+=== Functions ===
+
+       void pool_debug(Pool *pool, int type, const char *format, ...);
+
+Report a message of the type _type_. You can filter debug messages by
+setting a debug mask.
+
+       void pool_setdebuglevel(Pool *pool, int level);
+
+Set a predefined debug mask. A higher level generally means more bits in
+the mask are set, thus more messages are printed.
+
+       void pool_setdebugmask(Pool *pool, int mask);
+
+Set the debug mask to filter debug messages.
+
+       int pool_error(Pool *pool, int ret, const char *format, ...);
+
+Set the pool's error string. The _ret_ value is simply used as a
+return value of the function so that you can write code like
++return pool_error(...);+. If the debug mask contains the *SOLV_ERROR*
+bit, pool_debug() is also called with the message and type *SOLV_ERROR*.
+
+       extern char *pool_errstr(Pool *pool);
+
+Return the current error string stored in the pool. Like with the libc's
+errno value, the string is only meaningful after a function returned an
+error.
+
+       void pool_setdebugcallback(Pool *pool, void (*debugcallback)(Pool *, void *data, int type, const char *str), void *debugcallbackdata);
+
+Set a custom debug callback function. Instead of writing to stdout or
+stderr, the callback function will be called.
+
+
+Pool configuration
+------------------
+
+=== Constants ===
+
+*DISTTYPE_RPM*::
+Used for systems which use rpm as low level package manager.
+
+*DISTTYPE_DEB*::
+Used for systems which use dpkg as low level package manager.
+
+*DISTTYPE_ARCH*::
+Used for systems which use the arch linux package manager.
+
+*DISTTYPE_HAIKU*::
+Used for systems which use haiku packages.
+
+*POOL_FLAG_PROMOTEEPOCH*::
+Promote the epoch of the providing dependency to the requesting
+dependency if it does not contain an epoch. Used at some time
+in old rpm versions, modern systems should never need this.
+
+*POOL_FLAG_FORBIDSELFCONFLICTS*::
+Disallow the installation of packages that conflict with themselves.
+Debian always allows self-conflicting packages, rpm used to forbid
+them but switched to also allowing them recently.
+
+*POOL_FLAG_OBSOLETEUSESPROVIDES*::
+Make obsolete type dependency match against provides instead of
+just the name and version of packages. Very old versions of rpm
+used the name/version, then it got switched to provides and later
+switched back again to just name/version.
+
+*POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES*::
+An implicit obsoletes is the internal mechanism to remove the
+old package on an update. The default is to remove all packages
+with the same name, rpm-5 switched to also removing packages
+providing the same name.
+
+*POOL_FLAG_OBSOLETEUSESCOLORS*::
+Rpm's multilib implementation (used in RedHat and Fedora)
+distinguishes between 32bit and 64bit packages (the terminology
+is that they have a different color). If obsoleteusescolors is
+set, packages with different colors will not obsolete each other.
+
+*POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*::
+Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if
+packages of the same name can be installed in parallel. For
+current Fedora systems, POOL_FLAG_OBSOLETEUSESCOLORS should be
+false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true
+(this is the default if FEDORA is defined when libsolv is
+compiled).
+
+*POOL_FLAG_NOINSTALLEDOBSOLETES*::
+New versions of rpm consider the obsoletes of installed packages
+when checking for dependency, thus you may not install a package
+that is obsoleted by some other installed package, unless you
+also erase the other package.
+
+*POOL_FLAG_HAVEDISTEPOCH*::
+Mandriva added a new field called distepoch that gets checked in
+version comparison if the epoch/version/release of two packages
+are the same.
+
+*POOL_FLAG_NOOBSOLETESMULTIVERSION*::
+If a package is installed in multiversionmode, rpm used to ignore
+both the implicit obsoletes and the obsolete dependency of a
+package. This was changed to ignoring just the implicit obsoletes,
+thus you may install multiple versions of the same name, but
+obsoleted packages still get removed.
+
+*POOL_FLAG_ADDFILEPROVIDESFILTERED*::
+Make the addfileprovides method only add files from the standard
+locations (i.e. the ``bin'' and ``etc'' directories). This is
+useful if you have only few packages that use non-standard file
+dependencies, but you still want the fast speed that addfileprovides()
+generates.
+
+
+=== Functions ===
+       int pool_setdisttype(Pool *pool, int disttype);
+
+Set the package type of your system. The disttype is used for example
+to define package comparison semantics. Libsolv's default disttype
+should match the package manager of your system, so you only need to
+use this function if you want to use the library to solve packaging
+problems for different systems. The Function returns the old
+disttype on success, and -1 if the new disttype is not supported.
+Note that any pool_setarch and pool_setarchpolicy calls need to
+come after the pool_setdisttype call, as they make use of the
+noarch/any/all architecture id.
+
+       int pool_set_flag(Pool *pool, int flag, int value);
+
+Set a flag to a new value. Returns the old value of the flag.
+
+       int pool_get_flag(Pool *pool, int flag);
+
+Get the value of a pool flag. See the constants section about the meaning
+of the flags.
+
+       void pool_set_rootdir(Pool *pool, const char *rootdir);
+
+Set a specific root directory. Some library functions support a flag that
+tells the function to prepend the rootdir to file and directory names.
+
+       const char *pool_get_rootdir(Pool *pool);
+
+Return the current value of the root directory.
+
+       char *pool_prepend_rootdir(Pool *pool, const char *dir);
+
+Prepend the root directory to the _dir_ argument string. The returned
+string has been newly allocated and needs to be freed after use.
+
+       char *pool_prepend_rootdir_tmp(Pool *pool, const char *dir);
+
+Same as pool_prepend_rootdir, but uses the pool's temporary space for
+allocation.
+
+       void pool_set_installed(Pool *pool, Repo *repo);
+
+Set which repository should be treated as the ``installed'' repository,
+i.e. the one that holds information about the installed packages.
+
+       void pool_set_languages(Pool *pool, const char **languages, int nlanguages);
+
+Set the language of your system. The library provides lookup functions that
+return localized strings, for example for package descriptions. You can
+set an array of languages to provide a fallback mechanism if one language
+is not available.
+
+       void pool_setarch(Pool *pool, const char *arch);
+
+Set the architecture of your system. The architecture is used to determine
+which packages are installable and which packages cannot be installed.
+The _arch_ argument is normally the ``machine'' value of the ``uname''
+system call.
+
+       void pool_setarchpolicy(Pool *, const char *);
+
+Set the architecture policy for your system. This is the general version
+of pool_setarch (in fact pool_setarch calls pool_setarchpolicy internally).
+See the section about architecture policies for more information.
+
+       void pool_addvendorclass(Pool *pool, const char **vendorclass);
+
+Add a new vendor equivalence class to the system. A vendor equivalence class
+defines if an installed package of one vendor can be replaced by a package
+coming from a different vendor. The _vendorclass_ argument must be a
+NULL terminated array of strings. See the section about vendor policies for
+more information.
+
+       void pool_setvendorclasses(Pool *pool, const char **vendorclasses);
+
+Set all allowed vendor equivalences. The vendorclasses argument must be an
+NULL terminated array consisting of all allowed classes concatenated.
+Each class itself must be NULL terminated, thus the last class ends with
+two NULL elements, one to finish the class and one to finish the list
+of classes.
+
+       void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *));
+
+Define a custom vendor check mechanism. You can use this if libsolv's
+internal vendor equivalence class mechanism does not match your needs.
+
+       void pool_setloadcallback(Pool *pool, int (*cb)(Pool *, Repodata *, void *), void *loadcbdata);
+
+Define a callback function that gets called when repository metadata needs
+to be loaded on demand. See the section about on demand loading in the
+libsolv-repodata manual.
+
+       void pool_setnamespacecallback(Pool *pool, Id (*cb)(Pool *, void *, Id, Id), void *nscbdata);
+
+Define a callback function to implement custom namespace support. See the
+section about namespace dependencies.
+
+
+Id pool management
+------------------
+=== Constants ===
+
+*ID_EMPTY*::
+The Id of the empty string, it is always Id 1.
+
+*REL_LT*::
+Represents a ``<'' relation.
+
+*REL_EQ*::
+Represents a ``='' relation.
+
+*REL_GT*::
+Represents a ``>'' relation. You can use combinations of REL_GT, REL_EQ,
+and REL_LT or-ed together to create any relation you like.
+
+*REL_AND*::
+A boolean AND operation, the ``name'' and ``evr'' parts of the relation can
+be two sub-dependencies. Packages must match both parts of the dependency.
+
+*REL_OR*::
+A boolean OR operation, the ``name'' and ``evr'' parts of the relation can
+be two sub-dependencies. Packages can match any part of the dependency.
+
+*REL_WITH*::
+Like REL_AND, but packages must match both dependencies simultaneously. See
+the section about boolean dependencies about more information.
+
+*REL_NAMESPACE*::
+A special namespace relation. See the section about namespace dependencies
+for more information.
+
+*REL_ARCH*::
+An architecture filter dependency. The ``name'' part of the relation is a
+sub-dependency, the ``evr'' part is the Id of an architecture that the
+matching packages must have (note that this is an exact match ignoring
+architecture policies).
+
+*REL_FILECONFLICT*::
+An internal file conflict dependency used to represent file conflicts. See
+the pool_add_fileconflicts_deps() function.
+
+*REL_COND*::
+A conditional dependency, the ``name'' sub-dependency is only considered if
+the ``evr'' sub-dependency is fulfilled. See the section about boolean
+dependencies about more information.
+
+*REL_UNLESS*::
+A conditional dependency, the ``name'' sub-dependency is only considered if
+the ``evr'' sub-dependency is not fulfilled. See the section about boolean
+dependencies about more information.
+
+*REL_COMPAT*::
+A compat dependency used in Haiku to represent version ranges.  The
+``name'' part is the actual version, the ``evr'' part is the backwards
+compatibility version.
+
+*REL_KIND*::
+A pseudo dependency that limits the solvables to a specific kind.
+The kind is expected to be a prefix of the solvable name, e.g.
+``patch:foo'' would be of kind ``patch''. ``REL_KIND'' is only
+supported in the selection functions.
+
+*REL_MULTIARCH*::
+A debian multiarch annotation. The most common value for the ``evr''
+part is ``any''.
+
+*REL_ELSE*::
+The else part of a ``REL_COND'' or ``REL_UNLESS'' dependency. See the
+section about boolean dependencies.
+
+*REL_ERROR*::
+An illegal dependency. This is useful to encode dependency parse errors.
+
+=== Functions ===
+       Id pool_str2id(Pool *pool, const char *str, int create);
+
+Add a string to the pool of unified strings, returning the Id of the string.
+If _create_ is zero, new strings will not be added to the pool, instead
+Id 0 is returned.
+
+       Id pool_strn2id(Pool *pool, const char *str, unsigned int len, int create);
+
+Same as pool_str2id, but only _len_ characters of the string are used. This
+can be used to add substrings to the pool.
+
+       Id pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create);
+
+Create a relational dependency from to other dependencies, _name_ and _evr_,
+and a _flag_. See the *REL_* constants for the supported flags. As with
+pool_str2id, _create_ defines if new dependencies will get added or Id zero
+will be returned instead.
+
+       Id pool_id2langid(Pool *pool, Id id, const char *lang, int create);
+
+Attach a language suffix to a string Id. This function can be used to
+create language keyname Ids from keynames, it is functional equivalent
+to converting the _id_ argument to a string, adding a ``:'' character
+and the _lang_ argument to the string and then converting the result back
+into an Id.
+
+       const char *pool_id2str(const Pool *pool, Id id);
+
+Convert an Id back into a string. If the Id is a relational Id, the
+``name'' part will be converted instead.
+
+       const char *pool_id2rel(const Pool *pool, Id id);
+
+Return the relation string of a relational Id. Returns an empty string if
+the passed Id is not a relation.
+
+       const char *pool_id2evr(const Pool *pool, Id id);
+
+Return the ``evr'' part of a relational Id as string. Returns an empty
+string if the passed Id is not a relation.
+
+       const char *pool_dep2str(Pool *pool, Id id);
+
+Convert an Id back into a string. If the passed Id belongs to a relation,
+a string representing the relation is returned. Note that in that case
+the string is allocated on the pool's temporary space.
+
+       void pool_freeidhashes(Pool *pool);
+
+Free the hashes used to unify strings and relations. You can use this
+function to save memory if you know that you will no longer create new
+strings and relations.
+
+
+Solvable functions
+------------------
+
+       Solvable *pool_id2solvable(const Pool *pool, Id p);
+
+Convert a solvable Id into a pointer to the solvable data. Note that the
+pointer may become invalid if new solvables are created or old solvables
+deleted, because the array storing all solvables may get reallocated.
+
+       Id pool_solvable2id(const Pool *pool, Solvable *s);
+
+Convert a pointer to the solvable data into a solvable Id.
+
+       const char *pool_solvid2str(Pool *pool, Id p);
+
+Return a string representing the solvable with the Id _p_. The string will
+be some canonical representation of the solvable, usually a combination of
+the name, the version, and the architecture.
+
+       const char *pool_solvable2str(Pool *pool, Solvable *s);
+
+Same as pool_solvid2str, but instead of the Id, a pointer to the solvable
+is passed.
+
+
+Dependency matching
+-------------------
+
+=== Constants ===
+*EVRCMP_COMPARE*::
+Compare all parts of the version, treat missing parts as empty strings.
+
+*EVRCMP_MATCH_RELEASE*::
+A special mode for rpm version string matching. If a version misses a
+release part, it matches all releases. In that case the special values
+``-2'' and ``2'' are returned, depending on which of the two versions
+did not have a release part.
+
+*EVRCMP_MATCH*::
+A generic match, missing parts always match.
+
+*EVRCMP_COMPARE_EVONLY*::
+Only compare the epoch and the version parts, ignore the release part.
+
+=== Functions ===
+       int pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode);
+
+Compare two version Ids, return -1 if the first version is less than the
+second version, 0 if they are identical, and 1 if the first version is
+bigger than the second one.
+
+       int pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
+
+Same as pool_evrcmp(), but uses strings instead of Ids.
+
+       int pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release);
+
+Match a version Id against an epoch, a version and a release string. Passing
+NULL means that the part should match everything.
+
+       int pool_match_dep(Pool *pool, Id d1, Id d2);
+
+Returns ``1'' if the dependency _d1_ (the provider) is matched by the
+dependency _d2_, otherwise ``0'' is returned. For two dependencies to
+match, both the ``name'' parts must match and the version range described
+by the ``evr'' parts must overlap.
+
+       int pool_match_nevr(Pool *pool, Solvable *s, Id d);
+
+Like pool_match_dep, but the provider is the "self-provides" dependency
+of the Solvable _s_, i.e. the dependency ``s->name = s->evr''.
+
+
+Whatprovides Index
+------------------
+       void pool_createwhatprovides(Pool *pool);
+
+Create an index that maps dependency Ids to sets of packages that provide the
+dependency.
+
+       void pool_freewhatprovides(Pool *pool);
+
+Free the whatprovides index to save memory.
+
+       Id pool_whatprovides(Pool *pool, Id d);
+
+Return an offset into the Pool's whatprovidesdata array. The solvables with
+the Ids stored starting at that offset provide the dependency _d_. The
+solvable list is zero terminated.
+
+       Id *pool_whatprovides_ptr(Pool *pool, Id d);
+
+Instead of returning the offset, return the pointer to the Ids stored at
+that offset. Note that this pointer has a very limit validity time, as any
+call that adds new values to the whatprovidesdata area may reallocate the
+array.
+
+       Id pool_queuetowhatprovides(Pool *pool, Queue *q);
+
+Add the contents of the Queue _q_ to the end of the whatprovidesdata array,
+returning the offset into the array.
+
+       void pool_addfileprovides(Pool *pool);
+
+Some package managers like rpm allow dependencies on files contained in
+other packages. To allow libsolv to deal with those dependencies in an
+efficient way, you need to call the addfileprovides method after creating
+and reading all repositories. This method will scan all dependency for file
+names and then scan all packages for matching files. If a filename has been
+matched, it will be added to the provides list of the corresponding
+package.
+
+       void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst);
+
+Same as pool_addfileprovides, but the added Ids are returned in two Queues,
+_idq_ for all repositories except the one containing the ``installed''
+packages, _idqinst_ for the latter one. This information can be stored in
+the meta section of the repositories to speed up the next time the
+repository is loaded and addfileprovides is called
+
+       void pool_set_whatprovides(pool, Id id, Id offset);
+
+Manually set an entry in the whatprovides index. You'll never do this for
+package dependencies, as those entries are created by calling the
+pool_createwhatprovides() function. But this function is useful for
+namespace provides if you do not want to use a namespace callback to
+lazily set the provides. The offset argument is a offset in the
+whatprovides array, thus you can use ``1'' as a false value and ``2''
+as true value.
+
+       void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
+
+Clear the cache of the providers for namespace dependencies matching
+namespace _ns_. If the _evr_ argument is non-zero, the namespace dependency
+for exactly that dependency is cleared, otherwise all matching namespace
+dependencies are cleared. See the section about Namespace dependencies
+for further information.
+
+       void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts);
+
+Some package managers like rpm report conflicts when a package installation
+overwrites a file of another installed package with different content. As
+file content information is not stored in the repository metadata, those
+conflicts can only be detected after the packages are downloaded. Libsolv
+provides a function to check for such conflicts, pool_findfileconflicts().
+If conflicts are found, they can be added as special *REL_FILECONFLICT*
+provides dependencies, so that the solver will know about the conflict when
+it is re-run.
+
+
+Utility functions
+-----------------
+       char *pool_alloctmpspace(Pool *pool, int len);
+
+Allocate space on the pool's temporary space area. This space has a limited
+lifetime, it will be automatically freed after a fixed amount (currently
+16) of other pool_alloctmpspace() calls are done.
+
+       void pool_freetmpspace(Pool *pool, const char *space);
+
+Give the space allocated with pool_alloctmpspace back to the system. You
+do not have to use this function, as the space is automatically reclaimed,
+but it can be useful to extend the lifetime of other pointers to the pool's
+temporary space area.
+
+       const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
+
+Convert some binary data to hexadecimal, returning a string allocated in
+the pool's temporary space area.
+
+       char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3);
+
+Join three strings and return the result in the pool's temporary space
+area. You can use NULL arguments if you just want to join less strings.
+
+       char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
+
+Like pool_tmpjoin(), but if the first argument is the last allocated space
+in the pool's temporary space area, it will be replaced with the result of
+the join and no new temporary space slot will be used.  Thus you can join
+more than three strings by a combination of one pool_tmpjoin() and multiple
+pool_tmpappend() calls. Note that the _str1_ pointer is no longer usable
+after the call.
+
+
+Data lookup
+-----------
+=== Constants ===
+
+*SOLVID_POS*::
+Use the data position stored in the pool for the lookup instead of looking
+up the data of a solvable.
+
+*SOLVID_META*::
+Use the data stored in the meta section of a repository (or repodata
+area) instead of looking up the data of a solvable. This constant does
+not work for the pool's lookup functions, use it for the repo's or
+repodata's lookup functions instead. It's just listed for completeness.
+
+=== Functions ===
+       const char *pool_lookup_str(Pool *pool, Id solvid, Id keyname);
+
+Return the  string value stored under the attribute _keyname_ in solvable
+_solvid_.
+
+       unsigned long long pool_lookup_num(Pool *pool, Id solvid, Id keyname, unsigned long long notfound);
+
+Return the 64bit unsigned number stored under the attribute _keyname_ in
+solvable _solvid_. If no such number is found, the value of the _notfound_
+argument is returned instead.
+
+       Id pool_lookup_id(Pool *pool, Id solvid, Id keyname);
+
+Return the Id stored under the attribute _keyname_ in solvable _solvid_.
+
+       int pool_lookup_idarray(Pool *pool, Id solvid, Id keyname, Queue *q);
+
+Fill the queue _q_ with the content of the Id array stored under the
+attribute _keyname_ in solvable _solvid_. Returns ``1'' if an array was
+found, otherwise the queue will be empty and ``0'' will be returned.
+
+       int pool_lookup_void(Pool *pool, Id solvid, Id keyname);
+
+Returns ``1'' if a void value is stored under the attribute _keyname_ in
+solvable _solvid_, otherwise ``0''.
+
+       const char *pool_lookup_checksum(Pool *pool, Id solvid, Id keyname, Id *typep);
+
+Return the checksum that is stored under the attribute _keyname_ in
+solvable _solvid_.  The type of the checksum will be returned over the
+_typep_ pointer. If no such checksum is found, NULL will be returned and
+the type will be set to zero. Note that the result is stored in the Pool's
+temporary space area.
+
+       const unsigned char *pool_lookup_bin_checksum(Pool *pool, Id solvid, Id keyname, Id *typep);
+
+Return the checksum that is stored under the attribute _keyname_ in
+solvable _solvid_.  Returns the checksum as binary data, you can use the
+returned type to calculate the length of the checksum. No temporary space
+area is needed.
+
+       const char *pool_lookup_deltalocation(Pool *pool, Id solvid, unsigned int *medianrp);
+
+This is a utility lookup function to return the delta location for a delta
+rpm.  As solvables cannot store deltas, you have to use SOLVID_POS as
+argument and set the Pool's datapos pointer to point to valid delta rpm
+data.
+
+       void pool_search(Pool *pool, Id solvid, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata);
+
+Perform a search on all data stored in the pool. You can limit the search
+area by using the _solvid_ and _keyname_ arguments. The values can be
+optionally matched against the _match_ argument, use NULL if you do not
+want this matching. See the Dataiterator manpage about the possible matches
+modes and the _flags_ argument. For all (matching) values, the callback
+function is called with the _cbdata_ callback argument and the data
+describing the value.
+
+
+Job and Selection functions
+---------------------------
+A Job consists of two Ids, _how_ and _what_. The _how_ part describes the
+action, the job flags, and the selection method while the _what_ part is
+in input for the selection. A Selection is a queue consisting of multiple
+jobs (thus the number of elements in the queue must be a multiple of two).
+See the Solver manpage for more information about jobs.
+
+       const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
+
+Convert a job into a string. Useful for debugging purposes. The _flagmask_
+can be used to mask the flags of the job, use ``0'' if you do not want to
+see such flags, ``-1'' to see all flags, or a combination of the flags
+you want to see.
+
+       void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
+
+Return a list of solvables that the specified job selects.
+
+       int pool_isemptyupdatejob(Pool *pool, Id how, Id what);
+
+Return ``1'' if the job is an update job that does not work with any
+installed package, i.e. the job is basically a no-op. You can use this
+to turn no-op update jobs into install jobs (as done by package managers
+like ``zypper'').
+
+       const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
+
+Convert a selection into a string. Useful for debugging purposes. See the
+pool_job2str() function for the _flagmask_ argument.
+
+
+Odds and Ends
+-------------
+       void pool_freeallrepos(Pool *pool, int reuseids);
+
+Free all repos from the pool (including all solvables). If _reuseids_ is
+true, all Ids of the solvables are free to be reused the next time
+solvables are created.
+
+       void pool_clear_pos(Pool *pool);
+       
+Clear the data position stored in the pool.
+
+
+Architecture Policies
+---------------------
+An architecture policy defines a list of architectures that can be
+installed on the system, and also the relationship between them (i.e. the
+ordering). Architectures can be delimited with three different characters:
+
+*\':'*::
+No relationship between the architectures. A package of one architecture
+can not be replaced with one of the other architecture.
+
+*\'>'*::
+The first architecture is better than the second one. An installed package
+of the second architecture may be replaced with one from the first
+architecture and vice versa. The solver will select the better architecture
+if the versions are the same.
+
+*\'='*::
+The two architectures are freely exchangeable. Used to define aliases
+for architectures.
+
+An example would be \'+x86_64:i686=athlon>i586+'. This means that x86_64
+packages can only be replaced by other x86_64 packages, i686 packages
+can be replaced by i686 and i586 packages (but i686 packages will be
+preferred) and athlon is another name for the i686 architecture.
+
+You can turn off the architecture replacement checks with the Solver's
+SOLVER_FLAG_ALLOW_ARCHCHANGE flag.
+
+Vendor Policies
+---------------
+Different vendors often compile packages with different features, so
+Libsolv only replace installed packages of one vendor with packages coming
+from the same vendor. Also, while the version of a package is normally
+defined by the upstream project, the release part of the version is
+set by the vendor's package maintainer, so it's not meaningful to
+do version comparisons for packages coming from different vendors.
+
+Vendor in this case means the SOLVABLE_VENDOR string stored in each
+solvable. Sometimes a vendor changes names, or multiple vendors form a
+group that coordinate their package building, so libsolv offers a way
+to define that a group of vendors are compatible. You do that be
+defining vendor equivalence classes, packages from a vendor from
+one class may be replaced with packages from all the other vendors
+in the class.
+
+There can be multiple equivalence classes, the set of allowed vendor
+changes for an installed package is calculated by building the union
+of all of the equivalence classes the vendor of the installed package
+is part of.
+
+You can turn off the architecture replacement checks with the Solver's
+SOLVER_FLAG_ALLOW_VENDORCHANGE flag.
+
+
+Boolean Dependencies
+--------------------
+Boolean Dependencies allow to build complex expressions from simple
+dependencies. Note that depending on the package manager only a subset
+of those may be useful. For example, debian currently only allows
+an "OR" expression.
+
+*REL_OR*::
+The expression is true if either the first dependency or the second
+one is true. This is useful for package dependencies like ``Requires'',
+where you can specify that either one of the packages need to be
+installed.
+
+*REL_AND*::
+The expression is true if both dependencies are true. The packages
+fulfilling the dependencies may be different, i.e. 
+``Supplements: perl REL_AND python'' is true if both a package providing
+perl and a package providing python are installed.
+
+*REL_WITH*::
+The expression is true if both dependencies are true and are fulfilled by
+the same package. Thus ``Supplements: perl REL_WITH python'' would only be true
+if a package is installed that provides both dependencies (some kind
+of multi-language interpreter).
+
+*REL_COND*::
+The expression is true if the first dependency is true or the second
+dependency is false. ``A REL_COND B'' is equivalent to
+``A REL_OR (NOT B)'' (except that libsolv does not expose ``NOT'').
+
+*REL_UNLESS*::
+The expression is true if the first dependency is true and the second
+dependency is false. ``A REL_UNLESS B'' is equivalent to
+``A REL_AND (NOT B)'' (except that libsolv does not expose ``NOT'').
+
+*REL_ELSE*::
+The ``else'' part of a ``REL_COND'' or ``REL_UNLESS''  dependency.
+It has to be directly in the evr part of the condition,
+e.g. ``foo REL_COND (bar REL_ELSE baz)''.
+For ``REL_COND'' this is equivalent to writing
+``(foo REL_COND bar) REL_AND (bar REL_OR baz)''.
+For ``REL_UNLESS'' this is equivalent to writing
+``(foo REL_UNLESS bar) REL_OR (bar REL_AND baz)''.
+
+Each sub-dependency of a boolean dependency can in turn be a boolean
+dependency, so you can chain them to create complex dependencies.
+
+
+Namespace Dependencies
+----------------------
+Namespace dependencies can be used to implement dependencies on
+attributes external to libsolv. An example would be a dependency
+on the language set by the user. This types of dependencies are
+usually only used for ``Conflicts'' or ``Supplements'' dependencies,
+as the underlying package manager does not know how to deal with
+them.
+
+If the library needs to evaluate a namespace dependency, it calls
+the namespace callback function set in the pool. The callback
+function can return a set of packages that ``provide'' the
+dependency. If the dependency is provided by the system, the
+returned set should consist of just the system solvable (Solvable
+Id 1).
+
+The returned set of packages must be returned as offset into
+the whatprovidesdata array. You can use the pool_queuetowhatprovides
+function to convert a queue into such an offset. To ease programming
+the callback function, the return values ``0'' and ``1'' are not
+interpreted as an offset. ``0'' means that no package is in the
+return set, ``1'' means that just the system solvable is in the set.
+
+The returned set is cached, so that for each namespace dependency
+the callback is just called once. If you need to flush the cache (maybe
+because the user has selected a different language), use the
+pool_flush_namespaceproviders() function.
+
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/libsolv.txt b/libsolv-0.7.2/doc/libsolv.txt
new file mode 100644 (file)
index 0000000..f101808
--- /dev/null
@@ -0,0 +1,61 @@
+Libsolv(3)
+==========
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+libsolv - package dependency solver library using a satisfiability algorithm
+
+
+Documentation
+-------------
+The libsolv documentation is split into multiple parts:
+
+*libsolv-history*::
+  how the libsolv library came into existence
+
+*libsolv-constantids*::
+  fixed Ids for often used strings
+
+*libsolv-bindings*::
+  access libsolv from perl/python/ruby
+
+*libsolv-pool*::
+  libsolv's pool object
+
+Pointer Validity
+----------------
+Note that all pointers to objects that have an Id have only a limited
+validity period, with the exception of Repo pointers. There are only
+guaranteed to be valid until a new object of that type is added or an
+object of that type is removed. Thus pointers to Solvable objects are only 
+valid until another solvable is created, because adding a Solvable may
+relocate the Pool's Solvable array. This is also true for Pool strings,
+you should use solv_strdup() to create a copy of the string if you
+want to use it at some later time. You should use the Ids in the code
+and not the pointers, except for short times where you know that the
+pointer is safe.
+
+Note also that the data lookup functions or the dataiterator also
+return values with limited lifetime, this is especially true for data
+stored in the paged data segment of solv files. This is normally
+data that consists of big strings like package descriptions or is not
+often needed like package checksums. Thus looking up a description of
+a solvable and then looking up the description of a different solvable
+or even the checksum of the same solvable may invalidate the first
+result. (The dataiterator supports a dataiterator_strdup() function
+to create a safe copy.)
+
+The language bindings already deal with pointer validity, so you do
+not have to worry about this issue when using the bindings.
+
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/mdk2solv.txt b/libsolv-0.7.2/doc/mdk2solv.txt
new file mode 100644 (file)
index 0000000..eb2ac14
--- /dev/null
@@ -0,0 +1,37 @@
+mdk2solv(1)
+===========
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+mdk2solv - convert files in Mandriva synthesis format into a solv file
+
+Synopsis
+--------
+*mdk2solv* ['OPTIONS']
+
+Description
+-----------
+The mdk2solv tool reads Mandriva synthesis data (*hdlist*) from stdin, and writes
+it as solv file to standard output.
+
+*-i* 'INFO.xml'::
+Also read the info file containing url, license, and src information from
+the specified xml file.
+
+*-f* 'FILES.xml'::
+Also read filelist information from the specified xml file.
+
+See Also
+--------
+genhdlist2(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/mergesolv.txt b/libsolv-0.7.2/doc/mergesolv.txt
new file mode 100644 (file)
index 0000000..8ae67d1
--- /dev/null
@@ -0,0 +1,29 @@
+mergesolv(1)
+============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+mergesolv - merge multiple files in solv format into a single one
+
+Synopsis
+--------
+*mergesolv* ['OPTIONS'] 'FILE1.solv' 'FILE2.solv' ...
+
+Description
+-----------
+The mergesolv tool reads all solv files specified on the command line,
+and writes a merged version to standard output.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/repo2solv.txt b/libsolv-0.7.2/doc/repo2solv.txt
new file mode 100644 (file)
index 0000000..3b2145f
--- /dev/null
@@ -0,0 +1,60 @@
+repo2solv(1)
+============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+repo2solv - convert repository metadata into a solv file
+
+Synopsis
+--------
+*repo2solv* ['OPTIONS'] 'DIR'
+
+Description
+-----------
+The repo2solv tool converts repository metadata in the directory
+'DIR' into a solv file written to standard output.
+
+Note that repo2solv does not verify signatures or checksum, it
+is expected that this is done by the tool that downloads the
+metadata.
+
+If no metadata is detected, repo2solv assumes the "plaindir"
+format and generates the solv file from all rpm files it
+finds.
+
+*-o* 'OUTFILE'::
+Write the solv file to 'OUTFILE' instead of stdout.
+
+*-R*::
+Also recurse into subdirectories in "plaindir" mode.
+
+*-F*::
+Put the complete filelist in the output. The default is
+to just include the "importent" parts of the file list,
+except for "plaindir" mode, which always includes all
+files.
+
+*-C*::
+Add changelog entires to the output.
+
+*-A*::
+Add appdata pseudo packages to the output. This is an
+experimental feature.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+See Also
+--------
+dumpsolv(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/repomdxml2solv.txt b/libsolv-0.7.2/doc/repomdxml2solv.txt
new file mode 100644 (file)
index 0000000..3b77820
--- /dev/null
@@ -0,0 +1,40 @@
+repomdxml2solv(1)
+=================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+repomdxml2solv - convert a repomd.xml file into a solv file
+
+Synopsis
+--------
+*repomdxml2solv* ['OPTIONS']
+
+Description
+-----------
+The repomd.xml file is the index file of a rpm-md repository,
+containing references to all data file with checksums. The
+repomdxml2solv tool reads the repomd.xml file from stdin and
+writes the parsed data as solv file to standard output. The
+data is stored as meta attributes in the result.
+
+*-q* 'WHAT'::
+Data query mode: instead of writing a solv file, select the
+'WHAT' element in the input data and write it to standard output.
+Examples for 'WHAT' are *type* to get a list of all types, and
+*primary:location* to get the location of the element with
+type *primary*.
+
+See Also
+--------
+rpmmd2solv(1), mergesolv(1), createrepo(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/rpmdb2solv.txt b/libsolv-0.7.2/doc/rpmdb2solv.txt
new file mode 100644 (file)
index 0000000..ad8314f
--- /dev/null
@@ -0,0 +1,63 @@
+rpmdb2solv(1)
+=============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+rpmdb2solv - convert the rpm database into a solv file
+
+Synopsis
+--------
+*rpmdb2solv* ['OPTIONS'] ['REFFILE.solv']
+
+Description
+-----------
+The rpmdb2solv tool reads rpm's installed packages database
+and writes it in solv file format to standard output. You can
+make use of an old version of the database by specifying a
+'REFFILE.solv' file.
+
+*-o* 'OUTFILE'::
+Write the generated solv to 'OUTFILE' instead of standard output.
+
+*-P*::
+Print percentages as packages are being read in. The output
+format is like rpm's --percent option.
+
+*-r* 'ROOTDIR'::
+Use 'ROOTDIR' as root directory.
+
+*-k*::
+Read pubkeys from the rpm database instead of installed packages.
+Note that many distributions stopped storing pubkeys in the
+database but use a directory like */var/lib/rpm/pubkeys*
+instead.
+
+*-A*::
+Also scan the */usr/share/appdata* for installed appdata files
+and create pseudo packages for each file.
+
+*-p* 'PRODDIR'::
+Also read SUSE product files from directory 'PRODDIR'. The
+standard directory is */etc/products.d*.
+
+*-n*::
+Do not read any packages from the rpm database. This is useful
+together with *-p* to only convert SUSE products.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+See Also
+--------
+rpms2solv(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/rpmmd2solv.txt b/libsolv-0.7.2/doc/rpmmd2solv.txt
new file mode 100644 (file)
index 0000000..f103f06
--- /dev/null
@@ -0,0 +1,34 @@
+rpmmd2solv(1)
+=============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+rpmmd2solv - convert files in rpm-md format into a solv file
+
+Synopsis
+--------
+*rpmmd2solv* ['OPTIONS']
+
+Description
+-----------
+The rpmmd2solv tool reads rpm-md xml data from stdin, and writes
+it as solv file to standard output. It understands the *primary*,
+*filelist*, *other*, and *susedata* format.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+See Also
+--------
+repomdxml2solv(1), mergesolv(1), createrepo(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/rpms2solv.txt b/libsolv-0.7.2/doc/rpms2solv.txt
new file mode 100644 (file)
index 0000000..11bdcf0
--- /dev/null
@@ -0,0 +1,52 @@
+rpms2solv(1)
+============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+rpms2solv - convert one or more rpms into a solv file
+
+Synopsis
+--------
+*rpms2solv* ['OPTIONS'] 'RPM1.rpm' ...
+
+Description
+-----------
+The rpms2solv tool converts the header data from one or more
+rpms into the solv file written to standard output.
+
+*-m* 'MANIFESTFILE'::
+Read the rpm file names from the specified 'MANIFESTFILE'. You can
+use *-* to read the manifest from standard input.
+
+*-0*::
+Use a null byte as line terminator for manifest files instead of
+a newline. This is useful if the file names can contain newlines.
+See also the *-print0* option in *find*.
+
+*-F*::
+Do not put all files from the headers into the file list, but
+instead use the filtering also found in *createrepo*.
+
+*-k*::
+Read pubkeys instead of rpms.
+
+*-K*::
+Read pubkey keyrings instead of rpms.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+See Also
+--------
+rpmdb2solv(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/solv.txt b/libsolv-0.7.2/doc/solv.txt
new file mode 100644 (file)
index 0000000..936ae78
--- /dev/null
@@ -0,0 +1,73 @@
+solv(1)
+=======
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+solv - example package manager based on libsolv
+
+Synopsis
+--------
+*solv* install [OPTIONS] PKG...
+
+*solv* erase [OPTIONS] PKG...
+
+*solv* list [OPTIONS] PKG...
+
+*solv* info [OPTIONS] PKG...
+
+*solv* search [OPTIONS] STRING...
+
+*solv* verify [OPTIONS] PKG...
+
+*solv* update [OPTIONS] PKG...
+
+*solv* dist-upgrade [OPTIONS] PKG...
+
+*solv* repolist [OPTIONS]
+
+Description
+-----------
+The solv tool demos some features of the libsolv library. It is not
+meant to replace a real package manager, for example it does not cache
+downloaded packages.
+
+*--root* 'ROOTDIR'::
+Install packages using 'ROOTDIR' as root of the filesystem. This also
+means that the package database of 'ROOTDIR' will be used.
+
+*--clean*::
+Also get rid of no longer needed packages when erasing, like libraries
+that have been used by the erased packages.
+
+*--best*::
+Force usage of the best package (normally the one with the highest
+version) for install and update operations.
+
+*--testcase*::
+Write a testcase after dependency solving.
+
+The following options can be used to filter the packages. If the
+same option is used multiple times, the result is ORed together.
+
+*-i*::
+Limit the packages to installed ones.
+
+*-r* 'REPO'::
+Limit the packages to the specified repository.
+
+*--arch* 'ARCHITECTURE'::
+Limit the packages to the specified package architecture.
+
+*--type* 'TYPE'::
+Limit the packages to the specified package type.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/susetags2solv.txt b/libsolv-0.7.2/doc/susetags2solv.txt
new file mode 100644 (file)
index 0000000..0d61c4d
--- /dev/null
@@ -0,0 +1,43 @@
+susetags2solv(1)
+================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+susetags2solv - convert the susetags repository format into a solv file
+
+Synopsis
+--------
+*susetags2solv* ['OPTIONS']
+
+Description
+-----------
+The susetags format is most as repository format on most products
+created by SUSE. The susetags2solv reads data from standard input,
+converts the format into a solv file, and writes it to standard output.
+
+*-c* 'CONTENTFILE'::
+Also parse the specified content file containing meta information
+about the repository.
+
+*-q* 'WHAT'::
+Data query mode: instead of writing a solv file, select the
+'WHAT' element in the input data and write it to standard output.
+An example for 'WHAT' is *defaultvendor* to get a default vendor for
+the repository.
+
+*-M* 'MERGEFILE.solv'::
+Merge the content of the specified solv file into the output.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/testsolv.txt b/libsolv-0.7.2/doc/testsolv.txt
new file mode 100644 (file)
index 0000000..eb52d95
--- /dev/null
@@ -0,0 +1,45 @@
+testsolv(1)
+===========
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+testsolv - run a libsolv testcase through the solver
+
+Synopsis
+--------
+*testsolv* ['OPTIONS'] 'TESTCASE'
+
+Description
+-----------
+The testsolv tools can be used to run a testcase. Testcases can
+either be manually created to test specific features, or they
+can be written by libsolv's testcase_write function. This is useful
+to evaluate bug reports about the solver.
+
+*-v*::
+Increase the debug level of the solver. This option can be specified
+multiple times to further increase the amount of debug data.
+
+*-r*::
+Write the output in testcase format instead of human readable text.
+The output can then be used in the result section of the test case.
+If the *-r* option is given twice, the output is formated for
+verbatim inclusion.
+
+*-l* 'PKGSPEC'::
+Instead of running the solver, list packages in the repositories.
+
+*-s* 'SOLUTIONSPEC'::
+This is used in the solver test suite to test the calculated solutions
+to encountered problems.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/doc/updateinfoxml2solv.txt b/libsolv-0.7.2/doc/updateinfoxml2solv.txt
new file mode 100644 (file)
index 0000000..6ebdeb4
--- /dev/null
@@ -0,0 +1,31 @@
+updateinfoxml2solv(1)
+=====================
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+updateinfoxml2solv - convert rpm-md's updateinfo.xml format into a solv file
+
+Synopsis
+--------
+*updateinfoxml2solv* ['OPTIONS']
+
+Description
+-----------
+The updateinfoxml2solv tool reads rpm-md's updateinfo xml data from stdin,
+and writes it as solv file to standard output. Update elements are converted
+into special *patch:* pseudo packages.
+
+See Also
+--------
+mergesolv(1), createrepo(8)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/libsolv-0.7.2/examples/CMakeLists.txt b/libsolv-0.7.2/examples/CMakeLists.txt
new file mode 100644 (file)
index 0000000..703796c
--- /dev/null
@@ -0,0 +1,5 @@
+IF (SUSE OR FEDORA OR DEBIAN OR MANDRIVA OR MAGEIA)
+
+ADD_SUBDIRECTORY (solv)
+
+ENDIF (SUSE OR FEDORA OR DEBIAN OR MANDRIVA OR MAGEIA)
diff --git a/libsolv-0.7.2/examples/p5solv b/libsolv-0.7.2/examples/p5solv
new file mode 100755 (executable)
index 0000000..6f54247
--- /dev/null
@@ -0,0 +1,751 @@
+#!/usr/bin/perl -w
+
+use POSIX;
+use Fcntl;
+use Config::IniFiles;
+use Data::Dumper;
+use solv;
+use Devel::Peek;
+use FileHandle;
+use File::Temp ();
+use strict;
+
+package Repo::generic;
+
+sub new {
+  my ($class, $alias, $type, $attr) = @_;
+  my $r = { %{$attr || {}} };
+  $r->{alias} = $alias;
+  $r->{type} = $type;
+  return bless $r, $class;
+}
+
+sub calc_cookie_fp {
+  my ($self, $fp) = @_;
+  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
+  $chksum->add("1.1");
+  $chksum->add_fp($fp);
+  return $chksum->raw();
+}
+
+sub calc_cookie_file {
+  my ($self, $filename) = @_;
+  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
+  $chksum->add("1.1");
+  $chksum->add_stat($filename);
+  return $chksum->raw();
+}
+
+sub calc_cookie_ext {
+  my ($self, $f, $cookie) = @_;
+  my $chksum = solv::Chksum->new($solv::REPOKEY_TYPE_SHA256);
+  $chksum->add("1.1");
+  $chksum->add($cookie);
+  $chksum->add_fstat(fileno($f));
+  return $chksum->raw();
+}
+
+sub cachepath {
+  my ($self, $ext) = @_;
+  my $path = $self->{alias};
+  $path =~ s/^\./_/s;
+  $path .= $ext ? "_$ext.solvx" : '.solv';
+  $path =~ s!/!_!gs;
+  return "/var/cache/solv/$path";
+}
+
+sub load {
+  my ($self, $pool) = @_;
+  $self->{handle} = $pool->add_repo($self->{alias});
+  $self->{handle}->{appdata} = $self;
+  $self->{handle}->{priority} = 99 - $self->{priority};
+  my $dorefresh = $self->{autorefresh};
+  if ($dorefresh) {
+    my @s = stat($self->cachepath());
+    $dorefresh = 0 if @s && ($self->{metadata_expire} == -1 || time() - $s[9] < $self->{metadata_expire});
+  }
+  $self->{cookie} = '';
+  $self->{extcookie} = '';
+  if (!$dorefresh && $self->usecachedrepo()) {
+    print "repo: '$self->{alias}' cached\n";
+    return 1;
+  }
+  return 0;
+}
+
+sub load_ext {
+  return 0;
+}
+
+sub download {
+  my ($self, $file, $uncompress, $chksum, $markincomplete) = @_;
+  if (!$self->{baseurl}) {
+    print "$self->{alias}: no baseurl\n";
+    return undef;
+  }
+  my $url = $self->{baseurl};
+  $url =~ s!/$!!;
+  $url .= "/$file";
+  open(my $f, '+>', undef) || die;
+  fcntl($f, Fcntl::F_SETFD, 0);                # turn off CLOEXEC
+  my $st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" . fileno($f), '--', $url);
+  if (POSIX::lseek(fileno($f), 0, POSIX::SEEK_END) == 0 && ($st == 0 || !$chksum)) {
+    return undef;
+  }
+  POSIX::lseek(fileno($f), 0, POSIX::SEEK_SET);
+  if ($st) {
+    print "$file: download error #$st\n";
+    $self->{incomplete} = 1 if $markincomplete;
+    return undef;
+  }
+  if ($chksum) {
+    my $fchksum = solv::Chksum->new($chksum->{type});
+    $fchksum->add_fd(fileno($f));
+    if ($fchksum != $chksum) {
+      print "$file: checksum error\n";
+      $self->{incomplete} = 1 if $markincomplete;
+      return undef;
+    }
+  }
+  if ($uncompress) {
+    return solv::xfopen_fd($file, fileno($f));
+  } else {
+    return solv::xfopen_fd(undef, fileno($f));
+  }
+}
+
+sub usecachedrepo {
+  my ($self, $ext, $mark) = @_;
+  my $cookie = $ext ? $self->{extcookie} : $self->{cookie};
+  my $cachepath = $self->cachepath($ext);
+  my $fextcookie;
+  if (sysopen(my $f, $cachepath, POSIX::O_RDONLY)) {
+    sysseek($f, -32, Fcntl::SEEK_END);
+    my $fcookie = '';
+    return undef if sysread($f, $fcookie, 32) != 32;
+    return undef if $cookie && $fcookie ne $cookie;
+    if ($self->{type} ne 'system' && !$ext) {
+      sysseek($f, -32 * 2, Fcntl::SEEK_END);
+      return undef if sysread($f, $fextcookie, 32) != 32;
+    }
+    sysseek($f, 0, Fcntl::SEEK_SET);
+    my $fd = solv::xfopen_fd(undef, fileno($f));
+    my $flags = $ext ? $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES : 0;
+    $flags |= $solv::Repo::REPO_LOCALPOOL if $ext && $ext ne 'DL';
+    if (!$self->{handle}->add_solv($fd, $flags)) {
+      return undef;
+    }
+    $self->{cookie} = $fcookie unless $ext;
+    $self->{extcookie} = $fextcookie if $fextcookie;
+    utime undef, undef, $f if $mark;
+    return 1;
+  }
+  return undef;
+}
+
+sub writecachedrepo {
+  my ($self, $ext, $repodata) = @_;
+  return if $self->{incomplete};
+  mkdir("/var/cache/solv", 0755) unless -d "/var/cache/solv";
+  my ($f, $tmpname);
+  eval {
+    ($f, $tmpname) = File::Temp::tempfile(".newsolv-XXXXXX", 'DIR' => '/var/cache/solv');
+  };
+  return unless $f;
+  chmod 0444, $f;
+  my $ff = solv::xfopen_fd(undef, fileno($f));
+  if (!$repodata) {
+    $self->{handle}->write($ff);
+  } elsif ($ext) {
+    $repodata->write($ff);
+  } else {
+     $self->{handle}->write_first_repodata($ff);
+  }
+  undef $ff;   # also flushes
+  if ($self->{type} ne 'system' && !$ext) {
+    $self->{extcookie} ||= $self->calc_cookie_ext($f, $self->{cookie});
+    syswrite($f, $self->{extcookie});
+  }
+  syswrite($f, $ext ? $self->{extcookie} : $self->{cookie});
+  close($f);
+  if ($self->{handle}->iscontiguous()) {
+    $f = solv::xfopen($tmpname);
+    if ($f) {
+      if (!$ext) {
+       $self->{handle}->empty();
+       die("internal error, cannot reload solv file\n") unless $self->{handle}->add_solv($f, $repodata ? 0 : $solv::Repo::SOLV_ADD_NO_STUBS);
+      } else {
+       $repodata->extend_to_repo();
+       my $flags = $solv::Repo::REPO_EXTEND_SOLVABLES;
+       $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL';
+       $repodata->add_solv($f, $flags);
+      }
+    }
+  }
+  rename($tmpname, $self->cachepath($ext));
+}
+
+sub packagespath {
+  my ($self) = @_;
+  return '';
+}
+
+my %langtags = (
+  $solv::SOLVABLE_SUMMARY     => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_DESCRIPTION => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_EULA        => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_MESSAGEINS  => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_MESSAGEDEL  => $solv::REPOKEY_TYPE_STR,
+  $solv::SOLVABLE_CATEGORY    => $solv::REPOKEY_TYPE_ID,
+);
+
+sub add_ext_keys {
+  my ($self, $ext, $repodata, $handle) = @_;
+  if ($ext eq 'DL') {
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOSITORY_DELTAINFO);
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_FLEXARRAY);
+  } elsif ($ext eq 'DU') {
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_DISKUSAGE);
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRNUMNUMARRAY);
+  } elsif ($ext eq 'FL') {
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::SOLVABLE_FILELIST);
+    $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $solv::REPOKEY_TYPE_DIRSTRARRAY);
+  } else {
+    for my $langid (sort { $a <=> $b } keys %langtags) {
+      $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $self->{handle}->{pool}->id2langid($langid, $ext, 1));
+      $repodata->add_idarray($handle, $solv::REPOSITORY_KEYS, $langtags{$langid});
+    }
+  }
+}
+
+package Repo::rpmmd;
+
+our @ISA = ('Repo::generic');
+
+sub find {
+  my ($self, $what) = @_;
+  my $di = $self->{handle}->Dataiterator_meta($solv::REPOSITORY_REPOMD_TYPE, $what, $solv::Dataiterator::SEARCH_STRING);
+  $di->prepend_keyname($solv::REPOSITORY_REPOMD);
+  for my $d (@$di) {
+    my $dp = $d->parentpos();
+    my $filename = $dp->lookup_str($solv::REPOSITORY_REPOMD_LOCATION);
+    next unless $filename;
+    my $chksum = $dp->lookup_checksum($solv::REPOSITORY_REPOMD_CHECKSUM);
+    if (!$chksum) {
+      print "no $filename file checksum!\n";
+      return (undef, undef);
+    }
+    return ($filename, $chksum);
+  }
+  return (undef, undef);
+}
+
+sub add_ext {
+  my ($self, $repodata, $what, $ext) = @_;
+  my ($filename, $chksum) = $self->find($what);
+  ($filename, $chksum) = $self->find('prestodelta') if !$filename && $what eq 'deltainfo';
+  return unless $filename;
+  my $handle = $repodata->new_handle();
+  $repodata->set_poolstr($handle, $solv::REPOSITORY_REPOMD_TYPE, $what);
+  $repodata->set_str($handle, $solv::REPOSITORY_REPOMD_LOCATION, $filename);
+  $repodata->set_checksum($handle, $solv::REPOSITORY_REPOMD_CHECKSUM, $chksum);
+  $self->add_ext_keys($ext, $repodata, $handle);
+  $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle);
+}
+
+sub add_exts {
+  my ($self) = @_;
+  my $repodata = $self->{handle}->add_repodata(0);
+  $repodata->extend_to_repo();
+  $self->add_ext($repodata, 'deltainfo', 'DL');
+  $self->add_ext($repodata, 'filelists', 'FL');
+  $repodata->internalize();
+}
+
+sub load_ext {
+  my ($self, $repodata) = @_;
+  my $repomdtype = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_TYPE);
+  my $ext;
+  if ($repomdtype eq 'filelists') {
+    $ext = 'FL';
+  } elsif ($repomdtype eq 'deltainfo') {
+    $ext = 'DL';
+  } else {
+    return 0;
+  }
+  print("[$self->{alias}:$ext: ");
+  STDOUT->flush();
+  if ($self->usecachedrepo($ext)) {
+    print "cached]\n";
+    return 1;
+  }
+  print "fetching]\n";
+  my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_LOCATION);
+  my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::REPOSITORY_REPOMD_CHECKSUM);
+  my $f = $self->download($filename, 1, $filechksum);
+  return 0 unless $f;
+  if ($ext eq 'FL') {
+    $self->{handle}->add_rpmmd($f, 'FL', $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES|$solv::Repo::REPO_LOCALPOOL);
+  } elsif ($ext eq 'DL') {
+    $self->{handle}->add_deltainfoxml($f, $solv::Repo::REPO_USE_LOADING);
+  }
+  $self->writecachedrepo($ext, $repodata);
+  return 1;
+}
+
+sub load {
+  my ($self, $pool) = @_;
+  return 1 if $self->Repo::generic::load($pool);
+  print "rpmmd repo '$self->{alias}': ";
+  STDOUT->flush();
+  my $f = $self->download("repodata/repomd.xml");
+  if (!$f) {
+    print "no repomd.xml file, skipped\n";
+    $self->{handle}->free(1);
+    delete $self->{handle};
+    return undef;
+  }
+  $self->{cookie} = $self->calc_cookie_fp($f);
+  if ($self->usecachedrepo(undef, 1)) {
+    print "cached\n";
+    return 1;
+  }
+  $self->{handle}->add_repomdxml($f, 0);
+  print "fetching\n";
+  my ($filename, $filechksum) = $self->find('primary');
+  if ($filename) {
+    $f = $self->download($filename, 1, $filechksum, 1);
+    if ($f) {
+      $self->{handle}->add_rpmmd($f, undef, 0);
+    }
+    return undef if $self->{incomplete};
+  }
+  ($filename, $filechksum) = $self->find('updateinfo');
+  if ($filename) {
+    $f = $self->download($filename, 1, $filechksum, 1);
+    if ($f) {
+      $self->{handle}->add_updateinfoxml($f, 0);
+    }
+  }
+  $self->add_exts();
+  $self->writecachedrepo();
+  $self->{handle}->create_stubs();
+  return 1;
+}
+
+package Repo::susetags;
+
+our @ISA = ('Repo::generic');
+
+sub find {
+  my ($self, $what) = @_;
+  
+  my $di = $self->{handle}->Dataiterator_meta($solv::SUSETAGS_FILE_NAME, $what, $solv::Dataiterator::SEARCH_STRING);
+  $di->prepend_keyname($solv::SUSETAGS_FILE);
+  for my $d (@$di) {
+    my $dp = $d->parentpos();
+    my $chksum = $dp->lookup_checksum($solv::SUSETAGS_FILE_CHECKSUM);
+    return ($what, $chksum);
+  }
+  return (undef, undef);
+}
+
+
+sub add_ext {
+  my ($self, $repodata, $what, $ext) = @_;
+  my ($filename, $chksum) = $self->find($what);
+  return unless $filename;
+  my $handle = $repodata->new_handle();
+  $repodata->set_str($handle, $solv::SUSETAGS_FILE_NAME, $filename);
+  $repodata->set_checksum($handle, $solv::SUSETAGS_FILE_CHECKSUM, $chksum);
+  $self->add_ext_keys($ext, $repodata, $handle);
+  $repodata->add_flexarray($solv::SOLVID_META, $solv::REPOSITORY_EXTERNAL, $handle);
+}
+
+sub add_exts {
+  my ($self) = @_;
+  my $repodata = $self->{handle}->add_repodata(0);
+  my $di = $self->{handle}->Dataiterator_meta($solv::SUSETAGS_FILE_NAME, undef, 0);
+  $di->prepend_keyname($solv::SUSETAGS_FILE);
+  for my $d (@$di) {
+    my $filename = $d->str();
+    next unless $filename && $filename =~ /^packages\.(..)(?:\..*)$/;
+    next if $1 eq 'en' || $1 eq 'gz';
+    $self->add_ext($repodata, $filename, $1);
+  }
+  $repodata->internalize();
+}
+
+sub load_ext {
+  my ($self, $repodata) = @_;
+  my $filename = $repodata->lookup_str($solv::SOLVID_META, $solv::SUSETAGS_FILE_NAME);
+  my $ext = substr($filename, 9, 2);
+  print("[$self->{alias}:$ext: ");
+  STDOUT->flush();
+  if ($self->usecachedrepo($ext)) {
+    print "cached]\n";
+    return 1;
+  }
+  print "fetching]\n";
+  my $defvendorid = $self->{handle}->{meta}->lookup_id($solv::SUSETAGS_DEFAULTVENDOR);
+  my $descrdir = $self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; 
+  my $filechksum = $repodata->lookup_checksum($solv::SOLVID_META, $solv::SUSETAGS_FILE_CHECKSUM);
+  my $f = $self->download("$descrdir/$filename", 1, $filechksum);
+  return 0 unless $f;
+  my $flags = $solv::Repo::REPO_USE_LOADING|$solv::Repo::REPO_EXTEND_SOLVABLES;
+  $flags |= $solv::Repo::REPO_LOCALPOOL if $ext ne 'DL';
+  $self->{handle}->add_susetags($f, $defvendorid, $ext, $flags);
+  $self->writecachedrepo($ext, $repodata);
+  return 1;
+}
+
+sub load {
+  my ($self, $pool) = @_;
+  return 1 if $self->Repo::generic::load($pool);
+  print "susetags repo '$self->{alias}': ";
+  STDOUT->flush();
+  my $f = $self->download("content");
+  if (!$f) {
+    print "no content file, skipped\n";
+    $self->{handle}->free(1);
+    delete $self->{handle};
+    return undef;
+  }
+  $self->{cookie} = $self->calc_cookie_fp($f);
+  if ($self->usecachedrepo(undef, 1)) {
+    print "cached\n";
+    return 1;
+  }
+  $self->{handle}->add_content($f, 0);
+  print "fetching\n";
+  my $defvendorid = $self->{handle}->{meta}->lookup_id($solv::SUSETAGS_DEFAULTVENDOR);
+  my $descrdir = $self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DESCRDIR) || 'suse/setup/descr'; 
+  my ($filename, $filechksum) = $self->find('packages.gz');
+  ($filename, $filechksum) = $self->find('packages') unless $filename;
+  if ($filename) {
+    $f = $self->download("$descrdir/$filename", 1, $filechksum, 1);
+    if ($f) {
+      $self->{handle}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::SUSETAGS_RECORD_SHARES);
+      ($filename, $filechksum) = $self->find('packages.en.gz');
+      ($filename, $filechksum) = $self->find('packages.en') unless $filename;
+      if ($filename) {
+       $f = $self->download("$descrdir/$filename", 1, $filechksum, 1);
+       if ($f) {
+         $self->{handle}->add_susetags($f, $defvendorid, undef, $solv::Repo::REPO_NO_INTERNALIZE|$solv::Repo::REPO_REUSE_REPODATA|$solv::Repo::REPO_EXTEND_SOLVABLES);
+       }
+      }
+      $self->{handle}->internalize();
+    }
+  }
+  $self->add_exts();
+  $self->writecachedrepo();
+  $self->{handle}->create_stubs();
+  return undef;
+}
+
+sub packagespath {
+  my ($self) = @_;
+  return ($self->{handle}->{meta}->lookup_str($solv::SUSETAGS_DATADIR) || 'suse') . '/';
+}
+
+package Repo::unknown;
+
+our @ISA = ('Repo::generic');
+
+sub load {
+  my ($self) = @_;
+  print "unsupported repo '$self->{alias}': skipped\n";
+  return 0;
+}
+
+package Repo::system;
+
+our @ISA = ('Repo::generic');
+
+sub load {
+  my ($self, $pool) = @_;
+
+  $self->{handle} = $pool->add_repo($self->{alias});
+  $self->{handle}->{appdata} = $self;
+  $pool->{installed} = $self->{handle};
+  print "rpm database: ";
+  $self->{cookie} = $self->calc_cookie_file('/var/lib/rpm/Packages');
+  if ($self->usecachedrepo()) {
+    print "cached\n";
+    return 1;
+  }
+  print "reading\n";
+  if (defined(&solv::Repo::add_products)) {
+    $self->{handle}->add_products("/etc/products.d", $solv::Repo::REPO_NO_INTERNALIZE);
+  }
+  my $f = solv::xfopen($self->cachepath());
+  $self->{handle}->add_rpmdb_reffp($f, $solv::Repo::REPO_REUSE_REPODATA);
+  $self->writecachedrepo();
+  return 1;
+}
+
+package main;
+
+sub load_stub {
+  my ($repodata) = @_;
+  my $repo = $repodata->{repo}->{appdata};
+  return $repo ? $repo->load_ext($repodata) : 0;
+}
+
+die("Usage: p5solv COMMAND [ARGS]\n") unless @ARGV;
+my $cmd = shift @ARGV;
+my %cmdabbrev = ( 'ls' => 'list', 'in' => 'install', 'rm' => 'erase',
+                  've' => 'verify', 'se' => 'search' );
+$cmd = $cmdabbrev{$cmd} if $cmdabbrev{$cmd};
+
+my %cmdactionmap = (
+  'install' => $solv::Job::SOLVER_INSTALL,
+  'erase'   => $solv::Job::SOLVER_ERASE,
+  'up'      => $solv::Job::SOLVER_UPDATE,
+  'dup'     => $solv::Job::SOLVER_DISTUPGRADE,
+  'verify'  => $solv::Job::SOLVER_VERIFY,
+  'list'    => 0,  
+  'info'    => 0,
+);
+
+my @repos;
+my @reposdirs;
+if (-d '/etc/zypp/repos.d') {
+  @reposdirs = ( '/etc/zypp/repos.d' );
+} else {
+  @reposdirs = ( '/etc/yum/repos.d' );
+}
+for my $reposdir (@reposdirs) {
+  next unless -d $reposdir;
+  my $dir;
+  next unless opendir($dir, $reposdir);
+  for my $reponame (sort(grep {/\.repo$/} readdir($dir))) {
+    my $cfg = new Config::IniFiles('-file' => "$reposdir/$reponame");
+    for my $alias ($cfg->Sections()) {
+      my $repoattr = {'alias' => $alias, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900};
+      for my $p ($cfg->Parameters($alias)) {
+       $repoattr->{$p} = $cfg->val($alias, $p);
+      }
+      my $repo;
+      if ($repoattr->{type} eq 'rpm-md') {
+       $repo = Repo::rpmmd->new($alias, 'repomd', $repoattr);
+      } elsif ($repoattr->{type} eq 'yast2') {
+       $repo = Repo::susetags->new($alias, 'susetags', $repoattr);
+      } else {
+       $repo = Repo::unknown->new($alias, 'unknown', $repoattr);
+      }
+      push @repos, $repo;
+    }
+  }
+}
+
+my $pool = solv::Pool->new();
+$pool->setarch();
+$pool->set_loadcallback(\&load_stub);
+
+my $sysrepo = Repo::system->new('@System', 'system');
+$sysrepo->load($pool);
+for my $repo (@repos) {
+  $repo->load($pool) if $repo->{enabled};
+}
+
+if ($cmd eq 'search') {
+  $pool->createwhatprovides();
+  my $sel = $pool->Selection();
+  my $di = $pool->Dataiterator($solv::SOLVABLE_NAME, $ARGV[0], $solv::Dataiterator::SEARCH_SUBSTRING | $solv::Dataiterator::SEARCH_NOCASE);
+  for my $d (@$di) {
+    $sel->add_raw($solv::Job::SOLVER_SOLVABLE, $d->{solvid});
+  }
+  for my $s ($sel->solvables()) {
+    print "- ".$s->str()." [$s->{repo}->{name}]: ".$s->lookup_str($solv::SOLVABLE_SUMMARY)."\n";
+  }
+  exit(0);
+}
+
+die("unknown command '$cmd'\n") unless defined $cmdactionmap{$cmd};
+
+$pool->addfileprovides();
+$pool->createwhatprovides();
+$pool->set_namespaceproviders($solv::NAMESPACE_LANGUAGE, $pool->Dep('de'), 1);
+
+my @jobs;
+for my $arg (@ARGV) {
+  my $flags = $solv::Selection::SELECTION_NAME | $solv::Selection::SELECTION_PROVIDES | $solv::Selection::SELECTION_GLOB;
+  $flags |= $solv::Selection::SELECTION_CANON | $solv::Selection::SELECTION_DOTARCH | $solv::Selection::SELECTION_REL;
+  if ($arg =~ m!^/!) {
+    $flags |= $solv::Selection::SELECTION_FILELIST;
+    $flags |= $solv::Selection::SELECTION_INSTALLED_ONLY if $cmd eq 'erase';
+  }
+  my $sel = $pool->select($arg, $flags);
+  if ($sel->isempty()) {
+    $sel = $pool->select($arg, $flags | $solv::Selection::SELECTION_NOCASE);
+    print "[ignoring case for '$arg']\n" unless $sel->isempty();
+  }
+  die("nothing matches '$arg'\n") if $sel->isempty();
+  print "[using file list match for '$arg']\n" if $sel->{flags} & $solv::Selection::SELECTION_FILELIST;
+  print "[using capability match for '$arg']\n" if $sel->{flags} & $solv::Selection::SELECTION_PROVIDES;
+  push @jobs, $sel->jobs($cmdactionmap{$cmd});
+}
+
+if (!@jobs && ($cmd eq 'up' || $cmd eq 'dup' || $cmd eq 'verify')) {
+  my $sel = $pool->Selection_all();
+  push @jobs, $sel->jobs($cmdactionmap{$cmd});
+}
+
+die("no package matched.\n") unless @jobs;
+
+if ($cmd eq 'list' || $cmd eq 'info') {
+  for my $job (@jobs) {
+    for my $s ($job->solvables()) {
+      if ($cmd eq 'info') {
+       printf "Name:        %s\n", $s->str();
+       printf "Repo:        %s\n", $s->{repo}->{name};
+       printf "Summary:     %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY);
+       my $str = $s->lookup_str($solv::SOLVABLE_URL);
+       printf "Url:         %s\n", $str if $str;
+       $str = $s->lookup_str($solv::SOLVABLE_LICENSE);
+       printf "License:     %s\n", $str if $str;
+       printf "Description:\n%s\n", $s->lookup_str($solv::SOLVABLE_DESCRIPTION);
+      } else {
+       printf "  - %s [%s]\n", $s->str(), $s->{repo}->{name};
+       printf "    %s\n", $s->lookup_str($solv::SOLVABLE_SUMMARY);
+      }
+    }
+  }
+  exit 0;
+}
+
+# up magic, turn into install if nothing matches
+for my $job (@jobs) {
+  $job->{how} ^= $solv::Job::SOLVER_UPDATE ^ $solv::Job::SOLVER_INSTALL if $cmd eq 'up' && $job->isemptyupdate();
+}
+
+my $solver = $pool->Solver();
+$solver->set_flag($solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1);
+$solver->set_flag($solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if $cmd eq 'erase';
+
+while (1) {
+  my @problems = $solver->solve(\@jobs);
+  last unless @problems;
+  for my $problem (@problems) {
+    print "Problem $problem->{id}/".@problems.":\n";
+    print $problem->str()."\n";
+    my @solutions = $problem->solutions();
+    for my $solution (@solutions) {
+      print "  Solution $solution->{id}:\n";
+      for my $element ($solution->elements(1)) {
+       print "  - ".$element->str()."\n";
+      }
+      print "\n";
+    }
+    my $sol;
+    while (1) {
+      print "Please choose a solution: ";
+      $sol = <STDIN>;
+      chomp $sol;
+      last if $sol eq 's' || $sol eq 'q' || ($sol =~ /^\d+$/ && $sol >= 1 && $sol <= @solutions);
+    }
+    next if $sol eq 's';
+    exit(1) if $sol eq 'q';
+    my $solution = $solutions[$sol - 1];
+    for my $element ($solution->elements()) {
+      my $newjob = $element->Job();
+      if ($element->{type} == $solv::Solver::SOLVER_SOLUTION_JOB) {
+       $jobs[$element->{jobidx}] = $newjob;
+      } else {
+       push @jobs, $newjob if $newjob && !grep {$_ == $newjob} @jobs;
+      }
+    }
+  }
+}
+
+my $trans = $solver->transaction();
+undef $solver;
+if ($trans->isempty()) {
+  print "Nothing to do.\n";
+  exit 0;
+}
+
+print "\nTransaction summary:\n\n";
+for my $c ($trans->classify($solv::Transaction::SOLVER_TRANSACTION_SHOW_OBSOLETES|$solv::Transaction::SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE)) {
+  if ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
+    print "$c->{count} erased packages:\n";
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_INSTALL) {
+    print "$c->{count} installed packages:\n";
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_REINSTALLED) {
+    print "$c->{count} reinstalled packages:\n";
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
+    print "$c->{count} downgraded packages:\n";
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_CHANGED) {
+    print "$c->{count} changed packages:\n";
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED) {
+    print "$c->{count} upgraded packages:\n";
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE) {
+    printf "$c->{count} vendor changes from '%s' to '%s':\n", $c->{fromstr}, $c->{tostr};
+  } elsif ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE) {
+    printf "$c->{count} arch changes from '%s' to '%s':\n", $c->{fromstr}, $c->{tostr};
+  } else {
+    next;
+  }
+  for my $p ($c->solvables()) {
+    if ($c->{type} == $solv::Transaction::SOLVER_TRANSACTION_UPGRADED || $c->{type} == $solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED) {
+      my $other = $trans->othersolvable($p);
+      printf "  - %s -> %s\n", $p->str(), $other->str();
+    } else {
+      printf "  - %s\n", $p->str();
+    }
+  }
+  print "\n";
+}
+printf "install size change: %d K\n\n", $trans->calc_installsizechange();
+
+while (1) {
+  print("OK to continue (y/n)? ");
+  my $yn = <STDIN>;
+  chomp $yn;
+  last if $yn eq 'y';
+  exit(1) if $yn eq 'n' || $yn eq 'q';
+}
+
+my @newpkgs = $trans->newsolvables();
+my %newpkgsfps;
+if (@newpkgs) {
+  my $downloadsize = 0;
+  $downloadsize += $_->lookup_num($solv::SOLVABLE_DOWNLOADSIZE) for @newpkgs;
+  printf "Downloading %d packages, %d K\n", scalar(@newpkgs), $downloadsize / 1024;
+  for my $p (@newpkgs) {
+    my $repo = $p->{repo}->{appdata};
+    my ($location) = $p->lookup_location();
+    next unless $location;
+    $location = $repo->packagespath() . $location;
+    my $chksum = $p->lookup_checksum($solv::SOLVABLE_CHECKSUM);
+    my $f = $repo->download($location, 0, $chksum);
+    die("\n$repo->{alias}: $location not found in repository\n") unless $f;
+    $newpkgsfps{$p->{id}} = $f;
+    print ".";
+    STDOUT->flush();
+  }
+  print "\n";
+}
+
+print "Committing transaction:\n\n";
+$trans->order();
+for my $p ($trans->steps()) {
+  my $steptype = $trans->steptype($p, $solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY);
+  if ($steptype == $solv::Transaction::SOLVER_TRANSACTION_ERASE) {
+    print "erase ".$p->str()."\n";
+    next unless $p->lookup_num($solv::RPM_RPMDBID);
+    my $evr = $p->{evr};
+    $evr =~ s/^[0-9]+://;      # strip epoch
+    system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "$p->{name}-$evr.$p->{arch}") && die("rpm failed: $?\n");
+  } elsif ($steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL) {
+    print "install ".$p->str()."\n";
+    my $f = $newpkgsfps{$p->{id}};
+    my $mode = $steptype == $solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i';
+    $f->cloexec(0);
+    system('rpm', $mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/".$f->fileno()) && die("rpm failed: $?\n");
+    delete $newpkgsfps{$p->{id}};
+  }
+}
+
+exit 0;
diff --git a/libsolv-0.7.2/examples/pysolv b/libsolv-0.7.2/examples/pysolv
new file mode 100755 (executable)
index 0000000..75067f2
--- /dev/null
@@ -0,0 +1,961 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2011, Novell Inc.
+#
+# This program is licensed under the BSD license, read LICENSE.BSD
+# for further information
+#
+
+# pysolv a little software installer demoing the sat solver library/bindings
+
+# things it does:
+# - understands globs for package names / dependencies
+# - understands .arch suffix
+# - repository data caching
+# - on demand loading of secondary repository data
+# - checksum verification
+# - deltarpm support
+# - installation of commandline packages
+#
+# things not yet ported:
+# - gpg verification
+# - file conflicts
+# - fastestmirror implementation
+#
+# things available in the library but missing from pysolv:
+# - vendor policy loading
+# - soft locks file handling
+# - multi version handling
+
+import sys
+import os
+import glob
+import solv
+import re
+import tempfile
+import time
+import subprocess
+import rpm
+from stat import *
+from iniparse import INIConfig
+from optparse import OptionParser
+
+#import gc
+#gc.set_debug(gc.DEBUG_LEAK)
+
+class repo_generic(dict):
+    def __init__(self, name, type, attribs = {}):
+        for k in attribs:
+            self[k] = attribs[k]
+        self.name = name
+        self.type = type
+
+    def calc_cookie_file(self, filename):
+        chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256)
+        chksum.add("1.1")
+        chksum.add_stat(filename)
+        return chksum.raw()
+
+    def calc_cookie_fp(self, fp):
+        chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256)
+        chksum.add("1.1");
+        chksum.add_fp(fp)
+        return chksum.raw()
+
+    def calc_cookie_ext(self, f, cookie):
+        chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256)
+        chksum.add("1.1");
+        chksum.add(cookie)
+        chksum.add_fstat(f.fileno())
+        return chksum.raw()
+
+    def cachepath(self, ext = None):
+        path = re.sub(r'^\.', '_', self.name)
+        if ext:
+            path += "_" + ext + ".solvx"
+        else:
+            path += ".solv"
+        return "/var/cache/solv/" + re.sub(r'[/]', '_', path)
+        
+    def load(self, pool):
+        self.handle = pool.add_repo(self.name)
+        self.handle.appdata = self
+        self.handle.priority = 99 - self['priority']
+        dorefresh = bool(int(self['autorefresh']))
+        if dorefresh:
+            try:
+                st = os.stat(self.cachepath())
+                if self['metadata_expire'] == -1 or time.time() - st[ST_MTIME] < self['metadata_expire']:
+                    dorefresh = False
+            except OSError:
+                pass
+        self['cookie'] = ''
+        self['extcookie'] = ''
+        if not dorefresh and self.usecachedrepo(None):
+            print("repo: '%s': cached" % self.name)
+            return True
+        return False
+
+    def load_ext(self, repodata):
+        return False
+
+    def setfromurls(self, urls):
+        if not urls:
+            return
+        url = urls[0]
+        print("[using mirror %s]" % re.sub(r'^(.*?/...*?)/.*$', r'\1', url))
+        self['baseurl'] = url
+
+    def setfrommetalink(self, metalink):
+        f = self.download(metalink, False, None)
+        if not f:
+            return None
+        f = os.fdopen(f.dup(), 'r')
+        urls = []
+        chksum = None
+        for l in f.readlines():
+            l = l.strip()
+            m = re.match(r'^<hash type="sha256">([0-9a-fA-F]{64})</hash>', l)
+            if m:
+                chksum = solv.Chksum(solv.REPOKEY_TYPE_SHA256, m.group(1))
+            m = re.match(r'^<url.*>(https?://.+)repodata/repomd.xml</url>', l)
+            if m:
+                urls.append(m.group(1))
+        if not urls:
+            chksum = None       # in case the metalink is about a different file
+        f.close()
+        self.setfromurls(urls)
+        return chksum
+        
+    def setfrommirrorlist(self, mirrorlist):
+        f = self.download(mirrorlist, False, None)
+        if not f:
+            return
+        f = os.fdopen(f.dup(), 'r')
+        urls = []
+        for l in f.readline():
+            l = l.strip()
+            if l[0:6] == 'http://' or l[0:7] == 'https://':
+                urls.append(l)
+        self.setfromurls(urls)
+        f.close()
+        
+    def download(self, file, uncompress, chksum, markincomplete=False):
+        url = None
+        if 'baseurl' not in self:
+            if 'metalink' in self:
+                if file != self['metalink']:
+                    metalinkchksum = self.setfrommetalink(self['metalink'])
+                    if file == 'repodata/repomd.xml' and metalinkchksum and not chksum:
+                        chksum = metalinkchksum
+                else:
+                    url = file
+            elif 'mirrorlist' in self:
+                if file != self['mirrorlist']:
+                    self.setfrommirrorlist(self['mirrorlist'])
+                else:
+                    url = file
+        if not url:
+            if 'baseurl' not in self:
+                print("%s: no baseurl" % self.name)
+                return None
+            url = re.sub(r'/$', '', self['baseurl']) + '/' + file
+        f = tempfile.TemporaryFile()
+        st = subprocess.call(['curl', '-f', '-s', '-L', url], stdout=f.fileno())
+        if os.lseek(f.fileno(), 0, os.SEEK_CUR) == 0 and (st == 0 or not chksum):
+            return None
+        os.lseek(f.fileno(), 0, os.SEEK_SET)
+        if st:
+            print("%s: download error %d" % (file, st))
+            if markincomplete:
+                self['incomplete'] = True
+            return None
+        if chksum:
+            fchksum = solv.Chksum(chksum.type)
+            if not fchksum:
+                print("%s: unknown checksum type" % file)
+                if markincomplete:
+                    self['incomplete'] = True
+                return None
+            fchksum.add_fd(f.fileno())
+            if fchksum != chksum:
+                print("%s: checksum mismatch" % file)
+                if markincomplete:
+                    self['incomplete'] = True
+                return None
+        if uncompress:
+            return solv.xfopen_fd(file, f.fileno())
+        return solv.xfopen_fd(None, f.fileno())
+
+    def usecachedrepo(self, ext, mark=False):
+        try: 
+            repopath = self.cachepath(ext)
+            f = open(repopath, 'rb')
+            f.seek(-32, os.SEEK_END)
+            fcookie = f.read(32)
+            if len(fcookie) != 32:
+                return False
+            if not ext:
+                cookie = self['cookie']
+            else:
+                cookie = self['extcookie']
+            if cookie and fcookie != cookie:
+                return False
+            if self.type != 'system' and not ext:
+                f.seek(-32 * 2, os.SEEK_END)
+                fextcookie = f.read(32)
+                if len(fextcookie) != 32:
+                    return False
+            f.seek(0)
+            f = solv.xfopen_fd('', f.fileno())
+            flags = 0
+            if ext:
+                flags = solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES
+                if ext != 'DL':
+                    flags |= solv.Repo.REPO_LOCALPOOL
+            if not self.handle.add_solv(f, flags):
+                return False
+            if self.type != 'system' and not ext:
+                self['cookie'] = fcookie
+                self['extcookie'] = fextcookie
+            if mark:
+                # no futimes in python?
+                try:
+                    os.utime(repopath, None)
+                except Exception:
+                    pass
+        except IOError:
+            return False
+        return True
+
+    def writecachedrepo(self, ext, repodata=None):
+        if 'incomplete' in self:
+            return
+        tmpname = None
+        try:
+            if not os.path.isdir("/var/cache/solv"):
+                os.mkdir("/var/cache/solv", 0o755)
+            (fd, tmpname) = tempfile.mkstemp(prefix='.newsolv-', dir='/var/cache/solv')
+            os.fchmod(fd, 0o444)
+            f = os.fdopen(fd, 'wb+')
+            f = solv.xfopen_fd(None, f.fileno())
+            if not repodata:
+                self.handle.write(f)
+            elif ext:
+                repodata.write(f)
+            else:       # rewrite_repos case, do not write stubs
+                self.handle.write_first_repodata(f)
+            f.flush()
+            if self.type != 'system' and not ext:
+                if not self['extcookie']:
+                    self['extcookie'] = self.calc_cookie_ext(f, self['cookie'])
+                f.write(self['extcookie'])
+            if not ext:
+                f.write(self['cookie'])
+            else:
+                f.write(self['extcookie'])
+            f.close
+            if self.handle.iscontiguous():
+                # switch to saved repo to activate paging and save memory
+                nf = solv.xfopen(tmpname)
+                if not ext:
+                    # main repo
+                    self.handle.empty()
+                    flags = solv.Repo.SOLV_ADD_NO_STUBS
+                    if repodata:
+                        flags = 0       # rewrite repos case, recreate stubs
+                    if not self.handle.add_solv(nf, flags):
+                        sys.exit("internal error, cannot reload solv file")
+                else:
+                    # extension repodata
+                    # need to extend to repo boundaries, as this is how
+                    # repodata.write() has written the data
+                    repodata.extend_to_repo()
+                    flags = solv.Repo.REPO_EXTEND_SOLVABLES
+                    if ext != 'DL':
+                        flags |= solv.Repo.REPO_LOCALPOOL
+                    repodata.add_solv(nf, flags)
+            os.rename(tmpname, self.cachepath(ext))
+        except (OSError, IOError):
+            if tmpname:
+                os.unlink(tmpname)
+
+    def updateaddedprovides(self, addedprovides):
+        if 'incomplete' in self:
+            return 
+        if not hasattr(self, 'handle'):
+            return 
+        if self.handle.isempty():
+            return
+        # make sure there's just one real repodata with extensions
+        repodata = self.handle.first_repodata()
+        if not repodata:
+            return
+        oldaddedprovides = repodata.lookup_idarray(solv.SOLVID_META, solv.REPOSITORY_ADDEDFILEPROVIDES)
+        if not set(addedprovides) <= set(oldaddedprovides):
+            for id in addedprovides:
+                repodata.add_idarray(solv.SOLVID_META, solv.REPOSITORY_ADDEDFILEPROVIDES, id)
+            repodata.internalize()
+            self.writecachedrepo(None, repodata)
+
+    def packagespath(self):
+        return ''
+
+    def add_ext_keys(self, ext, repodata, handle):
+        if ext == 'DL':
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOSITORY_DELTAINFO)
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_FLEXARRAY)
+        elif ext == 'DU':
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_DISKUSAGE)
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRNUMNUMARRAY)
+        elif ext == 'FL':
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.SOLVABLE_FILELIST)
+            repodata.add_idarray(handle, solv.REPOSITORY_KEYS, solv.REPOKEY_TYPE_DIRSTRARRAY)
+        else:
+            for langtag, langtagtype in [
+                (solv.SOLVABLE_SUMMARY, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_DESCRIPTION, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_EULA, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_MESSAGEINS, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_MESSAGEDEL, solv.REPOKEY_TYPE_STR),
+                (solv.SOLVABLE_CATEGORY, solv.REPOKEY_TYPE_ID)
+            ]:
+                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, self.handle.pool.id2langid(langtag, ext, 1))
+                repodata.add_idarray(handle, solv.REPOSITORY_KEYS, langtagtype)
+        
+
+class repo_repomd(repo_generic):
+    def load(self, pool):
+        if super(repo_repomd, self).load(pool):
+            return True
+        sys.stdout.write("rpmmd repo '%s': " % self.name)
+        sys.stdout.flush()
+        f = self.download("repodata/repomd.xml", False, None, None)
+        if not f:
+            print("no repomd.xml file, skipped")
+            self.handle.free(True)
+            del self.handle
+            return False
+        self['cookie'] = self.calc_cookie_fp(f)
+        if self.usecachedrepo(None, True):
+            print("cached")
+            return True
+        self.handle.add_repomdxml(f, 0)
+        print("fetching")
+        (filename, filechksum) = self.find('primary')
+        if filename:
+            f = self.download(filename, True, filechksum, True)
+            if f:
+                self.handle.add_rpmmd(f, None, 0)
+            if 'incomplete' in self:
+                return False # hopeless, need good primary
+        (filename, filechksum) = self.find('updateinfo')
+        if filename:
+            f = self.download(filename, True, filechksum, True)
+            if f:
+                self.handle.add_updateinfoxml(f, 0)
+        self.add_exts()
+        self.writecachedrepo(None)
+        # must be called after writing the repo
+        self.handle.create_stubs()
+        return True
+
+    def find(self, what):
+        di = self.handle.Dataiterator_meta(solv.REPOSITORY_REPOMD_TYPE, what, solv.Dataiterator.SEARCH_STRING)
+        di.prepend_keyname(solv.REPOSITORY_REPOMD)
+        for d in di:
+            dp = d.parentpos()
+            filename = dp.lookup_str(solv.REPOSITORY_REPOMD_LOCATION)
+            chksum = dp.lookup_checksum(solv.REPOSITORY_REPOMD_CHECKSUM)
+            if filename and not chksum:
+                print("no %s file checksum!" % filename)
+                filename = None
+                chksum = None
+            if filename:
+                return (filename, chksum)
+        return (None, None)
+        
+    def add_ext(self, repodata, what, ext):
+        filename, chksum = self.find(what)
+        if not filename and what == 'deltainfo':
+            filename, chksum = self.find('prestodelta')
+        if not filename:
+            return
+        handle = repodata.new_handle()
+        repodata.set_poolstr(handle, solv.REPOSITORY_REPOMD_TYPE, what)
+        repodata.set_str(handle, solv.REPOSITORY_REPOMD_LOCATION, filename)
+        repodata.set_checksum(handle, solv.REPOSITORY_REPOMD_CHECKSUM, chksum)
+        self.add_ext_keys(ext, repodata, handle)
+        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
+
+    def add_exts(self):
+        repodata = self.handle.add_repodata(0)
+        repodata.extend_to_repo()
+        self.add_ext(repodata, 'deltainfo', 'DL')
+        self.add_ext(repodata, 'filelists', 'FL')
+        repodata.internalize()
+    
+    def load_ext(self, repodata):
+        repomdtype = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_TYPE)
+        if repomdtype == 'filelists':
+            ext = 'FL'
+        elif repomdtype == 'deltainfo':
+            ext = 'DL'
+        else:
+            return False
+        sys.stdout.write("[%s:%s: " % (self.name, ext))
+        if self.usecachedrepo(ext):
+            sys.stdout.write("cached]\n")
+            sys.stdout.flush()
+            return True
+        sys.stdout.write("fetching]\n")
+        sys.stdout.flush()
+        filename = repodata.lookup_str(solv.SOLVID_META, solv.REPOSITORY_REPOMD_LOCATION)
+        filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.REPOSITORY_REPOMD_CHECKSUM)
+        f = self.download(filename, True, filechksum)
+        if not f:
+            return False
+        if ext == 'FL':
+            self.handle.add_rpmmd(f, 'FL', solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES|solv.Repo.REPO_LOCALPOOL)
+        elif ext == 'DL':
+            self.handle.add_deltainfoxml(f, solv.Repo.REPO_USE_LOADING)
+        self.writecachedrepo(ext, repodata)
+        return True
+
+class repo_susetags(repo_generic):
+    def load(self, pool):
+        if super(repo_susetags, self).load(pool):
+            return True
+        sys.stdout.write("susetags repo '%s': " % self.name)
+        sys.stdout.flush()
+        f = self.download("content", False, None, None)
+        if not f:
+            print("no content file, skipped")
+            self.handle.free(True)
+            del self.handle
+            return False
+        self['cookie'] = self.calc_cookie_fp(f)
+        if self.usecachedrepo(None, True):
+            print("cached")
+            return True
+        self.handle.add_content(f, 0)
+        print("fetching")
+        defvendorid = self.handle.meta.lookup_id(solv.SUSETAGS_DEFAULTVENDOR)
+        descrdir = self.handle.meta.lookup_str(solv.SUSETAGS_DESCRDIR)
+        if not descrdir:
+            descrdir = "suse/setup/descr"
+        (filename, filechksum) = self.find('packages.gz')
+        if not filename:
+            (filename, filechksum) = self.find('packages')
+        if filename:
+            f = self.download(descrdir + '/' + filename, True, filechksum, True)
+            if f:
+                self.handle.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE|solv.Repo.SUSETAGS_RECORD_SHARES)
+                (filename, filechksum) = self.find('packages.en.gz')
+                if not filename:
+                    (filename, filechksum) = self.find('packages.en')
+                if filename:
+                    f = self.download(descrdir + '/' + filename, True, filechksum, True)
+                    if f:
+                        self.handle.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE|solv.Repo.REPO_REUSE_REPODATA|solv.Repo.REPO_EXTEND_SOLVABLES)
+                self.handle.internalize()
+        self.add_exts()
+        self.writecachedrepo(None)
+        # must be called after writing the repo
+        self.handle.create_stubs()
+        return True
+
+    def find(self, what):
+        di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, what, solv.Dataiterator.SEARCH_STRING)
+        di.prepend_keyname(solv.SUSETAGS_FILE)
+        for d in di:
+            dp = d.parentpos()
+            chksum = dp.lookup_checksum(solv.SUSETAGS_FILE_CHECKSUM)
+            return (what, chksum)
+        return (None, None)
+
+    def add_ext(self, repodata, what, ext):
+        (filename, chksum) = self.find(what)
+        if not filename:
+            return
+        handle = repodata.new_handle()
+        repodata.set_str(handle, solv.SUSETAGS_FILE_NAME, filename)
+        if chksum:
+            repodata.set_checksum(handle, solv.SUSETAGS_FILE_CHECKSUM, chksum)
+        self.add_ext_keys(ext, repodata, handle)
+        repodata.add_flexarray(solv.SOLVID_META, solv.REPOSITORY_EXTERNAL, handle)
+        
+    def add_exts(self):
+        repodata = self.handle.add_repodata(0)
+        di = self.handle.Dataiterator_meta(solv.SUSETAGS_FILE_NAME, None, 0)
+        di.prepend_keyname(solv.SUSETAGS_FILE)
+        for d in di:
+            filename = d.str
+            if not filename:
+                continue
+            if filename[0:9] != "packages.":
+                continue
+            if len(filename) == 11 and filename != "packages.gz":
+                ext = filename[9:11]
+            elif filename[11:12] == ".":
+                ext = filename[9:11]
+            else:
+                continue
+            if ext == "en":
+                continue
+            self.add_ext(repodata, filename, ext)
+        repodata.internalize()
+
+    def load_ext(self, repodata):
+        filename = repodata.lookup_str(solv.SOLVID_META, solv.SUSETAGS_FILE_NAME)
+        ext = filename[9:11]
+        sys.stdout.write("[%s:%s: " % (self.name, ext))
+        if self.usecachedrepo(ext):
+            sys.stdout.write("cached]\n")
+            sys.stdout.flush()
+            return True
+        sys.stdout.write("fetching]\n")
+        sys.stdout.flush()
+        defvendorid = self.handle.meta.lookup_id(solv.SUSETAGS_DEFAULTVENDOR)
+        descrdir = self.handle.meta.lookup_str(solv.SUSETAGS_DESCRDIR)
+        if not descrdir:
+            descrdir = "suse/setup/descr"
+        filechksum = repodata.lookup_checksum(solv.SOLVID_META, solv.SUSETAGS_FILE_CHECKSUM)
+        f = self.download(descrdir + '/' + filename, True, filechksum)
+        if not f:
+            return False
+        flags = solv.Repo.REPO_USE_LOADING|solv.Repo.REPO_EXTEND_SOLVABLES
+        if ext != 'DL':
+            flags |= solv.Repo.REPO_LOCALPOOL
+        self.handle.add_susetags(f, defvendorid, ext, flags)
+        self.writecachedrepo(ext, repodata)
+        return True
+
+    def packagespath(self):
+        datadir = repo.handle.meta.lookup_str(solv.SUSETAGS_DATADIR)
+        if not datadir:
+            datadir = 'suse'
+        return datadir + '/'
+
+class repo_unknown(repo_generic):
+    def load(self, pool):
+        print("unsupported repo '%s': skipped" % self.name)
+        return False
+
+class repo_system(repo_generic):
+    def load(self, pool):
+        self.handle = pool.add_repo(self.name)
+        self.handle.appdata = self
+        pool.installed = self.handle
+        sys.stdout.write("rpm database: ")
+        self['cookie'] = self.calc_cookie_file("/var/lib/rpm/Packages")
+        if self.usecachedrepo(None):
+            print("cached")
+            return True
+        print("reading")
+        if hasattr(self.handle.__class__, 'add_products'):
+            self.handle.add_products("/etc/products.d", solv.Repo.REPO_NO_INTERNALIZE)
+        f = solv.xfopen(self.cachepath())
+        self.handle.add_rpmdb_reffp(f, solv.Repo.REPO_REUSE_REPODATA)
+        self.writecachedrepo(None)
+        return True
+
+class repo_cmdline(repo_generic):
+    def load(self, pool):
+        self.handle = pool.add_repo(self.name)
+        self.handle.appdata = self 
+        return True
+
+def load_stub(repodata):
+    repo = repodata.repo.appdata
+    if repo:
+        return repo.load_ext(repodata)
+    return False
+
+
+parser = OptionParser(usage="usage: solv.py [options] COMMAND")
+parser.add_option('-r', '--repo', action="append", type="string", dest="repos", help="limit to specified repositories")
+parser.add_option('--best', action="store_true", dest="best", help="force installation/update to best packages")
+parser.add_option('--clean', action="store_true", dest="clean", help="delete no longer needed packages")
+(options, args) = parser.parse_args()
+if not args:
+    parser.print_help(sys.stderr)
+    sys.exit(1)
+
+cmd = args[0]
+args = args[1:]
+
+cmdabbrev = {'ls': 'list', 'in': 'install', 'rm': 'erase', 've': 'verify', 'se': 'search'}
+if cmd in cmdabbrev:
+    cmd = cmdabbrev[cmd]
+
+cmdactionmap = {
+  'install': solv.Job.SOLVER_INSTALL,
+  'erase':   solv.Job.SOLVER_ERASE,
+  'up':      solv.Job.SOLVER_UPDATE,
+  'dup':     solv.Job.SOLVER_DISTUPGRADE,
+  'verify':  solv.Job.SOLVER_VERIFY,
+  'list':    0,
+  'info':    0
+}
+
+# read all repo configs
+repos = []
+reposdirs = []
+if os.path.isdir("/etc/zypp/repos.d"):
+  reposdirs = [ "/etc/zypp/repos.d" ]
+else:
+  reposdirs = [ "/etc/yum/repos.d" ]
+
+for reposdir in reposdirs:
+    if not os.path.isdir(reposdir):
+        continue
+    for reponame in sorted(glob.glob('%s/*.repo' % reposdir)):
+        cfg = INIConfig(open(reponame))
+        for alias in cfg:
+            repoattr = {'enabled': 0, 'priority': 99, 'autorefresh': 1, 'type': 'rpm-md', 'metadata_expire': 900}
+            for k in cfg[alias]:
+                repoattr[k] = cfg[alias][k]
+            if 'mirrorlist' in repoattr and 'metalink' not in repoattr:
+                if repoattr['mirrorlist'].find('/metalink'):
+                    repoattr['metalink'] = repoattr['mirrorlist']
+                    del repoattr['mirrorlist']
+            if repoattr['type'] == 'rpm-md':
+                repo = repo_repomd(alias, 'repomd', repoattr)
+            elif repoattr['type'] == 'yast2':
+                repo = repo_susetags(alias, 'susetags', repoattr)
+            else:
+                repo = repo_unknown(alias, 'unknown', repoattr)
+            repos.append(repo)
+
+pool = solv.Pool()
+pool.setarch()
+pool.set_loadcallback(load_stub)
+
+# now load all enabled repos into the pool
+sysrepo = repo_system('@System', 'system')
+sysrepo.load(pool)
+for repo in repos:
+    if int(repo['enabled']):
+        repo.load(pool)
+    
+repofilter = None
+if options.repos:
+    for reponame in options.repos:
+        mrepos = [ repo for repo in repos if repo.name == reponame ]
+        if not mrepos:
+            print("no repository matches '%s'" % reponame)
+            sys.exit(1)
+        repo = mrepos[0]
+        if hasattr(repo, 'handle'):
+            if not repofilter:
+                repofilter = pool.Selection()
+            repofilter.add(repo.handle.Selection(solv.Job.SOLVER_SETVENDOR))
+
+if cmd == 'search':
+    pool.createwhatprovides()
+    sel = pool.Selection()
+    di = pool.Dataiterator(solv.SOLVABLE_NAME, args[0], solv.Dataiterator.SEARCH_SUBSTRING|solv.Dataiterator.SEARCH_NOCASE)
+    for d in di:
+        sel.add_raw(solv.Job.SOLVER_SOLVABLE, d.solvid)
+    if repofilter:
+       sel.filter(repofilter)
+    for s in sel.solvables():
+        print(" - %s [%s]: %s" % (s, s.repo.name, s.lookup_str(solv.SOLVABLE_SUMMARY)))
+    sys.exit(0)
+
+if cmd not in cmdactionmap:
+    print("unknown command %s" % cmd)
+    sys.exit(1)
+
+cmdlinerepo = None
+if cmd == 'list' or cmd == 'info' or cmd == 'install':
+    for arg in args:
+        if arg.endswith(".rpm") and os.access(arg, os.R_OK):
+            if not cmdlinerepo:
+                cmdlinerepo = repo_cmdline('@commandline', 'cmdline')
+                cmdlinerepo.load(pool)
+                cmdlinerepo['packages'] = {}
+            s = cmdlinerepo.handle.add_rpm(arg, solv.Repo.REPO_REUSE_REPODATA|solv.Repo.REPO_NO_INTERNALIZE)
+            if not s:
+                print(pool.errstr)
+                sys.exit(1)
+            cmdlinerepo['packages'][arg] = s
+    if cmdlinerepo:
+        cmdlinerepo.handle.internalize()
+
+addedprovides = pool.addfileprovides_queue()
+if addedprovides:
+    sysrepo.updateaddedprovides(addedprovides)
+    for repo in repos:
+        repo.updateaddedprovides(addedprovides)
+
+pool.createwhatprovides()
+
+# convert arguments into jobs
+jobs = []
+for arg in args:
+    if cmdlinerepo and arg in cmdlinerepo['packages']:
+        jobs.append(pool.Job(solv.Job.SOLVER_SOLVABLE, cmdlinerepo['packages'][arg].id))
+    else:
+        flags = solv.Selection.SELECTION_NAME|solv.Selection.SELECTION_PROVIDES|solv.Selection.SELECTION_GLOB
+        flags |= solv.Selection.SELECTION_CANON|solv.Selection.SELECTION_DOTARCH|solv.Selection.SELECTION_REL
+        if len(arg) and arg[0] == '/':
+            flags |= solv.Selection.SELECTION_FILELIST
+            if cmd == 'erase':
+                flags |= solv.Selection.SELECTION_INSTALLED_ONLY
+        sel = pool.select(arg, flags)
+        if repofilter:
+           sel.filter(repofilter)
+        if sel.isempty():
+            sel = pool.select(arg, flags | solv.Selection.SELECTION_NOCASE)
+            if repofilter:
+               sel.filter(repofilter)
+            if not sel.isempty():
+                print("[ignoring case for '%s']" % arg)
+        if sel.isempty():
+            print("nothing matches '%s'" % arg)
+            sys.exit(1)
+        if sel.flags & solv.Selection.SELECTION_FILELIST:
+            print("[using file list match for '%s']" % arg)
+        if sel.flags & solv.Selection.SELECTION_PROVIDES:
+            print("[using capability match for '%s']" % arg)
+        jobs += sel.jobs(cmdactionmap[cmd])
+
+if not jobs and (cmd == 'up' or cmd == 'dup' or cmd == 'verify' or repofilter):
+    sel = pool.Selection_all()
+    if repofilter:
+       sel.filter(repofilter)
+    jobs += sel.jobs(cmdactionmap[cmd])
+
+if not jobs:
+    print("no package matched.")
+    sys.exit(1)
+
+if cmd == 'list' or cmd == 'info':
+    for job in jobs:
+        for s in job.solvables():
+            if cmd == 'info':
+                print("Name:        %s" % s)
+                print("Repo:        %s" % s.repo)
+                print("Summary:     %s" % s.lookup_str(solv.SOLVABLE_SUMMARY))
+                str = s.lookup_str(solv.SOLVABLE_URL)
+                if str:
+                    print("Url:         %s" % str)
+                str = s.lookup_str(solv.SOLVABLE_LICENSE)
+                if str:
+                    print("License:     %s" % str)
+                print("Description:\n%s" % s.lookup_str(solv.SOLVABLE_DESCRIPTION))
+                print('')
+            else:
+                print("  - %s [%s]" % (s, s.repo))
+                print("    %s" % s.lookup_str(solv.SOLVABLE_SUMMARY))
+    sys.exit(0)
+
+# up magic: use install instead of update if no installed package matches
+for job in jobs:
+    if cmd == 'up' and job.isemptyupdate():
+        job.how ^= solv.Job.SOLVER_UPDATE ^ solv.Job.SOLVER_INSTALL
+    if options.best:
+        job.how |= solv.Job.SOLVER_FORCEBEST
+    if options.clean:
+        job.how |= solv.Job.SOLVER_CLEANDEPS
+
+#pool.set_debuglevel(2)
+solver = pool.Solver()
+solver.set_flag(solv.Solver.SOLVER_FLAG_SPLITPROVIDES, 1);
+if cmd == 'erase':
+    solver.set_flag(solv.Solver.SOLVER_FLAG_ALLOW_UNINSTALL, 1);
+
+while True:
+    problems = solver.solve(jobs)
+    if not problems:
+        break
+    for problem in problems:
+        print("Problem %d/%d:" % (problem.id, len(problems)))
+        print(problem)
+        solutions = problem.solutions()
+        for solution in solutions:
+            print("  Solution %d:" % solution.id)
+            elements = solution.elements(True)
+            for element in elements:
+                print("  - %s" % element.str())
+            print('')
+        sol = ''
+        while not (sol == 's' or sol == 'q' or (sol.isdigit() and int(sol) >= 1 and int(sol) <= len(solutions))):
+            sys.stdout.write("Please choose a solution: ")
+            sys.stdout.flush()
+            sol = sys.stdin.readline().strip()
+        if sol == 's':
+            continue        # skip problem
+        if sol == 'q':
+            sys.exit(1)
+        solution = solutions[int(sol) - 1]
+        for element in solution.elements():
+            newjob = element.Job()
+            if element.type == solv.Solver.SOLVER_SOLUTION_JOB:
+                jobs[element.jobidx] = newjob
+            else:
+                if newjob and newjob not in jobs:
+                    jobs.append(newjob)
+                    
+# no problems, show transaction
+trans = solver.transaction()
+del solver
+if trans.isempty():
+    print("Nothing to do.")
+    sys.exit(0)
+print('')
+print("Transaction summary:")
+print('')
+for cl in trans.classify(solv.Transaction.SOLVER_TRANSACTION_SHOW_OBSOLETES | solv.Transaction.SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE):
+    if cl.type == solv.Transaction.SOLVER_TRANSACTION_ERASE:
+        print("%d erased packages:" % cl.count)
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_INSTALL:
+        print("%d installed packages:" % cl.count)
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_REINSTALLED:
+        print("%d reinstalled packages:" % cl.count)
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_DOWNGRADED:
+        print("%d downgraded packages:" % cl.count)
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_CHANGED:
+        print("%d changed packages:" % cl.count)
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_UPGRADED:
+        print("%d upgraded packages:" % cl.count)
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_VENDORCHANGE:
+        print("%d vendor changes from '%s' to '%s':" % (cl.count, cl.fromstr, cl.tostr))
+    elif cl.type == solv.Transaction.SOLVER_TRANSACTION_ARCHCHANGE:
+        print("%d arch changes from '%s' to '%s':" % (cl.count, cl.fromstr, cl.tostr))
+    else:
+        continue
+    for p in cl.solvables():
+        if cl.type == solv.Transaction.SOLVER_TRANSACTION_UPGRADED or cl.type == solv.Transaction.SOLVER_TRANSACTION_DOWNGRADED:
+            op = trans.othersolvable(p)
+            print("  - %s -> %s" % (p, op))
+        else:
+            print("  - %s" % p)
+    print('')
+print("install size change: %d K" % trans.calc_installsizechange())
+print('')
+
+while True:
+    sys.stdout.write("OK to continue (y/n)? ")
+    sys.stdout.flush()
+    yn = sys.stdin.readline().strip()
+    if yn == 'y': break
+    if yn == 'n' or yn == 'q': sys.exit(1)
+newpkgs = trans.newsolvables()
+newpkgsfp = {}
+if newpkgs:
+    downloadsize = 0
+    for p in newpkgs:
+        downloadsize += p.lookup_num(solv.SOLVABLE_DOWNLOADSIZE)
+    print("Downloading %d packages, %d K" % (len(newpkgs), downloadsize / 1024))
+    for p in newpkgs:
+        repo = p.repo.appdata
+        location, medianr = p.lookup_location()
+        if not location:
+            continue
+        if repo.type == 'commandline':
+            f = solv.xfopen(location)
+            if not f:
+                sys.exit("\n%s: %s not found" % location)
+            newpkgsfp[p.id] = f
+            continue
+        if not sysrepo.handle.isempty() and os.access('/usr/bin/applydeltarpm', os.X_OK):
+            pname = p.name
+            di = p.repo.Dataiterator_meta(solv.DELTA_PACKAGE_NAME, pname, solv.Dataiterator.SEARCH_STRING)
+            di.prepend_keyname(solv.REPOSITORY_DELTAINFO)
+            for d in di:
+                dp = d.parentpos()
+                if dp.lookup_id(solv.DELTA_PACKAGE_EVR) != p.evrid or dp.lookup_id(solv.DELTA_PACKAGE_ARCH) != p.archid:
+                    continue
+                baseevrid = dp.lookup_id(solv.DELTA_BASE_EVR)
+                candidate = None
+                for installedp in pool.whatprovides(p.nameid):
+                    if installedp.isinstalled() and installedp.nameid == p.nameid and installedp.archid == p.archid and installedp.evrid == baseevrid:
+                        candidate = installedp
+                if not candidate:
+                    continue
+                seq = dp.lookup_deltaseq()
+                st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, '-c', '-s', seq])
+                if st:
+                    continue
+                chksum = dp.lookup_checksum(solv.DELTA_CHECKSUM)
+                if not chksum:
+                    continue
+                dloc, dmedianr = dp.lookup_deltalocation()
+                dloc = repo.packagespath() + dloc
+                f = repo.download(dloc, False, chksum)
+                if not f:
+                    continue
+                nf = tempfile.TemporaryFile()
+                nf = os.dup(nf.fileno())   # get rid of CLOEXEC
+                f.cloexec(0)
+                st = subprocess.call(['/usr/bin/applydeltarpm', '-a', p.arch, "/dev/fd/%d" % f.fileno(), "/dev/fd/%d" % nf])
+                if st:
+                    os.close(nf)
+                    continue
+                os.lseek(nf, 0, os.SEEK_SET)
+                newpkgsfp[p.id] = solv.xfopen_fd("", nf)
+                os.close(nf)
+                break
+            if p.id in newpkgsfp:
+                sys.stdout.write("d")
+                sys.stdout.flush()
+                continue
+                    
+        chksum = p.lookup_checksum(solv.SOLVABLE_CHECKSUM)
+        location = repo.packagespath() + location
+        f = repo.download(location, False, chksum)
+        if not f:
+            sys.exit("\n%s: %s not found in repository" % (repo.name, location))
+        newpkgsfp[p.id] = f
+        sys.stdout.write(".")
+        sys.stdout.flush()
+    print('')
+print("Committing transaction:")
+print('')
+ts = rpm.TransactionSet('/')
+ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
+erasenamehelper = {}
+for p in trans.steps():
+    type = trans.steptype(p, solv.Transaction.SOLVER_TRANSACTION_RPM_ONLY)
+    if type == solv.Transaction.SOLVER_TRANSACTION_ERASE:
+        rpmdbid = p.lookup_num(solv.RPM_RPMDBID)
+        erasenamehelper[p.name] = p
+        if not rpmdbid:
+            sys.exit("\ninternal error: installed package %s has no rpmdbid\n" % p)
+        ts.addErase(rpmdbid)
+    elif type == solv.Transaction.SOLVER_TRANSACTION_INSTALL:
+        f = newpkgsfp[p.id]
+        h = ts.hdrFromFdno(f.fileno())
+        os.lseek(f.fileno(), 0, os.SEEK_SET)
+        ts.addInstall(h, p, 'u')
+    elif type == solv.Transaction.SOLVER_TRANSACTION_MULTIINSTALL:
+        f = newpkgsfp[p.id]
+        h = ts.hdrFromFdno(f.fileno())
+        os.lseek(f.fileno(), 0, os.SEEK_SET)
+        ts.addInstall(h, p, 'i')
+checkproblems = ts.check()
+if checkproblems:
+    print(checkproblems)
+    sys.exit("Sorry.")
+ts.order()
+def runCallback(reason, amount, total, p, d):
+    if reason == rpm.RPMCALLBACK_INST_OPEN_FILE:
+        return newpkgsfp[p.id].fileno()
+    if reason == rpm.RPMCALLBACK_INST_START:
+        print("install %s" % p)
+    if reason == rpm.RPMCALLBACK_UNINST_START:
+        # argh, p is just the name of the package
+        if p in erasenamehelper:
+            p = erasenamehelper[p]
+            print("erase %s" % p)
+runproblems = ts.run(runCallback, '')
+if runproblems:
+    print(runproblems)
+    sys.exit(1)
+sys.exit(0)
+
+# vim: sw=4 et
diff --git a/libsolv-0.7.2/examples/rbsolv b/libsolv-0.7.2/examples/rbsolv
new file mode 100755 (executable)
index 0000000..87f0d16
--- /dev/null
@@ -0,0 +1,763 @@
+#!/usr/bin/ruby
+
+require 'solv'
+require 'rubygems'
+require 'inifile'
+require 'tempfile'
+
+class Repo_generic
+  def initialize(name, type, attribs = {})
+    @name = name
+    @type = type
+    @attribs = attribs.dup
+    @incomplete = false
+  end
+
+  def enabled?
+    return @attribs['enabled'].to_i != 0
+  end
+
+  def autorefresh?
+    return @attribs['autorefresh'].to_i != 0
+  end
+
+  def id
+    return @handle ? @handle.id : 0
+  end
+
+  def calc_cookie_fp(f)
+    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
+    chksum.add("1.1")
+    chksum.add_fp(f)
+    return chksum.raw
+  end
+
+  def calc_cookie_file(filename)
+    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
+    chksum.add("1.1")
+    chksum.add_stat(filename)
+    return chksum.raw
+  end
+
+  def calc_cookie_ext(f, cookie)
+    chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
+    chksum.add("1.1")
+    chksum.add(cookie)
+    chksum.add_fstat(f.fileno)
+    return chksum.raw()
+  end
+
+  def cachepath(ext = nil)
+    path = @name.sub(/^\./, '_')
+    path += ext ? "_#{ext}.solvx" : '.solv'
+    return '/var/cache/solv/' + path.gsub(/\//, '_')
+  end
+
+  def load(pool)
+    @handle = pool.add_repo(@name)
+    @handle.appdata = self
+    @handle.priority = 99 - @attribs['priority'].to_i if @attribs['priority']
+    dorefresh = autorefresh?
+    if dorefresh
+      begin
+       s = File.stat(cachepath)
+       dorefresh = false if s && (@attribs['metadata_expire'].to_i == -1 || Time.now - s.mtime < @attribs['metadata_expire'].to_i)
+      rescue SystemCallError
+      end
+    end
+    @cookie = nil
+    @extcookie = nil
+    if !dorefresh && usecachedrepo(nil)
+      puts "repo: '#{@name}' cached"
+      return true
+    end
+    return false
+  end
+
+  def load_ext(repodata)
+    return false
+  end
+
+  def download(file, uncompress, chksum, markincomplete = false)
+    url = @attribs['baseurl']
+    if !url
+      puts "%{@name}: no baseurl"
+      return nil
+    end
+    url = url.sub(/\/$/, '') + "/#{file}"
+    f =  Tempfile.new('rbsolv')
+    f.unlink
+    st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" + f.fileno.to_s, '--', url)
+    return nil if f.stat.size == 0 && (st || !chksum)
+    if !st
+       puts "#{file}: download error #{$? >> 8}"
+       @incomplete = true if markincomplete
+       return nil
+    end
+    if chksum
+      fchksum = Solv::Chksum.new(chksum.type)
+      fchksum.add_fd(f.fileno)
+      if !fchksum == chksum
+       puts "#{file}: checksum error"
+       @incomplete = true if markincomplete
+       return nil
+      end
+    end
+    rf = nil
+    if uncompress
+      rf = Solv::xfopen_fd(file, f.fileno)
+    else
+      rf = Solv::xfopen_fd('', f.fileno)
+    end
+    f.close
+    return rf
+  end
+
+  def usecachedrepo(ext, mark = false)
+    cookie = ext ? @extcookie : @cookie
+    begin
+      repopath = cachepath(ext)
+      f = File.new(repopath, "r")
+      f.sysseek(-32, IO::SEEK_END)
+      fcookie = f.sysread(32)
+      return false if fcookie.length != 32
+      return false if cookie && fcookie != cookie
+      if !ext && @type != 'system'
+       f.sysseek(-32 * 2, IO::SEEK_END)
+       fextcookie = f.sysread(32)
+       return false if fextcookie.length != 32
+      end
+      f.sysseek(0, IO::SEEK_SET)
+      nf = Solv::xfopen_fd('', f.fileno)
+      f.close
+      flags = ext ? Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES : 0
+      flags |= Solv::Repo::REPO_LOCALPOOL if ext && ext != 'DL'
+      if ! @handle.add_solv(nf, flags)
+       nf.close
+       return false
+      end
+      nf.close()
+      @cookie = fcookie unless ext
+      @extcookie = fextcookie if !ext && @type != 'system'
+      now = Time.now
+      begin
+       File::utime(now, now, repopath) if mark
+      rescue SystemCallError
+      end
+      return true
+    rescue SystemCallError
+      return false
+    end
+    return true
+  end
+
+  def writecachedrepo(ext, repodata = nil)
+    return if @incomplete
+    begin
+      Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv")
+      f =  Tempfile.new('.newsolv-', '/var/cache/solv')
+      f.chmod(0444)
+      sf = Solv::xfopen_fd('', f.fileno)
+      if !repodata
+       @handle.write(sf)
+      elsif ext
+       repodata.write(sf)
+      else
+       @handle.write_first_repodata(sf)
+      end
+      sf.close
+      f.sysseek(0, IO::SEEK_END)
+      if @type != 'system' && !ext
+       @extcookie = calc_cookie_ext(f, @cookie) unless @extcookie
+       f.syswrite(@extcookie)
+      end
+      f.syswrite(ext ? @extcookie : @cookie)
+      f.close
+      if @handle.iscontiguous?
+       sf = Solv::xfopen(f.path)
+       if sf
+         if !ext
+           @handle.empty()
+           abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, repodata ? 0 : Solv::Repo::SOLV_ADD_NO_STUBS)
+         else
+           repodata.extend_to_repo()
+           flags = Solv::Repo::REPO_EXTEND_SOLVABLES
+           flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL'
+           repodata.add_solv(sf, flags)
+         end
+         sf.close
+       end
+      end
+      File.rename(f.path, cachepath(ext))
+      f.unlink
+      return true
+    rescue SystemCallError
+      return false
+    end
+  end
+
+  def updateaddedprovides(addedprovides)
+    return if @incomplete
+    return unless @handle && !@handle.isempty?
+    repodata = @handle.first_repodata()
+    return unless repodata
+    oldaddedprovides = repodata.lookup_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES)
+    return if (oldaddedprovides | addedprovides) == oldaddedprovides
+    for id in addedprovides
+      repodata.add_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES, id)
+    end
+    repodata.internalize()
+    writecachedrepo(nil, repodata)
+  end
+
+  def packagespath()
+    return ''
+  end
+
+  @@langtags = {
+    Solv::SOLVABLE_SUMMARY     => Solv::REPOKEY_TYPE_STR,
+    Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR,
+    Solv::SOLVABLE_EULA        => Solv::REPOKEY_TYPE_STR,
+    Solv::SOLVABLE_MESSAGEINS  => Solv::REPOKEY_TYPE_STR,
+    Solv::SOLVABLE_MESSAGEDEL  => Solv::REPOKEY_TYPE_STR,
+    Solv::SOLVABLE_CATEGORY    => Solv::REPOKEY_TYPE_ID,
+  }
+
+  def add_ext_keys(ext, repodata, h)
+    if ext == 'DL'
+      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
+      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
+    elsif ext == 'DU'
+      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE)
+      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY)
+    elsif ext == 'FL'
+      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
+      repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
+    else
+      @@langtags.sort.each do |langid, langtype|
+       repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true))
+       repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype)
+      end
+    end
+  end
+end
+
+class Repo_rpmmd < Repo_generic
+
+  def find(what)
+    di = @handle.Dataiterator_meta(Solv::REPOSITORY_REPOMD_TYPE, what, Solv::Dataiterator::SEARCH_STRING)
+    di.prepend_keyname(Solv::REPOSITORY_REPOMD)
+    for d in di
+      dp = d.parentpos()
+      filename = dp.lookup_str(Solv::REPOSITORY_REPOMD_LOCATION)
+      next unless filename
+      checksum = dp.lookup_checksum(Solv::REPOSITORY_REPOMD_CHECKSUM)
+      if !checksum
+       puts "no #{filename} checksum!"
+       return nil, nil
+      end
+      return filename, checksum
+    end
+    return nil, nil
+  end
+
+  def load(pool)
+    return true if super(pool)
+    print "rpmmd repo '#{@name}: "
+    f = download("repodata/repomd.xml", false, nil, nil)
+    if !f
+      puts "no repomd.xml file, skipped"
+      @handle.free(true)
+      @handle = nil
+      return false
+    end
+    @cookie = calc_cookie_fp(f)
+    if usecachedrepo(nil, true)
+      puts "cached"
+      f.close
+      return true
+    end
+    @handle.add_repomdxml(f, 0)
+    f.close
+    puts "fetching"
+    filename, filechksum = find('primary')
+    if filename
+      f = download(filename, true, filechksum, true)
+      if f
+       @handle.add_rpmmd(f, nil, 0)
+       f.close
+      end
+      return false if @incomplete
+    end
+    filename, filechksum = find('updateinfo')
+    if filename
+      f = download(filename, true, filechksum, true)
+      if f
+       @handle.add_updateinfoxml(f, 0)
+       f.close
+      end
+    end
+    add_exts()
+    writecachedrepo(nil)
+    @handle.create_stubs()
+    return true
+  end
+
+  def add_ext(repodata, what, ext)
+    filename, filechksum = find(what)
+    filename, filechksum = find('prestodelta') if !filename && what == 'deltainfo'
+    return unless filename
+    h = repodata.new_handle()
+    repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what)
+    repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename)
+    repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum)
+    add_ext_keys(ext, repodata, h)
+    repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
+  end
+
+  def add_exts
+    repodata = @handle.add_repodata(0)
+    repodata.extend_to_repo()
+    add_ext(repodata, 'deltainfo', 'DL')
+    add_ext(repodata, 'filelists', 'FL')
+    repodata.internalize()
+  end
+
+  def load_ext(repodata)
+    repomdtype = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE)
+    if repomdtype == 'filelists'
+      ext = 'FL'
+    elsif repomdtype == 'deltainfo'
+      ext = 'DL'
+    else
+      return false
+    end
+    print "[#{@name}:#{ext}: "
+    STDOUT.flush
+    if usecachedrepo(ext)
+      puts "cached]\n"
+      return true
+    end
+    puts "fetching]\n"
+    filename = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_LOCATION)
+    filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_CHECKSUM)
+    f = download(filename, true, filechksum)
+    return false unless f
+    if ext == 'FL'
+      @handle.add_rpmmd(f, 'FL', Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES|Solv::Repo::REPO_LOCALPOOL)
+    elsif ext == 'DL'
+      @handle.add_deltainfoxml(f, Solv::Repo::REPO_USE_LOADING)
+    end
+    f.close
+    writecachedrepo(ext, repodata)
+    return true
+  end
+
+end
+
+class Repo_susetags < Repo_generic
+
+  def find(what)
+    di = @handle.Dataiterator_meta(Solv::SUSETAGS_FILE_NAME, what, Solv::Dataiterator::SEARCH_STRING)
+    di.prepend_keyname(Solv::SUSETAGS_FILE)
+    for d in di
+      dp = d.parentpos()
+      checksum = dp.lookup_checksum(Solv::SUSETAGS_FILE_CHECKSUM)
+      return what, checksum
+    end
+    return nil, nil
+  end
+
+  def load(pool)
+    return true if super(pool)
+    print "susetags repo '#{@name}: "
+    f = download("content", false, nil, nil)
+    if !f
+      puts "no content file, skipped"
+      @handle.free(true)
+      @handle = nil
+      return false
+    end
+    @cookie = calc_cookie_fp(f)
+    if usecachedrepo(nil, true)
+      puts "cached"
+      f.close
+      return true
+    end
+    @handle.add_content(f, 0)
+    f.close
+    puts "fetching"
+    defvendorid = @handle.meta.lookup_id(Solv::SUSETAGS_DEFAULTVENDOR)
+    descrdir = @handle.meta.lookup_str(Solv::SUSETAGS_DESCRDIR)
+    descrdir = "suse/setup/descr" unless descrdir
+    (filename, filechksum) = find('packages.gz')
+    (filename, filechksum) = find('packages') unless filename
+    if filename
+      f = download("#{descrdir}/#{filename}", true, filechksum, true)
+      if f
+       @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::SUSETAGS_RECORD_SHARES)
+       f.close
+       (filename, filechksum) = find('packages.en.gz')
+       (filename, filechksum) = find('packages.en') unless filename
+       if filename
+         f = download("#{descrdir}/#{filename}", true, filechksum, true)
+         if f
+           @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::REPO_REUSE_REPODATA|Solv::Repo::REPO_EXTEND_SOLVABLES)
+           f.close
+         end
+       end
+       @handle.internalize()
+      end
+    end
+    add_exts()
+    writecachedrepo(nil)
+    @handle.create_stubs()
+    return true
+  end
+
+  def add_ext(repodata, what, ext)
+    (filename, filechksum) = find(what)
+    h = repodata.new_handle()
+    repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename)
+    repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum)
+    add_ext_keys(ext, repodata, h)
+    repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
+  end
+
+  def add_exts
+    repodata = @handle.add_repodata(0)
+    di = @handle.Dataiterator_meta(Solv::SUSETAGS_FILE_NAME, nil, 0)
+    di.prepend_keyname(Solv::SUSETAGS_FILE)
+    for d in di
+      filename = d.str
+      next unless filename && filename =~ /^packages\.(..)(?:\..*)$/
+      next if $1 == 'en' || $1 == 'gz'
+      add_ext(repodata, filename, $1)
+    end
+    repodata.internalize()
+  end
+
+  def load_ext(repodata)
+    filename = repodata.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME)
+    ext = filename[9,2]
+    print "[#{@name}:#{ext}: "
+    STDOUT.flush
+    if usecachedrepo(ext)
+      puts "cached]\n"
+      return true
+    end
+    puts "fetching]\n"
+    defvendorid = @handle.meta.lookup_id(Solv::SUSETAGS_DEFAULTVENDOR)
+    descrdir = @handle.meta.lookup_str(Solv::SUSETAGS_DESCRDIR)
+    descrdir = "suse/setup/descr" unless descrdir
+    filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::SUSETAGS_FILE_CHECKSUM)
+    f = download("#{descrdir}/#{filename}", true, filechksum)
+    return false unless f
+    flags = Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES
+    flags |= Solv::Repo::REPO_LOCALPOOL if ext != 'DL'
+    @handle.add_susetags(f, defvendorid, ext, flags)
+    f.close
+    writecachedrepo(ext, repodata)
+    return true
+  end
+
+  def packagespath()
+    datadir = @handle.meta.lookup_str(Solv::SUSETAGS_DATADIR)
+    datadir = "suse" unless datadir
+    return datadir + '/'
+  end
+end
+
+class Repo_unknown < Repo_generic
+  def load(pool)
+    puts "unsupported repo '#{@name}: skipped"
+    return false
+  end
+end
+
+class Repo_system < Repo_generic
+  def load(pool)
+    @handle = pool.add_repo(@name)
+    @handle.appdata = self
+    pool.installed = @handle
+    print "rpm database: "
+    @cookie = calc_cookie_file("/var/lib/rpm/Packages")
+    if usecachedrepo(nil)
+      puts "cached"
+      return true
+    end
+    puts "reading"
+    if @handle.respond_to? :add_products
+      @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
+    end
+    f = Solv::xfopen(cachepath())
+    @handle.add_rpmdb_reffp(f, Solv::Repo::REPO_REUSE_REPODATA)
+    f.close if f
+    writecachedrepo(nil)
+    return true
+  end
+end
+
+args = ARGV
+cmd = args.shift
+
+cmdabbrev = { 'ls' => 'list', 'in' => 'install', 'rm' => 'erase',
+              've' => 'verify', 'se' => 'search' }
+cmd = cmdabbrev[cmd] if cmdabbrev.has_key?(cmd)
+
+cmdactionmap = { 
+  'install' => Solv::Job::SOLVER_INSTALL,
+  'erase'   => Solv::Job::SOLVER_ERASE,
+  'up'      => Solv::Job::SOLVER_UPDATE,
+  'dup'     => Solv::Job::SOLVER_DISTUPGRADE,
+  'verify'  => Solv::Job::SOLVER_VERIFY,
+  'list'    => 0,  
+  'info'    => 0,
+}
+
+repos = []
+reposdirs = []
+if FileTest.directory?('/etc/zypp/repos.d')
+  reposdirs = [ '/etc/zypp/repos.d' ]
+else
+  reposdirs = [ '/etc/yum/repos.d' ]
+end
+for reposdir in reposdirs do
+  next unless FileTest.directory?(reposdir)
+  for reponame in Dir["#{reposdir}/*.repo"].sort do
+    cfg = IniFile.load(reponame)
+    cfg.each_section do |ali|
+      repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
+      repoattr.update(cfg[ali])
+      if repoattr['type'] == 'rpm-md'
+       repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
+      elsif repoattr['type'] == 'yast2'
+       repo = Repo_susetags.new(ali, 'susetags', repoattr)
+      else
+       repo = Repo_unknown.new(ali, 'unknown', repoattr)
+      end
+      repos.push(repo)
+    end
+  end
+end
+
+pool = Solv::Pool.new()
+pool.setarch()
+
+pool.set_loadcallback { |repodata|
+  repo = repodata.repo.appdata
+  repo ? repo.load_ext(repodata) : false
+}
+
+sysrepo = Repo_system.new('@System', 'system')
+sysrepo.load(pool)
+for repo in repos
+  repo.load(pool) if repo.enabled?
+end
+
+if cmd == 'search'
+  pool.createwhatprovides()
+  sel = pool.Selection
+  for di in pool.Dataiterator(Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
+    sel.add_raw(Solv::Job::SOLVER_SOLVABLE, di.solvid)
+  end
+  for s in sel.solvables
+    puts "- #{s.str} [#{s.repo.name}]: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
+  end
+  exit
+end
+
+abort("unknown command '#{cmd}'\n") unless cmdactionmap.has_key?(cmd)
+
+addedprovides = pool.addfileprovides_queue()
+if !addedprovides.empty?
+  sysrepo.updateaddedprovides(addedprovides)
+  for repo in repos
+    repo.updateaddedprovides(addedprovides)
+  end
+end
+pool.createwhatprovides()
+
+jobs = []
+for arg in args
+  flags = Solv::Selection::SELECTION_NAME | Solv::Selection::SELECTION_PROVIDES | Solv::Selection::SELECTION_GLOB
+  flags |= Solv::Selection::SELECTION_CANON | Solv::Selection::SELECTION_DOTARCH | Solv::Selection::SELECTION_REL
+  if arg =~ /^\//
+    flags |= Solv::Selection::SELECTION_FILELIST
+    flags |= Solv::Selection::SELECTION_INSTALLED_ONLY if cmd == 'erase'
+  end
+  sel = pool.select(arg, flags)
+  if sel.isempty?
+    sel = pool.select(arg, flags |  Solv::Selection::SELECTION_NOCASE)
+    puts "[ignoring case for '#{arg}']" unless sel.isempty?
+  end
+  puts "[using file list match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_FILELIST != 0
+  puts "[using capability match for '#{arg}']" if sel.flags & Solv::Selection::SELECTION_PROVIDES != 0
+  jobs += sel.jobs(cmdactionmap[cmd])
+end
+
+if jobs.empty? && (cmd == 'up' || cmd == 'dup' || cmd == 'verify')
+  sel = pool.Selection_all()
+  jobs += sel.jobs(cmdactionmap[cmd])
+end
+
+abort("no package matched.") if jobs.empty?
+
+if cmd == 'list' || cmd == 'info'
+  for job in jobs
+    for s in job.solvables()
+      if cmd == 'info'
+       puts "Name:        #{s.str}"
+       puts "Repo:        #{s.repo.name}"
+       puts "Summary:     #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
+       str = s.lookup_str(Solv::SOLVABLE_URL)
+       puts "Url:         #{str}" if str
+       str = s.lookup_str(Solv::SOLVABLE_LICENSE)
+       puts "License:     #{str}" if str
+       puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
+       puts
+      else
+       puts "  - #{s.str} [#{s.repo.name}]"
+       puts "    #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
+      end
+    end
+  end
+  exit
+end
+
+for job in jobs
+  job.how ^= Solv::Job::SOLVER_UPDATE ^ Solv::Job::SOLVER_INSTALL if cmd == 'up' and job.isemptyupdate?
+end
+
+solver = pool.Solver
+solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1)
+solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase'
+#pool.set_debuglevel(1)
+
+while true
+  problems = solver.solve(jobs)
+  break if problems.empty?
+  for problem in problems
+    puts "Problem #{problem.id}/#{problems.count}:"
+    puts problem
+    solutions = problem.solutions
+    for solution in solutions
+      puts "  Solution #{solution.id}:"
+      elements = solution.elements(true)
+      for element in elements
+       puts "  - #{element.str}"
+      end
+      puts
+    end
+    sol = nil
+    while true
+      print "Please choose a solution: "
+      STDOUT.flush
+      sol = STDIN.gets.strip
+      break if sol == 's' || sol == 'q'
+      break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length
+    end
+    next if sol == 's'
+    abort if sol == 'q'
+    solution = solutions[sol.to_i - 1]
+    for element in solution.elements
+      newjob = element.Job()
+      if element.type == Solv::Solver::SOLVER_SOLUTION_JOB
+       jobs[element.jobidx] = newjob
+      else
+       jobs.push(newjob) if newjob && !jobs.include?(newjob)
+      end
+    end
+  end
+end
+
+trans = solver.transaction
+solver = nil
+if trans.isempty?
+  puts "Nothing to do."
+  exit
+end
+
+puts "\nTransaction summary:\n"
+for cl in trans.classify(Solv::Transaction::SOLVER_TRANSACTION_SHOW_OBSOLETES | Solv::Transaction::SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE)
+  if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
+    puts "#{cl.count} erased packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
+    puts "#{cl.count} installed packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
+    puts "#{cl.count} reinstalled packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
+    puts "#{cl.count} downgraded packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
+    puts "#{cl.count} changed packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
+    puts "#{cl.count} upgraded packages:"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
+    puts "#{cl.count} vendor changes from '#{cl.fromstr}' to '#{cl.tostr}':"
+  elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
+    puts "#{cl.count} arch changes from '#{cl.fromstr}' to '#{cl.tostr}':"
+  else
+    next
+  end
+  for p in cl.solvables
+    if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
+      puts "  - #{p.str} -> #{trans.othersolvable(p).str}"
+    else
+      puts "  - #{p.str}"
+    end
+  end
+  puts
+end
+puts "install size change: #{trans.calc_installsizechange()} K\n\n"
+
+while true
+  print("OK to continue (y/n)? ")
+  STDOUT.flush
+  yn = STDIN.gets.strip
+  break if yn == 'y'
+  abort if yn == 'n' || yn == 'q'
+end
+
+newpkgs = trans.newsolvables()
+newpkgsfp = {}
+if !newpkgs.empty?
+  downloadsize = 0
+  for p in newpkgs
+    downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE)
+  end
+  puts "Downloading #{newpkgs.length} packages, #{downloadsize / 1024} K"
+  for p in newpkgs
+    repo = p.repo.appdata
+    location, medianr = p.lookup_location()
+    next unless location
+    location = repo.packagespath + location
+    chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM)
+    f = repo.download(location, false, chksum)
+    abort("\n#{@name}: #{location} not found in repository\n") unless f
+    newpkgsfp[p.id] = f
+    print "."
+    STDOUT.flush()
+  end
+  puts
+end
+
+puts "Committing transaction:"
+puts
+trans.order()
+for p in trans.steps
+  steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY)
+  if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE
+    puts "erase #{p.str}"
+    next unless p.lookup_num(Solv::RPM_RPMDBID)
+    evr = p.evr.sub(/^[0-9]+:/, '')
+    system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}") 
+  elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL)
+    puts "install #{p.str}"
+    f = newpkgsfp.delete(p.id)
+    next unless f
+    mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'
+    f.cloexec(0)
+    system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{f.fileno().to_s}") || abort("rpm failed: #{$? >> 8}")
+    f.close
+  end
+end
diff --git a/libsolv-0.7.2/examples/repo2solv.sh b/libsolv-0.7.2/examples/repo2solv.sh
new file mode 100755 (executable)
index 0000000..450b7fa
--- /dev/null
@@ -0,0 +1,303 @@
+#! /bin/sh
+# repo2solv
+#
+# this is a shell implementation of repo2solv that makes use of
+# the different parser utilities
+#
+# give it a directory of a local mirror of a repo and this
+# tries to detect the repo type and generate one SOLV file on stdout
+
+get_DESCRDIR () {
+  local d=$(grep '^DESCRDIR' content | sed 's/^DESCRDIR[[:space:]]\+\(.*[^[:space:]]\)[[:space:]]*$/\1/')
+  if  test -z "$d"; then
+    echo suse/setup/descr
+  else
+    echo ${d}
+  fi
+}
+
+test_susetags() {
+  if test -s content; then
+    DESCR=$(get_DESCRDIR)
+    test -d $DESCR
+    return $?
+  else
+    return 1
+  fi
+}
+
+repomd_findfile() {
+  local t=$1
+  local p=$2
+  local f
+  if test -n "$t" -a -s repomd.xml ; then
+    f=`repomdxml2solv -q "$t:location" < repomd.xml 2>/dev/null`
+    f=${f##*/}
+    if test -f "$f" ; then
+      echo "$f"
+      return
+    fi
+  fi
+  if test -f "$p.bz2" ; then
+    echo "$p.bz2"
+  elif test -f "$p.gz" ; then
+    echo "$p.gz"
+  elif test -f "$p" ; then
+    echo "$p"
+  fi
+}
+
+repomd_types() {
+  test -s repomd.xml && repomdxml2solv -q type < repomd.xml
+}
+
+repomd_decompress() {
+  case $1 in
+   *.gz) gzip -dc "$1" ;;
+   *.bz2) bzip2 -dc "$1" ;;
+   *.lzma) lzma -dc "$1" ;;
+   *.xz) xz -dc "$1" ;;
+   *) cat "$1" ;;
+  esac
+}
+
+susetags_findfile() {
+  if test -s "$1.xz" ; then
+    echo "$1.xz"
+  elif test -s "$1.lzma" ; then
+    echo "$1.lzma"
+  elif test -s "$1.bz2" ; then
+    echo "$1.bz2"
+  elif test -s "$1.gz" ; then
+    echo "$1.gz"
+  fi
+}
+
+susetags_findfile_cat() {
+  if test -s "$1.xz" ; then
+    xz -dc "$1.xz"
+  elif test -s "$1.lzma" ; then
+    lzma -dc "$1.lzma"
+  elif test -s "$1.bz2" ; then
+    bzip2 -dc "$1.bz2"
+  elif test -s "$1.gz" ; then
+    gzip -dc "$1.gz"
+  elif test -s "$1" ; then
+    cat "$1"
+  fi
+}
+
+# signal an error if there is a problem
+set -e
+
+LANG=C
+unset CDPATH
+parser_options=${PARSER_OPTIONS:-}
+
+findopt="-prune"
+repotype=
+addautooption=
+
+while true ; do
+  if test "$1" = "-o" ; then
+    exec > "$2"
+    shift
+    shift
+  elif test "$1" = "-R" ; then
+    # recursive
+    findopt=
+    repotype=plaindir
+    shift
+  elif test "$1" = "-X" ; then
+    addautooption=-X
+    shift
+  elif test "$1" = "-A" ; then
+    shift
+  else
+    break
+  fi
+done
+
+dir="$1"
+cd "$dir" || exit 1
+
+if test -z "$repotype" ; then
+  # autodetect repository type
+  if test -d repodata -o -f repomd.xml; then
+    repotype=rpmmd
+  elif test_susetags ; then
+    repotype=susetags
+  else
+    repotype=plaindir
+  fi
+fi
+
+if test "$repotype" = rpmmd ; then
+  test -d repodata && {
+    cd repodata || exit 2
+  }
+
+  primfile=
+  primxml=`repomd_findfile primary primary.xml`
+  if test -n "$primxml" -a -s "$primxml" ; then
+    primfile=`mktemp` || exit 3
+    (
+     # fake tag to combine primary.xml and extensions
+     # like susedata.xml, other.xml, filelists.xml
+     echo '<rpmmd>'
+     if test -f $primxml ; then
+       repomd_decompress $primxml
+         # add a newline
+        echo
+     fi
+     susedataxml=`repomd_findfile susedata susedata.xml`
+     if test -f "$susedataxml" ; then
+       repomd_decompress "$susedataxml"
+     fi
+     # all the languages as well
+     for t in `repomd_types` ; do
+       case "$t" in
+           susedata.*)
+               susedataxml=`repomd_findfile "$t" "$t.xml"`
+               if test -f "$susedataxml" ; then
+                   repomd_decompress "$susedataxml"
+               fi
+           ;;
+       esac
+     done
+     echo '</rpmmd>'
+    ) | sed 's/<?xml[^>]*>//g' | sed '1i\<?xml version="1.0" encoding="UTF-8"?>' | rpmmd2solv $parser_options > $primfile || exit 4
+  fi
+
+  prodfile=
+  prodxml=`repomd_findfile products products.xml`
+  if test -z "$prodxml" ; then
+    prodxml=`repomd_findfile product product.xml`
+  fi
+  if test -n "$prodxml" -a -s "$prodxml" ; then
+      prodfile=`mktemp` || exit 3
+      repomd_decompress "$prodxml" | rpmmd2solv $parser_options > $prodfile || exit 4
+  fi
+
+  patternfile=
+  patternxml=`repomd_findfile 'patterns' patterns.xml`
+  if test -n "$patternxml" -a -s "$patternxml" ; then
+      patternfile=`mktemp` || exit 3
+      repomd_decompress "$patternxml" | rpmmd2solv $parser_options > $patternfile || exit 4
+  fi
+
+  # This contains repomd.xml
+  # for now we only read some keys like timestamp
+  repomdfile=
+  repomdxml=`repomd_findfile '' repomd.xml`
+  if test -n "$repomdxml" -a -s "$repomdxml" ; then
+      repomdfile=`mktemp` || exit 3
+      repomd_decompress "$repomdxml" | repomdxml2solv $parser_options > $repomdfile || exit 4
+  fi
+
+  # This contains suseinfo.xml, which is an extension to repomd.xml
+  # for now we only read some keys like expiration and products
+  suseinfofile=
+  suseinfoxml=`repomd_findfile suseinfo suseinfo.xml`
+  if test -n "$suseinfoxml" -a -s "$suseinfoxml" ; then
+      suseinfofile=`mktemp` || exit 3
+      repomd_decompress "$suseinfoxml" | repomdxml2solv $parser_options > $suseinfofile || exit 4
+  fi
+
+  # This contains a updateinfo.xml* and maybe patches
+  updateinfofile=
+  updateinfoxml=`repomd_findfile updateinfo updateinfo.xml`
+  if test -n "$updateinfoxml" -a -s "$updateinfoxml" ; then
+      updateinfofile=`mktemp` || exit 3
+      repomd_decompress "$updateinfoxml" | updateinfoxml2solv $parser_options > $updateinfofile || exit 4
+  fi
+
+  # This contains a deltainfo.xml*
+  deltainfofile=
+  deltainfoxml=`repomd_findfile deltainfo deltainfo.xml`
+  if test -z "$deltainfoxml"; then 
+      deltainfoxml=`repomd_findfile prestodelta prestodelta.xml`
+  fi
+  if test -n "$deltainfoxml" -a -s "$deltainfoxml" ; then
+      deltainfofile=`mktemp` || exit 3
+      repomd_decompress "$deltainfoxml" | deltainfoxml2solv $parser_options > $deltainfofile || exit 4
+  fi
+
+  # This contains appdata
+  appdataxml=
+  appdatafile=
+  if test -x /usr/bin/appdata2solv ; then
+      appdataxml=`repomd_findfile appdata appdata.xml`
+  fi
+  if test -n "$appdataxml" -a -s "$appdataxml" ; then
+      appdatafile=`mktemp` || exit 3
+      repomd_decompress "$appdataxml" | appdata2solv $parser_options > $appdatafile || exit 4
+  fi
+
+  # Now merge primary, patches, updateinfo, and deltainfo
+  mergesolv $addautooption $repomdfile $suseinfofile $primfile $prodfile $patternfile $updateinfofile $deltainfofile $appdatafile
+  rm -f $repomdfile $suseinfofile $primfile $patternfile $prodfile $updateinfofile $deltainfofile $appdatafile
+
+elif test "$repotype" = susetags ; then
+  olddir=`pwd`
+  DESCR=$(get_DESCRDIR)
+  cd ${DESCR} || exit 2
+  appdataxml=
+  appdatafile=
+  if test -x /usr/bin/appdata2solv ; then
+      appdataxml=`susetags_findfile appdata.xml`
+  fi
+  if test -n "$appdataxml" ; then
+      appdatafile=`mktemp` || exit 3
+      repomd_decompress "$appdataxml" | appdata2solv $parser_options > $appdatafile || exit 4
+      parser_options="-M $appdatafile $parser_options"
+  fi
+  (
+    # First packages
+    susetags_findfile_cat packages
+
+    # DU
+    susetags_findfile_cat packages.DU
+
+    # Now default language
+    susetags_findfile_cat packages.en
+
+    # DL (delta rpms)
+    susetags_findfile_cat packages.DL
+
+    # Now patterns.  Not simply those files matching *.pat{,.gz,bz2},
+    # but only those mentioned in the file 'patterns'
+    if test -f patterns ; then
+      for i in `cat patterns`; do
+        if test -s "$i" ; then
+         repomd_decompress "$i"
+       fi
+      done
+    fi
+
+    # Now all other packages.{lang}.  Needs to come last as it switches
+    # languages for all following susetags files
+    for i in packages.* ; do
+      case $i in
+       *.gz|*.bz2|*.xz|*.lzma) name="${i%.*}" ;;
+       *) name="$i" ;;
+      esac
+      case $name in
+       # ignore files we handled already
+       *.DU | *.en | *.FL | *.DL | packages ) continue ;;
+       *)
+         suff=${name#packages.}
+         echo "=Lan: $suff"
+         repomd_decompress "$i"
+      esac
+    done
+
+  ) | susetags2solv $addautooption -c "${olddir}/content" $parser_options || exit 4
+  test -n "$appdatafile" && rm -f "$appdatafile"
+  cd "$olddir"
+elif test "$repotype" = plaindir ; then
+  find * -name .\* -prune -o $findopt -name \*.delta.rpm -o -name \*.patch.rpm -o -name \*.rpm -a -type f -print0 | rpms2solv $addautooption -0 -m -
+else
+  echo "unknown repository type '$repotype'" >&2
+  exit 1
+fi
diff --git a/libsolv-0.7.2/examples/solv/CMakeLists.txt b/libsolv-0.7.2/examples/solv/CMakeLists.txt
new file mode 100644 (file)
index 0000000..41f45f7
--- /dev/null
@@ -0,0 +1,29 @@
+
+ADD_EXECUTABLE (solv solv.c
+checksig.c
+deltarpm.c
+fastestmirror.c
+fileconflicts.c
+fileprovides.c
+mirror.c
+patchjobs.c
+repoinfo.c
+repoinfo_cache.c
+repoinfo_config_debian.c
+repoinfo_config_yum.c
+repoinfo_config_urpmi.c
+repoinfo_download.c
+repoinfo_system_debian.c
+repoinfo_system_rpm.c
+repoinfo_type_debian.c
+repoinfo_type_mdk.c
+repoinfo_type_rpmmd.c
+repoinfo_type_susetags.c
+)
+
+TARGET_LINK_LIBRARIES (solv libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL(TARGETS
+    solv
+    DESTINATION ${BIN_INSTALL_DIR})
+
diff --git a/libsolv-0.7.2/examples/solv/checksig.c b/libsolv-0.7.2/examples/solv/checksig.c
new file mode 100644 (file)
index 0000000..44603d3
--- /dev/null
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "pool.h"
+#include "repo.h"
+#ifdef ENABLE_PUBKEY
+#include "repo_pubkey.h"
+#endif
+
+#include "checksig.h"
+
+#ifndef DEBIAN
+
+static void
+cleanupgpg(char *gpgdir)
+{
+  char cmd[256];
+  snprintf(cmd, sizeof(cmd), "%s/pubring.gpg", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/pubring.gpg~", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/secring.gpg", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/trustdb.gpg", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/keys", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/pubring.kbx", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/pubring.kbx~", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/private-keys-v1.d", gpgdir);
+  rmdir(cmd);
+  rmdir(gpgdir);
+}
+
+int
+checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
+{
+  char *gpgdir;
+  char *keysfile;
+  const char *pubkey, *pubring;
+  char cmd[256];
+  FILE *kfp;
+  Solvable *s;
+  Id p;
+  off_t posfp, possigfp;
+  int r, nkeys;
+
+  gpgdir = mkdtemp(pool_tmpjoin(sigpool, "/var/tmp/solvgpg.XXXXXX", 0, 0));
+  if (!gpgdir)
+    return 0;
+  keysfile = pool_tmpjoin(sigpool, gpgdir, "/keys", 0);
+  if (!(kfp = fopen(keysfile, "w")) )
+    {
+      cleanupgpg(gpgdir);
+      return 0;
+    }
+  nkeys = 0;
+  for (p = 1, s = sigpool->solvables + p; p < sigpool->nsolvables; p++, s++)
+    {
+      if (!s->repo)
+       continue;
+      pubkey = solvable_lookup_str(s, SOLVABLE_DESCRIPTION);
+      if (!pubkey || !*pubkey)
+       continue;
+      if (fwrite(pubkey, strlen(pubkey), 1, kfp) != 1)
+       break;
+      if (fputc('\n', kfp) == EOF)     /* Just in case... */
+       break;
+      nkeys++;
+    }
+  if (fclose(kfp) || !nkeys || p < sigpool->nsolvables)
+    {
+      cleanupgpg(gpgdir);
+      return 0;
+    }
+  snprintf(cmd, sizeof(cmd), "gpg2 -q --homedir %s --import %s", gpgdir, keysfile);
+  if (system(cmd))
+    {
+      fprintf(stderr, "key import error\n");
+      cleanupgpg(gpgdir);
+      return 0;
+    }
+  unlink(keysfile);
+  posfp = lseek(fileno(fp), 0, SEEK_CUR);
+  lseek(fileno(fp), 0, SEEK_SET);
+  possigfp = lseek(fileno(sigfp), 0, SEEK_CUR);
+  lseek(fileno(sigfp), 0, SEEK_SET);
+  snprintf(cmd, sizeof(cmd), "%s/pubring.kbx", gpgdir);
+  pubring = access(cmd, R_OK) == 0 ? "pubring.kbx" : "pubring.gpg";
+  snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/%s /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, pubring, fileno(sigfp), fileno(fp));
+  fcntl(fileno(fp), F_SETFD, 0);       /* clear CLOEXEC */
+  fcntl(fileno(sigfp), F_SETFD, 0);    /* clear CLOEXEC */
+  r = system(cmd);
+  lseek(fileno(sigfp), possigfp, SEEK_SET);
+  lseek(fileno(fp), posfp, SEEK_SET);
+  fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
+  fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
+  cleanupgpg(gpgdir);
+  return r == 0 ? 1 : 0;
+}
+
+#else
+
+int
+checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
+{
+  char cmd[256];
+  int r;
+
+  snprintf(cmd, sizeof(cmd), "gpgv -q --keyring /etc/apt/trusted.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", fileno(sigfp), fileno(fp));
+  fcntl(fileno(fp), F_SETFD, 0);       /* clear CLOEXEC */
+  fcntl(fileno(sigfp), F_SETFD, 0);    /* clear CLOEXEC */
+  r = system(cmd);
+  fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
+  fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
+  return r == 0 ? 1 : 0;
+}
+
+#endif
+
+Pool *
+read_sigs()
+{
+  Pool *sigpool = pool_create();
+#if defined(ENABLE_PUBKEY) && defined(ENABLE_RPMDB)
+  Repo *repo = repo_create(sigpool, "pubkeys");
+  repo_add_rpmdb_pubkeys(repo, 0);
+#endif
+  return sigpool;
+}
diff --git a/libsolv-0.7.2/examples/solv/checksig.h b/libsolv-0.7.2/examples/solv/checksig.h
new file mode 100644 (file)
index 0000000..67ebaf8
--- /dev/null
@@ -0,0 +1,3 @@
+extern int checksig(Pool *sigpool, FILE *fp, FILE *sigfp);
+extern Pool *read_sigs();
+
diff --git a/libsolv-0.7.2/examples/solv/deltarpm.c b/libsolv-0.7.2/examples/solv/deltarpm.c
new file mode 100644 (file)
index 0000000..438c2d8
--- /dev/null
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repoinfo.h"
+#include "repoinfo_download.h"
+
+#include "deltarpm.h"
+
+static inline int
+opentmpfile()
+{
+  char tmpl[100];
+  int fd;
+
+  strcpy(tmpl, "/var/tmp/solvXXXXXX");
+  fd = mkstemp(tmpl);
+  if (fd < 0) 
+    {    
+      perror("mkstemp");
+      exit(1);
+    }    
+  unlink(tmpl);
+  return fd;
+}
+
+FILE *
+trydeltadownload(Solvable *s, const char *loc)
+{
+  Repo *repo = s->repo;
+  Pool *pool = repo->pool;
+  struct repoinfo *cinfo = repo->appdata;
+  Dataiterator di;
+  Id pp;
+  const unsigned char *chksum;
+  Id chksumtype;
+  FILE *retfp = 0;
+  char *matchname = strdup(pool_id2str(pool, s->name));
+
+  dataiterator_init(&di, pool, repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING);
+  dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO);
+  while (dataiterator_step(&di))
+    {
+      Id baseevr, op;
+
+      dataiterator_setpos_parent(&di);
+      if (pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_EVR) != s->evr ||
+         pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_ARCH) != s->arch)
+       continue;
+      baseevr = pool_lookup_id(pool, SOLVID_POS, DELTA_BASE_EVR);
+      FOR_PROVIDES(op, pp, s->name)
+       {
+         Solvable *os = pool->solvables + op;
+         if (os->repo == pool->installed && os->name == s->name && os->arch == s->arch && os->evr == baseevr)
+           break;
+       }
+      if (op && access("/usr/bin/applydeltarpm", X_OK) == 0)
+       {
+         /* base is installed, run sequence check */
+         const char *seq;
+         const char *dloc;
+         const char *archstr;
+         FILE *fp;
+         char cmd[128];
+         int newfd;
+
+         archstr = pool_id2str(pool, s->arch);
+         if (strlen(archstr) > 10 || strchr(archstr, '\'') != 0)
+           continue;
+
+         seq = pool_tmpjoin(pool, pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME), "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR));
+         seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM));
+         if (strchr(seq, '\'') != 0)
+           continue;
+#if defined(FEDORA) || defined(MAGEIA)
+         sprintf(cmd, "/usr/bin/applydeltarpm -a '%s' -c -s '", archstr);
+#else
+         sprintf(cmd, "/usr/bin/applydeltarpm -c -s '");
+#endif
+         if (system(pool_tmpjoin(pool, cmd, seq, "'")) != 0)
+           continue;   /* didn't match */
+         /* looks good, download delta */
+         chksumtype = 0;
+         chksum = pool_lookup_bin_checksum(pool, SOLVID_POS, DELTA_CHECKSUM, &chksumtype);
+         if (!chksumtype)
+           continue;   /* no way! */
+         dloc = pool_lookup_deltalocation(pool, SOLVID_POS, 0);
+         if (!dloc)
+           continue;
+#ifdef ENABLE_SUSEREPO
+         if (cinfo->type == TYPE_SUSETAGS)
+           {
+             const char *datadir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DATADIR);
+             dloc = pool_tmpjoin(pool, datadir ? datadir : "suse", "/", dloc);
+           }
+#endif
+         if ((fp = curlfopen(cinfo, dloc, 0, chksum, chksumtype, 0)) == 0)
+           continue;
+         /* got it, now reconstruct */
+         newfd = opentmpfile();
+#if defined(FEDORA) || defined(MAGEIA)
+         sprintf(cmd, "applydeltarpm -a '%s' /dev/fd/%d /dev/fd/%d", archstr, fileno(fp), newfd);
+#else
+         sprintf(cmd, "applydeltarpm /dev/fd/%d /dev/fd/%d", fileno(fp), newfd);
+#endif
+         fcntl(fileno(fp), F_SETFD, 0);
+         if (system(cmd))
+           {
+             close(newfd);
+             fclose(fp);
+             continue;
+           }
+         lseek(newfd, 0, SEEK_SET);
+         chksumtype = 0;
+         chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
+         if (chksumtype && !verify_checksum(newfd, loc, chksum, chksumtype))
+           {
+             close(newfd);
+             fclose(fp);
+             continue;
+           }
+         retfp = fdopen(newfd, "r");
+         fclose(fp);
+         break;
+       }
+    }
+  dataiterator_free(&di);
+  solv_free(matchname);
+  return retfp;
+}
diff --git a/libsolv-0.7.2/examples/solv/deltarpm.h b/libsolv-0.7.2/examples/solv/deltarpm.h
new file mode 100644 (file)
index 0000000..528e5a2
--- /dev/null
@@ -0,0 +1 @@
+extern FILE *trydeltadownload(Solvable *s, const char *loc);
diff --git a/libsolv-0.7.2/examples/solv/fastestmirror.c b/libsolv-0.7.2/examples/solv/fastestmirror.c
new file mode 100644 (file)
index 0000000..d2ebd97
--- /dev/null
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <poll.h>
+#include <errno.h>
+
+#include "util.h"
+
+#include "fastestmirror.h"
+
+void
+findfastest(char **urls, int nurls)
+{
+  int i, j, port;
+  int *socks, qc;
+  struct pollfd *fds;
+  char *p, *p2, *q;
+  char portstr[16];
+  struct addrinfo hints, *result;;
+
+  fds = solv_calloc(nurls, sizeof(*fds));
+  socks = solv_calloc(nurls, sizeof(*socks));
+  for (i = 0; i < nurls; i++)
+    {
+      socks[i] = -1;
+      p = strchr(urls[i], '/');
+      if (!p)
+       continue;
+      if (p[1] != '/')
+       continue;
+      p += 2;
+      q = strchr(p, '/');
+      qc = 0;
+      if (q)
+       {
+         qc = *q;
+         *q = 0;
+       }
+      if ((p2 = strchr(p, '@')) != 0)
+       p = p2 + 1;
+      port = 80;
+      if (!strncmp("https:", urls[i], 6))
+       port = 443;
+      else if (!strncmp("ftp:", urls[i], 4))
+       port = 21;
+      if ((p2 = strrchr(p, ':')) != 0)
+       {
+         port = atoi(p2 + 1);
+         if (q)
+           *q = qc;
+         q = p2;
+         qc = *q;
+         *q = 0;
+       }
+      sprintf(portstr, "%d", port);
+      memset(&hints, 0, sizeof(struct addrinfo));
+      hints.ai_family = AF_UNSPEC;
+      hints.ai_socktype = SOCK_STREAM;
+      hints.ai_flags = AI_NUMERICSERV;
+      result = 0;
+      if (!getaddrinfo(p, portstr, &hints, &result))
+       {
+         socks[i] = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
+         if (socks[i] >= 0)
+           {
+             fcntl(socks[i], F_SETFL, O_NONBLOCK);
+             if (connect(socks[i], result->ai_addr, result->ai_addrlen) == -1)
+               {
+                 if (errno != EINPROGRESS)
+                   {
+                     close(socks[i]);
+                     socks[i] = -1;
+                   }
+               }
+           }
+         freeaddrinfo(result);
+       }
+      if (q)
+       *q = qc;
+    }
+  for (;;)
+    {
+      for (i = j = 0; i < nurls; i++)
+       {
+         if (socks[i] < 0)
+           continue;
+         fds[j].fd = socks[i];
+         fds[j].events = POLLOUT;
+         j++;
+       }
+      if (j < 2)
+       {
+         i = j - 1;
+         break;
+       }
+      if (poll(fds, j, 10000) <= 0)
+       {
+         i = -1;       /* something is wrong */
+         break;
+       }
+      for (i = 0; i < j; i++)
+       if ((fds[i].revents & POLLOUT) != 0)
+         {
+           int soe = 0;
+           socklen_t soel = sizeof(int);
+           if (getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, &soe, &soel) == -1 || soe != 0)
+             {
+               /* connect failed, kill socket */
+               for (j = 0; j < nurls; j++)
+                 if (socks[j] == fds[i].fd)
+                   {
+                     close(socks[j]);
+                     socks[j] = -1;
+                   }
+               i = j + 1;
+               break;
+             }
+           break;      /* horray! */
+         }
+      if (i == j + 1)
+       continue;
+      if (i == j)
+        i = -1;                /* something is wrong, no bit was set */
+      break;
+    }
+  /* now i contains the fastest fd index */
+  if (i >= 0)
+    {
+      for (j = 0; j < nurls; j++)
+       if (socks[j] == fds[i].fd)
+         break;
+      if (j != 0)
+       {
+         char *url0 = urls[0];
+         urls[0] = urls[j];
+         urls[j] = url0;
+       }
+    }
+  for (i = j = 0; i < nurls; i++)
+    if (socks[i] >= 0)
+      close(socks[i]);
+  free(socks);
+  free(fds);
+}
diff --git a/libsolv-0.7.2/examples/solv/fastestmirror.h b/libsolv-0.7.2/examples/solv/fastestmirror.h
new file mode 100644 (file)
index 0000000..53251ef
--- /dev/null
@@ -0,0 +1,2 @@
+extern void findfastest(char **urls, int nurls);
+
diff --git a/libsolv-0.7.2/examples/solv/fileconflicts.c b/libsolv-0.7.2/examples/solv/fileconflicts.c
new file mode 100644 (file)
index 0000000..2d45bc4
--- /dev/null
@@ -0,0 +1,81 @@
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_rpmdb.h"
+#include "pool_fileconflicts.h"
+
+#include "fileconflicts.h"
+
+struct fcstate {
+  FILE **newpkgsfps;
+  Queue *checkq;
+  int newpkgscnt;
+  void *rpmstate;
+};
+
+static void *
+fileconflict_cb(Pool *pool, Id p, void *cbdata)
+{
+  struct fcstate *fcstate = cbdata;
+  Solvable *s;
+  Id rpmdbid;
+  int i;
+  FILE *fp; 
+
+  s = pool_id2solvable(pool, p);
+  if (pool->installed && s->repo == pool->installed)
+    {    
+      if (!s->repo->rpmdbid)
+        return 0;
+      rpmdbid = s->repo->rpmdbid[p - s->repo->start];
+      if (!rpmdbid)
+        return 0;
+      return rpm_byrpmdbid(fcstate->rpmstate, rpmdbid);
+    }    
+  for (i = 0; i < fcstate->newpkgscnt; i++) 
+    if (fcstate->checkq->elements[i] == p)
+      break;
+  if (i == fcstate->newpkgscnt)
+    return 0;
+  fp = fcstate->newpkgsfps[i];
+  if (!fp)
+    return 0;
+  rewind(fp);
+  return rpm_byfp(fcstate->rpmstate, fp, pool_solvable2str(pool, s)); 
+}
+
+int
+checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Queue *conflicts)
+{
+  struct fcstate fcstate;
+  int i;
+
+  printf("Searching for file conflicts\n");
+  queue_init(conflicts);
+  fcstate.rpmstate = rpm_state_create(pool, pool_get_rootdir(pool));
+  fcstate.newpkgscnt = newpkgs;
+  fcstate.checkq = checkq;
+  fcstate.newpkgsfps = newpkgsfps;
+  pool_findfileconflicts(pool, checkq, newpkgs, conflicts, FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, &fileconflict_cb, &fcstate);
+  fcstate.rpmstate = rpm_state_free(fcstate.rpmstate);
+  if (conflicts->count)
+    {
+      printf("\n");
+      for (i = 0; i < conflicts->count; i += 6)
+       {
+         if (conflicts->elements[i] == conflicts->elements[i + 3])
+           printf("file %s of package %s conflicts with package %s\n", pool_id2str(pool, conflicts->elements[i]), pool_solvid2str(pool, conflicts->elements[i + 1]), pool_solvid2str(pool, conflicts->elements[i + 4]));
+         else
+           printf("file %s of package %s conflicts with file %s of package %s\n", pool_id2str(pool, conflicts->elements[i]), pool_solvid2str(pool, conflicts->elements[i + 1]), pool_id2str(pool, conflicts->elements[i + 3]), pool_solvid2str(pool, conflicts->elements[i + 4]));
+       }
+      printf("\n");
+    }
+  return conflicts->count;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/fileconflicts.h b/libsolv-0.7.2/examples/solv/fileconflicts.h
new file mode 100644 (file)
index 0000000..e3f31e7
--- /dev/null
@@ -0,0 +1,2 @@
+extern int checkfileconflicts(Pool *pool, Queue *checkq, int newpkgs, FILE **newpkgsfps, Queue *conflicts);
+
diff --git a/libsolv-0.7.2/examples/solv/fileprovides.c b/libsolv-0.7.2/examples/solv/fileprovides.c
new file mode 100644 (file)
index 0000000..2654ab6
--- /dev/null
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+
+#include "fileprovides.h"
+
+static void
+rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_inst)
+{
+  Repo *repo;
+  Repodata *data;
+  Map providedids;
+  Queue fileprovidesq;
+  int i, j, n;
+  struct repoinfo *cinfo;
+
+  map_init(&providedids, pool->ss.nstrings);
+  queue_init(&fileprovidesq);
+  for (i = 0; i < addedfileprovides->count; i++)
+    MAPSET(&providedids, addedfileprovides->elements[i]);
+  FOR_REPOS(i, repo)
+    {
+      /* make sure all repodatas but the first are extensions */
+      if (repo->nrepodata < 2)
+       continue;
+      cinfo = repo->appdata;
+      if (!cinfo)
+       continue;       /* cmdline */
+      if (cinfo->incomplete)
+       continue;
+      data = repo_id2repodata(repo, 1);
+      if (data->loadcallback)
+        continue;
+      for (j = 2; j < repo->nrepodata; j++)
+       {
+         Repodata *edata = repo_id2repodata(repo, j);
+         if (!edata->loadcallback)
+           break;
+       }
+      if (j < repo->nrepodata)
+       continue;       /* found a non-extension repodata, can't rewrite  */
+      if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
+       {
+         if (repo == pool->installed && addedfileprovides_inst)
+           {
+             for (j = 0; j < addedfileprovides->count; j++)
+               MAPCLR(&providedids, addedfileprovides->elements[j]);
+             for (j = 0; j < addedfileprovides_inst->count; j++)
+               MAPSET(&providedids, addedfileprovides_inst->elements[j]);
+           }
+         n = 0;
+         for (j = 0; j < fileprovidesq.count; j++)
+           if (MAPTST(&providedids, fileprovidesq.elements[j]))
+             n++;
+         if (repo == pool->installed && addedfileprovides_inst)
+           {
+             for (j = 0; j < addedfileprovides_inst->count; j++)
+               MAPCLR(&providedids, addedfileprovides_inst->elements[j]);
+             for (j = 0; j < addedfileprovides->count; j++)
+               MAPSET(&providedids, addedfileprovides->elements[j]);
+             if (n == addedfileprovides_inst->count)
+               continue;       /* nothing new added */
+           }
+         else if (n == addedfileprovides->count)
+           continue;   /* nothing new added */
+       }
+      repodata_set_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, repo == pool->installed && addedfileprovides_inst ? addedfileprovides_inst : addedfileprovides);
+      repodata_internalize(data);
+      writecachedrepo(cinfo, 0, data);
+    }
+  queue_free(&fileprovidesq);
+  map_free(&providedids);
+}
+
+void
+addfileprovides(Pool *pool)
+{
+  Queue addedfileprovides;
+  Queue addedfileprovides_inst;
+
+  queue_init(&addedfileprovides);
+  queue_init(&addedfileprovides_inst);
+  pool_addfileprovides_queue(pool, &addedfileprovides, &addedfileprovides_inst);
+  if (addedfileprovides.count || addedfileprovides_inst.count)
+    rewrite_repos(pool, &addedfileprovides, &addedfileprovides_inst);
+  queue_free(&addedfileprovides);
+  queue_free(&addedfileprovides_inst);
+}
diff --git a/libsolv-0.7.2/examples/solv/fileprovides.h b/libsolv-0.7.2/examples/solv/fileprovides.h
new file mode 100644 (file)
index 0000000..1069d5a
--- /dev/null
@@ -0,0 +1 @@
+void addfileprovides(Pool *pool);
diff --git a/libsolv-0.7.2/examples/solv/mirror.c b/libsolv-0.7.2/examples/solv/mirror.c
new file mode 100644 (file)
index 0000000..52dc5ef
--- /dev/null
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pool.h"
+#include "util.h"
+#include "fastestmirror.h"
+
+#include "mirror.h"
+
+char *
+findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep)
+{
+  char buf[4096], *bp, *ep;
+  char **urls = 0;
+  int nurls = 0;
+  int i;
+
+  if (chksumtypep)
+    *chksumtypep = 0;
+  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
+    {
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      if (chksumtypep && !*chksumtypep && !strncmp(bp, "<hash type=\"sha256\">", 20))
+       {
+         bp += 20;
+         if (solv_hex2bin((const char **)&bp, chksump, 32) == 32)
+           *chksumtypep = REPOKEY_TYPE_SHA256;
+         continue;
+       }
+      if (strncmp(bp, "<url", 4))
+       continue;
+      bp = strchr(bp, '>');
+      if (!bp)
+       continue;
+      bp++;
+      ep = strstr(bp, "repodata/repomd.xml</url>");
+      if (!ep)
+       continue;
+      *ep = 0;
+      if (strncmp(bp, "http", 4))
+       continue;
+      urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15);
+      urls[nurls++] = strdup(bp);
+    }
+  if (nurls)
+    {
+      if (nurls > 1)
+        findfastest(urls, nurls > 5 ? 5 : nurls);
+      bp = urls[0];
+      urls[0] = 0;
+      for (i = 0; i < nurls; i++)
+        solv_free(urls[i]);
+      solv_free(urls);
+      ep = strchr(bp, '/');
+      if ((ep = strchr(ep + 2, '/')) != 0)
+       {
+         *ep = 0;
+         printf("[using mirror %s]\n", bp);
+         *ep = '/';
+       }
+      return bp;
+    }
+  return 0;
+}
+
+char *
+findmirrorlisturl(FILE *fp)
+{
+  char buf[4096], *bp, *ep;
+  int i, l;
+  char **urls = 0;
+  int nurls = 0;
+
+  while((bp = fgets(buf, sizeof(buf), fp)) != 0)
+    {
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      if (!*bp || *bp == '#')
+       continue;
+      l = strlen(bp);
+      while (l > 0 && (bp[l - 1] == ' ' || bp[l - 1] == '\t' || bp[l - 1] == '\n'))
+       bp[--l] = 0;
+      if ((ep = strstr(bp, "url=")) != 0)
+       bp = ep + 4;
+      urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15);
+      urls[nurls++] = strdup(bp);
+    }
+  if (nurls)
+    {
+      if (nurls > 1)
+        findfastest(urls, nurls > 5 ? 5 : nurls);
+      bp = urls[0];
+      urls[0] = 0;
+      for (i = 0; i < nurls; i++)
+        solv_free(urls[i]);
+      solv_free(urls);
+      ep = strchr(bp, '/');
+      if ((ep = strchr(ep + 2, '/')) != 0)
+       {
+         *ep = 0;
+         printf("[using mirror %s]\n", bp);
+         *ep = '/';
+       }
+      return bp;
+    }
+  return 0;
+}
diff --git a/libsolv-0.7.2/examples/solv/mirror.h b/libsolv-0.7.2/examples/solv/mirror.h
new file mode 100644 (file)
index 0000000..ed85a39
--- /dev/null
@@ -0,0 +1,2 @@
+char *findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep);
+char *findmirrorlisturl(FILE *fp);
diff --git a/libsolv-0.7.2/examples/solv/patchjobs.c b/libsolv-0.7.2/examples/solv/patchjobs.c
new file mode 100644 (file)
index 0000000..929a203
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "evr.h"
+#include "solver.h"
+
+void
+add_patchjobs(Pool *pool, Queue *job)
+{
+  Id p, pp;
+  int pruneyou = 0;
+  Map installedmap, multiversionmap;
+  Solvable *s;
+
+  map_init(&multiversionmap, 0);
+  map_init(&installedmap, pool->nsolvables);
+  solver_calculate_multiversionmap(pool, job, &multiversionmap);
+  if (pool->installed)
+    {
+      FOR_REPO_SOLVABLES(pool->installed, p, s)
+        MAPSET(&installedmap, p);
+    }
+
+  /* install all patches */
+  for (p = 1; p < pool->nsolvables; p++)
+    {
+      const char *type;
+      int r;
+      Id p2;
+
+      s = pool->solvables + p;
+      if (strncmp(pool_id2str(pool, s->name), "patch:", 6) != 0)
+       continue;
+      FOR_PROVIDES(p2, pp, s->name)
+       {
+         Solvable *s2 = pool->solvables + p2;
+         if (s2->name != s->name)
+           continue;
+         r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+         if (r < 0 || (r == 0 && p > p2))
+           break;
+       }
+      if (p2)
+       continue;
+      type = solvable_lookup_str(s, SOLVABLE_PATCHCATEGORY);
+      if (type && !strcmp(type, "optional"))
+       continue;
+      r = solvable_trivial_installable_map(s, &installedmap, 0, &multiversionmap);
+      if (r == -1)
+       continue;
+      if (solvable_lookup_bool(s, UPDATE_RESTART) && r == 0)
+       {
+         if (!pruneyou++)
+           queue_empty(job);
+       }
+      else if (pruneyou)
+       continue;
+      queue_push2(job, SOLVER_SOLVABLE, p);
+    }
+  map_free(&installedmap);
+  map_free(&multiversionmap);
+}
diff --git a/libsolv-0.7.2/examples/solv/patchjobs.h b/libsolv-0.7.2/examples/solv/patchjobs.h
new file mode 100644 (file)
index 0000000..52edcbe
--- /dev/null
@@ -0,0 +1,2 @@
+extern void add_patchjobs(Pool *pool, Queue *job);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo.c b/libsolv-0.7.2/examples/solv/repoinfo.c
new file mode 100644 (file)
index 0000000..6273972
--- /dev/null
@@ -0,0 +1,289 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+#include "repo_rpmdb.h"
+#endif
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+#include "repo_deb.h"
+#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+#include "repoinfo_config_yum.h"
+#endif
+#if defined(DEBIAN)
+#include "repoinfo_config_debian.h"
+#endif
+#if defined(MANDRIVA)
+#include "repoinfo_config_urpmi.h"
+#endif
+
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+#include "repoinfo_system_rpm.h"
+#endif
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+#include "repoinfo_system_debian.h"
+#endif
+
+#ifdef ENABLE_RPMMD
+#include "repoinfo_type_rpmmd.h"
+#endif
+#ifdef ENABLE_SUSEREPO
+#include "repoinfo_type_susetags.h"
+#endif
+#ifdef ENABLE_DEBIAN
+#include "repoinfo_type_debian.h"
+#endif
+#ifdef ENABLE_MDKREPO
+#include "repoinfo_type_mdk.h"
+#endif
+
+static int
+repoinfos_sort_cmp(const void *ap, const void *bp)
+{
+  const struct repoinfo *a = ap;
+  const struct repoinfo *b = bp;
+  return strcmp(a->alias, b->alias);
+}
+
+void
+sort_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
+{
+  qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), repoinfos_sort_cmp);
+}
+
+void
+free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
+{
+  int i, j;
+  for (i = 0; i < nrepoinfos; i++)
+    {
+      struct repoinfo *cinfo = repoinfos + i;
+      solv_free(cinfo->name);
+      solv_free(cinfo->alias);
+      solv_free(cinfo->path);
+      solv_free(cinfo->metalink);
+      solv_free(cinfo->mirrorlist);
+      solv_free(cinfo->baseurl);
+      for (j = 0; j < cinfo->ncomponents; j++)
+        solv_free(cinfo->components[j]);
+      solv_free(cinfo->components);
+    }
+  solv_free(repoinfos);
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+  yum_substitute((Pool *)0, 0);                /* free data */
+#endif
+}
+
+struct repoinfo *
+read_repoinfos(Pool *pool, int *nrepoinfosp)
+{
+  struct repoinfo *repoinfos = 0;
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+  repoinfos = read_repoinfos_yum(pool, nrepoinfosp);
+#endif
+#if defined(MANDRIVA)
+  repoinfos = read_repoinfos_urpmi(pool, nrepoinfosp);
+#endif
+#if defined(DEBIAN)
+  repoinfos = read_repoinfos_debian(pool, nrepoinfosp);
+#endif
+  return repoinfos;
+}
+
+int
+read_installed_repo(struct repoinfo *cinfo, Pool *pool)
+{
+  int r = 1;
+  cinfo->type = TYPE_INSTALLED;
+  cinfo->repo = repo_create(pool, "@System");
+  cinfo->repo->appdata = cinfo;
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+  r = read_installed_rpm(cinfo);
+#endif
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+  r = read_installed_debian(cinfo);
+#endif
+#ifdef SUSE
+  repo_add_autopattern(cinfo->repo, 0);
+#endif
+  pool_set_installed(pool, cinfo->repo);
+  return r;
+}
+
+int
+is_cmdline_package(const char *filename)
+{
+  int l = strlen(filename);
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+  if (l > 4 && !strcmp(filename + l - 4, ".rpm"))
+    return 1;
+#endif
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+  if (l > 4 && !strcmp(filename + l - 4, ".deb"))
+    return 1;
+#endif
+  return 0;
+}
+
+Id
+add_cmdline_package(Repo *repo, const char *filename)
+{
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+  return repo_add_rpm(repo, filename, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+#endif
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+  return repo_add_deb(repo, filename, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+#endif
+  return 0;
+}
+
+void
+commit_transactionelement(Pool *pool, Id type, Id p, FILE *fp)
+{
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+  commit_transactionelement_rpm(pool, type, p, fp);
+#endif
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+  commit_transactionelement_debian(pool, type, p, fp);
+#endif
+}
+
+void
+add_ext_keys(Repodata *data, Id handle, const char *ext)
+{
+  static Id langtags[] = {
+    SOLVABLE_SUMMARY,     REPOKEY_TYPE_STR,
+    SOLVABLE_DESCRIPTION, REPOKEY_TYPE_STR,
+    SOLVABLE_EULA,        REPOKEY_TYPE_STR,
+    SOLVABLE_MESSAGEINS,  REPOKEY_TYPE_STR,
+    SOLVABLE_MESSAGEDEL,  REPOKEY_TYPE_STR,
+    SOLVABLE_CATEGORY,    REPOKEY_TYPE_ID,
+    0, 0
+  };
+  if (!strcmp(ext, "DL"))
+    {
+      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOSITORY_DELTAINFO);
+      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_FLEXARRAY);
+    }
+  else if (!strcmp(ext, "FL"))
+    {
+      repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_FILELIST);
+      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRSTRARRAY);
+    }
+  else if (!strcmp(ext, "DU"))
+    {
+      repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_DISKUSAGE);
+      repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRNUMNUMARRAY);
+    }
+  else
+    {
+      Pool *pool = data->repo->pool;
+      int i;
+      for (i = 0; langtags[i]; i += 2)
+       {
+         repodata_add_idarray(data, handle, REPOSITORY_KEYS, pool_id2langid(pool, langtags[i], ext, 1));
+         repodata_add_idarray(data, handle, REPOSITORY_KEYS, langtags[i + 1]);
+       }
+    }
+}
+
+int
+load_stub(Pool *pool, Repodata *data, void *dp)
+{
+  struct repoinfo *cinfo = data->repo->appdata;
+  switch (cinfo->type)
+    {
+#ifdef ENABLE_SUSEREPO
+    case TYPE_SUSETAGS:
+      return susetags_load_ext(data->repo, data);
+#endif
+#ifdef ENABLE_RPMMD
+    case TYPE_RPMMD:
+      return repomd_load_ext(data->repo, data);
+#endif
+#ifdef ENABLE_MDKREPO
+    case TYPE_MDK:
+      return mdk_load_ext(data->repo, data);
+#endif
+    default:
+      /* debian does not have any ext data yet */
+      return 0;
+    }
+}
+
+void
+read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
+{
+  Repo *repo;
+  int i;
+  Pool *sigpool = 0;
+
+  for (i = 0; i < nrepoinfos; i++)
+    {
+      struct repoinfo *cinfo = repoinfos + i;
+      if (!cinfo->enabled)
+       continue;
+
+      repo = repo_create(pool, cinfo->alias);
+      cinfo->repo = repo;
+      repo->appdata = cinfo;
+      repo->priority = 99 - cinfo->priority;
+
+      if ((!cinfo->autorefresh || cinfo->metadata_expire) && usecachedrepo(cinfo, 0, 0))
+       {
+#ifdef SUSE
+         repo_add_autopattern(cinfo->repo, 0);
+#endif
+         printf("repo '%s':", cinfo->alias);
+         printf(" cached\n");
+         continue;
+       }
+
+      switch (cinfo->type)
+       {
+#ifdef ENABLE_RPMMD
+        case TYPE_RPMMD:
+         repomd_load(cinfo, &sigpool);
+         break;
+#endif
+#ifdef ENABLE_SUSEREPO
+        case TYPE_SUSETAGS:
+         susetags_load(cinfo, &sigpool);
+         break;
+#endif
+#ifdef ENABLE_DEBIAN
+        case TYPE_DEBIAN:
+         debian_load(cinfo, &sigpool);
+         break;
+#endif
+#ifdef ENABLE_MDKREPO
+        case TYPE_MDK:
+         mdk_load(cinfo, &sigpool);
+         break;
+#endif
+       default:
+         printf("unsupported repo '%s': skipped\n", cinfo->alias);
+         repo_free(repo, 1);
+         cinfo->repo = 0;
+         break;
+       }
+#ifdef SUSE
+      if (cinfo->repo)
+        repo_add_autopattern(cinfo->repo, 0);
+#endif
+    }
+  if (sigpool)
+    pool_free(sigpool);
+}
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo.h b/libsolv-0.7.2/examples/solv/repoinfo.h
new file mode 100644 (file)
index 0000000..04f94b7
--- /dev/null
@@ -0,0 +1,53 @@
+struct repoinfo {
+  Repo *repo;
+
+  int type;
+  char *alias;
+  char *name;
+  int enabled;
+  int autorefresh;
+  char *baseurl;
+  char *metalink;
+  char *mirrorlist;
+  char *path;
+  int pkgs_gpgcheck;
+  int repo_gpgcheck;
+  int priority;
+  int keeppackages;
+  int metadata_expire;
+  char **components;
+  int ncomponents;
+  int cookieset;
+  unsigned char cookie[32];
+  int extcookieset;
+  unsigned char extcookie[32];
+  int incomplete;
+};
+
+#define TYPE_UNKNOWN    0
+#define TYPE_SUSETAGS   1
+#define TYPE_RPMMD      2
+#define TYPE_PLAINDIR   3
+#define TYPE_DEBIAN     4
+#define TYPE_MDK        5
+
+#define TYPE_INSTALLED  16
+#define TYPE_CMDLINE    17
+
+#define METADATA_EXPIRE (60 * 15)
+
+extern void sort_repoinfos(struct repoinfo *repoinfos, int nrepoinfos);
+extern void free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos);
+extern void read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos);
+extern struct repoinfo *read_repoinfos(Pool *pool, int *nrepoinfosp);
+
+extern int read_installed_repo(struct repoinfo *cinfo, Pool *pool);
+
+extern int is_cmdline_package(const char *filename);
+extern Id add_cmdline_package(Repo *repo, const char *filename);
+
+extern void commit_transactionelement(Pool *pool, Id type, Id p, FILE *fp);
+
+extern void add_ext_keys(Repodata *data, Id handle, const char *ext);
+extern int load_stub(Pool *pool, Repodata *data, void *dp);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_cache.c b/libsolv-0.7.2/examples/solv/repoinfo_cache.c
new file mode 100644 (file)
index 0000000..ec4fe57
--- /dev/null
@@ -0,0 +1,290 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "repo_solv.h"
+#include "repo_write.h"
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+
+#define COOKIE_IDENT "1.1"
+
+#define SOLVCACHE_PATH "/var/cache/solv"
+
+static char *userhome;
+
+void
+set_userhome()
+{
+  userhome = getenv("HOME");
+  if (userhome && userhome[0] != '/') 
+    userhome = 0; 
+}
+
+void
+calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out)
+{
+  char buf[4096];
+  Chksum *h = solv_chksum_create(chktype);
+  int l;
+
+  solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT));
+  while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
+    solv_chksum_add(h, buf, l);
+  rewind(fp);
+  solv_chksum_free(h, out);
+}
+
+void
+calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out)
+{
+  Chksum *h = solv_chksum_create(chktype);
+  solv_chksum_add(h, COOKIE_IDENT, strlen(COOKIE_IDENT));
+  if (cookie)
+    solv_chksum_add(h, cookie, 32);
+  solv_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev));
+  solv_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino));
+  solv_chksum_add(h, &stb->st_size, sizeof(stb->st_size));
+  solv_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime));
+  solv_chksum_free(h, out);
+}
+
+char *
+calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc)
+{
+  char *q, *p;
+  int l;
+  if (!forcesystemloc && userhome && getuid())
+    p = pool_tmpjoin(repo->pool, userhome, "/.solvcache/", 0);
+  else
+    p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", 0);
+  l = strlen(p);
+  p = pool_tmpappend(repo->pool, p, repo->name, 0);
+  if (repoext)
+    {
+      p = pool_tmpappend(repo->pool, p, "_", repoext);
+      p = pool_tmpappend(repo->pool, p, ".solvx", 0);
+    }
+  else
+    p = pool_tmpappend(repo->pool, p, ".solv", 0);
+  q = p + l;
+  if (*q == '.')
+    *q = '_';
+  for (; *q; q++)
+    if (*q == '/')
+      *q = '_';
+  return p;
+}
+
+int
+usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark)
+{
+  Repo *repo = cinfo->repo;
+  FILE *fp;
+  unsigned char *cookie = repoext ? cinfo->extcookie : (cinfo->cookieset ? cinfo->cookie : 0);
+  unsigned char mycookie[32];
+  unsigned char myextcookie[32];
+  int flags;
+  int forcesystemloc;
+
+  if (repoext && !cinfo->extcookieset)
+    return 0;  /* huh? */
+  forcesystemloc = mark & 2 ? 0 : 1;
+  if (mark < 2 && userhome && getuid())
+    {
+      /* first try home location */
+      int res = usecachedrepo(cinfo, repoext, mark | 2);
+      if (res)
+       return res;
+    }
+  mark &= 1;
+  if (!(fp = fopen(calc_cachepath(repo, repoext, forcesystemloc), "r")))
+    return 0;
+  if (!repoext && !cinfo->cookieset && cinfo->autorefresh && cinfo->metadata_expire != -1)
+    {
+      struct stat stb;         /* no cookie set yet, check cache expiry time */
+      if (fstat(fileno(fp), &stb) || time(0) - stb.st_mtime >= cinfo->metadata_expire)
+       {
+         fclose(fp);
+         return 0;
+       }
+    }
+  if (fseek(fp, -sizeof(mycookie), SEEK_END) || fread(mycookie, sizeof(mycookie), 1, fp) != 1)
+    {
+      fclose(fp);
+      return 0;
+    }
+  if (cookie && memcmp(cookie, mycookie, sizeof(mycookie)) != 0)
+    {
+      fclose(fp);
+      return 0;
+    }
+  if (cinfo->type != TYPE_INSTALLED && !repoext)
+    {
+      if (fseek(fp, -sizeof(mycookie) * 2, SEEK_END) || fread(myextcookie, sizeof(myextcookie), 1, fp) != 1)
+       {
+         fclose(fp);
+         return 0;
+       }
+    }
+  rewind(fp);
+
+  flags = 0;
+  if (repoext)
+    {
+      flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
+      if (strcmp(repoext, "DL") != 0)
+        flags |= REPO_LOCALPOOL;       /* no local pool for DL so that we can compare IDs */
+    }
+  if (repo_add_solv(repo, fp, flags))
+    {
+      fclose(fp);
+      return 0;
+    }
+  if (cinfo->type != TYPE_INSTALLED && !repoext)
+    {
+      memcpy(cinfo->cookie, mycookie, sizeof(mycookie));
+      cinfo->cookieset = 1;
+      memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie));
+      cinfo->extcookieset = 1;
+    }
+  if (mark)
+    futimens(fileno(fp), 0);   /* try to set modification time */
+  fclose(fp);
+  return 1;
+}
+
+static void
+switchtowritten(struct repoinfo *cinfo, const char *repoext, Repodata *repodata, char *tmpl)
+{
+  Repo *repo = cinfo->repo;
+  FILE *fp;
+  int i;
+
+  if (!repoext && repodata)
+    return;    /* rewrite case, don't bother for the added fileprovides */
+  for (i = repo->start; i < repo->end; i++)
+   if (repo->pool->solvables[i].repo != repo)
+     break;
+  if (i < repo->end)
+    return;    /* not a simple block */
+      /* switch to just saved repo to activate paging and save memory */
+  fp = fopen(tmpl, "r");
+  if (!fp)
+    return;
+  if (!repoext)
+    {
+      /* main repo */
+      repo_empty(repo, 1);
+      if (repo_add_solv(repo, fp, SOLV_ADD_NO_STUBS))
+       {
+         /* oops, no way to recover from here */
+         fprintf(stderr, "internal error\n");
+         exit(1);
+       }
+    }
+  else
+    {
+      int flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
+      /* make sure repodata contains complete repo */
+      /* (this is how repodata_write saves it) */
+      repodata_extend_block(repodata, repo->start, repo->end - repo->start);
+      repodata->state = REPODATA_LOADING;
+      if (strcmp(repoext, "DL") != 0)
+       flags |= REPO_LOCALPOOL;
+      repo_add_solv(repo, fp, flags);
+      repodata->state = REPODATA_AVAILABLE;    /* in case the load failed */
+    }
+  fclose(fp);
+}
+
+void
+writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata)
+{
+  Repo *repo = cinfo->repo;
+  FILE *fp;
+  int fd;
+  char *tmpl, *cachedir;
+
+  if (cinfo->incomplete || (repoext && !cinfo->extcookieset) || (!repoext && !cinfo->cookieset))
+    return;
+  cachedir = userhome && getuid() ? pool_tmpjoin(repo->pool, userhome, "/.solvcache", 0) : SOLVCACHE_PATH;
+  if (access(cachedir, W_OK | X_OK) != 0 && mkdir(cachedir, 0755) == 0)
+    printf("[created %s]\n", cachedir);
+  /* use dupjoin instead of tmpjoin because tmpl must survive repo_write */
+  tmpl = solv_dupjoin(cachedir, "/", ".newsolv-XXXXXX");
+  fd = mkstemp(tmpl);
+  if (fd < 0)
+    {
+      free(tmpl);
+      return;
+    }
+  fchmod(fd, 0444);
+  if (!(fp = fdopen(fd, "w")))
+    {
+      close(fd);
+      unlink(tmpl);
+      free(tmpl);
+      return;
+    }
+
+  if (!repodata)
+    repo_write(repo, fp);
+  else if (repoext)
+    repodata_write(repodata, fp);
+  else
+    {
+      int oldnrepodata = repo->nrepodata;
+      repo->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata;   /* XXX: do this right */
+      repo_write(repo, fp);
+      repo->nrepodata = oldnrepodata;
+    }
+
+  if (!repoext && cinfo->type != TYPE_INSTALLED)
+    {
+      if (!cinfo->extcookieset)
+       {
+         /* create the ext cookie and append it */
+         /* we just need some unique ID */
+         struct stat stb;
+         if (fstat(fileno(fp), &stb))
+           memset(&stb, 0, sizeof(stb));
+         calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->cookie, cinfo->extcookie);
+         cinfo->extcookieset = 1;
+       }
+      if (fwrite(cinfo->extcookie, 32, 1, fp) != 1)
+       {
+         fclose(fp);
+         unlink(tmpl);
+         free(tmpl);
+         return;
+       }
+    }
+  /* append our cookie describing the metadata state */
+  if (fwrite(repoext ? cinfo->extcookie : cinfo->cookie, 32, 1, fp) != 1)
+    {
+      fclose(fp);
+      unlink(tmpl);
+      free(tmpl);
+      return;
+    }
+  if (fclose(fp))
+    {
+      unlink(tmpl);
+      free(tmpl);
+      return;
+    }
+
+  switchtowritten(cinfo, repoext, repodata, tmpl);
+
+  if (!rename(tmpl, calc_cachepath(repo, repoext, 0)))
+    unlink(tmpl);
+  free(tmpl);
+}
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_cache.h b/libsolv-0.7.2/examples/solv/repoinfo_cache.h
new file mode 100644 (file)
index 0000000..cc74715
--- /dev/null
@@ -0,0 +1,12 @@
+
+struct repoinfo;
+struct stat;
+
+extern void set_userhome(void);
+extern char *calc_cachepath(Repo *repo, const char *repoext, int forcesystemloc);
+extern void calc_cookie_fp(FILE *fp, Id chktype, unsigned char *out);
+extern void calc_cookie_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out);
+
+extern int usecachedrepo(struct repoinfo *cinfo, const char *repoext, int mark);
+extern void  writecachedrepo(struct repoinfo *cinfo, const char *repoext, Repodata *repodata);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_config_debian.c b/libsolv-0.7.2/examples/solv/repoinfo_config_debian.c
new file mode 100644 (file)
index 0000000..b369970
--- /dev/null
@@ -0,0 +1,127 @@
+#ifdef DEBIAN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "pool.h"
+#include "repo.h"
+
+#include "repoinfo.h"
+#include "repoinfo_config_debian.h"
+
+
+
+struct repoinfo *
+read_repoinfos_debian(Pool *pool, int *nrepoinfosp)
+{
+  FILE *fp;
+  char buf[4096];
+  char buf2[4096];
+  int l;
+  char *kp, *url, *distro;
+  struct repoinfo *repoinfos = 0, *cinfo;
+  int nrepoinfos = 0;
+  DIR *dir = 0;
+  struct dirent *ent;
+
+  fp = fopen("/etc/apt/sources.list", "r");
+  while (1)
+    {
+      if (!fp)
+       {
+         if (!dir)
+           {
+             dir = opendir("/etc/apt/sources.list.d");
+             if (!dir)
+               break;
+           }
+         if ((ent = readdir(dir)) == 0)
+           {
+             closedir(dir);
+             break;
+           }
+         if (ent->d_name[0] == '.')
+           continue;
+         l = strlen(ent->d_name);
+         if (l < 5 || strcmp(ent->d_name + l - 5, ".list") != 0)
+           continue;
+         snprintf(buf, sizeof(buf), "%s/%s", "/etc/apt/sources.list.d", ent->d_name);
+         if (!(fp = fopen(buf, "r")))
+           continue;
+       }
+      while(fgets(buf2, sizeof(buf2), fp))
+       {
+         l = strlen(buf2);
+         if (l == 0)
+           continue;
+         while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
+           buf2[--l] = 0;
+         kp = buf2;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp || *kp == '#')
+           continue;
+         if (strncmp(kp, "deb", 3) != 0)
+           continue;
+         kp += 3;
+         if (*kp != ' ' && *kp != '\t')
+           continue;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp)
+           continue;
+         url = kp;
+         while (*kp && *kp != ' ' && *kp != '\t')
+           kp++;
+         if (*kp)
+           *kp++ = 0;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp)
+           continue;
+         distro = kp;
+         while (*kp && *kp != ' ' && *kp != '\t')
+           kp++;
+         if (*kp)
+           *kp++ = 0;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp)
+           continue;
+         repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
+         cinfo = repoinfos + nrepoinfos++;
+         memset(cinfo, 0, sizeof(*cinfo));
+         cinfo->baseurl = strdup(url);
+         cinfo->alias = solv_dupjoin(url, "/", distro);
+         cinfo->name = strdup(distro);
+         cinfo->type = TYPE_DEBIAN;
+         cinfo->enabled = 1;
+         cinfo->autorefresh = 1;
+         cinfo->repo_gpgcheck = 1;
+         cinfo->metadata_expire = METADATA_EXPIRE;
+         while (*kp)
+           {
+             char *compo;
+             while (*kp == ' ' || *kp == '\t')
+               kp++;
+             if (!*kp)
+               break;
+             compo = kp;
+             while (*kp && *kp != ' ' && *kp != '\t')
+               kp++;
+             if (*kp)
+               *kp++ = 0;
+             cinfo->components = solv_extend(cinfo->components, cinfo->ncomponents, 1, sizeof(*cinfo->components), 15);
+             cinfo->components[cinfo->ncomponents++] = strdup(compo);
+           }
+       }
+      fclose(fp);
+      fp = 0;
+    }
+  *nrepoinfosp = nrepoinfos;
+  return repoinfos;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_config_debian.h b/libsolv-0.7.2/examples/solv/repoinfo_config_debian.h
new file mode 100644 (file)
index 0000000..64b3eb6
--- /dev/null
@@ -0,0 +1 @@
+extern struct repoinfo *read_repoinfos_debian(Pool *pool, int *nrepoinfosp);
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.c b/libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.c
new file mode 100644 (file)
index 0000000..a79ea9b
--- /dev/null
@@ -0,0 +1,106 @@
+#if defined(MANDRIVA) || defined(MAGEIA)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "pool.h"
+#include "repo.h"
+
+#include "repoinfo.h"
+#include "repoinfo_config_urpmi.h"
+
+
+#define URPMI_CFG "/etc/urpmi/urpmi.cfg"
+
+
+struct repoinfo *
+read_repoinfos_urpmi(Pool *pool, int *nrepoinfosp)
+{
+  char buf[4096], *bp, *arg;
+  FILE *fp;
+  int l, insect = 0;
+  struct repoinfo *cinfo = 0;
+  struct repoinfo *repoinfos = 0;
+  int nrepoinfos = 0;
+
+  if ((fp = fopen(URPMI_CFG, "r")) == 0)
+    {
+      *nrepoinfosp = 0;
+      return 0;
+    }
+  while (fgets(buf, sizeof(buf), fp))
+    {
+      l = strlen(buf);
+      while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+       buf[--l] = 0;
+      bp = buf;
+      while (l && (*bp == ' ' || *bp == '\t'))
+       {
+         l--;
+         bp++;
+       }
+      if (!l || *bp == '#')
+       continue;
+      if (!insect && bp[l - 1] == '{')
+       {
+         insect++;
+         bp[--l] = 0;
+         if (l > 0)
+           {
+             while (l && (bp[l - 1] == ' ' || bp[l - 1] == '\t'))
+               bp[--l] = 0;
+           }
+         if (l)
+           {
+             char *bbp = bp, *bbp2 = bp;
+             /* unescape */
+             while (*bbp)
+               {
+                 if (*bbp == '\\' && bbp[1])
+                   bbp++;
+                 *bbp2++ = *bbp++;
+               }
+             *bbp2 = 0;
+             repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
+             cinfo = repoinfos + nrepoinfos++;
+             memset(cinfo, 0, sizeof(*cinfo));
+             cinfo->alias = strdup(bp);
+             cinfo->type = TYPE_MDK;
+             cinfo->autorefresh = 1;
+             cinfo->priority = 99;
+             cinfo->enabled = 1;
+             cinfo->metadata_expire = METADATA_EXPIRE;
+           }
+         continue;
+       }
+      if (insect && *bp == '}')
+       {
+         insect--;
+         cinfo = 0;
+         continue;
+       }
+      if (!insect || !cinfo)
+       continue;
+      if ((arg = strchr(bp, ':')) != 0)
+       {
+         *arg++ = 0;
+         while (*arg == ' ' || *arg == '\t')
+           arg++;
+         if (!*arg)
+           arg = 0;
+       }
+      if (strcmp(bp, "ignore") == 0)
+       cinfo->enabled = 0;
+      if (strcmp(bp, "mirrorlist") == 0)
+       cinfo->mirrorlist = solv_strdup(arg);
+      if (strcmp(bp, "with-dir") == 0)
+       cinfo->path = solv_strdup(arg);
+    }
+  fclose(fp);
+  *nrepoinfosp = nrepoinfos;
+  return repoinfos;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.h b/libsolv-0.7.2/examples/solv/repoinfo_config_urpmi.h
new file mode 100644 (file)
index 0000000..bb7374f
--- /dev/null
@@ -0,0 +1,2 @@
+extern struct repoinfo *read_repoinfos_urpmi(Pool *pool, int *nrepoinfosp);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_config_yum.c b/libsolv-0.7.2/examples/solv/repoinfo_config_yum.c
new file mode 100644 (file)
index 0000000..efccf1e
--- /dev/null
@@ -0,0 +1,233 @@
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/utsname.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_rpmdb.h"
+
+#include "repoinfo.h"
+#include "repoinfo_config_yum.h"
+
+
+#if defined(FEDORA) || defined(MAGEIA)
+# define REPOINFO_PATH "/etc/yum.repos.d"
+#endif
+#ifdef SUSE
+# define REPOINFO_PATH "/etc/zypp/repos.d"
+#endif
+
+char *
+yum_substitute(Pool *pool, char *line)
+{
+  char *p, *p2;
+  static char *releaseevr;
+  static char *basearch;
+
+  if (!line)
+    {
+      solv_free(releaseevr);
+      releaseevr = 0;
+      solv_free(basearch);
+      basearch = 0;
+      return 0;
+    }
+  p = line;
+  while ((p2 = strchr(p, '$')) != 0)
+    {
+      if (!strncmp(p2, "$releasever", 11))
+       {
+         if (!releaseevr)
+           {
+             void *rpmstate;
+             Queue q;
+       
+             queue_init(&q);
+             rpmstate = rpm_state_create(pool, pool_get_rootdir(pool));
+             rpm_installedrpmdbids(rpmstate, "Providename", "system-release", &q);
+             if (q.count)
+               {
+                 void *handle;
+                 char *p;
+                 handle = rpm_byrpmdbid(rpmstate, q.elements[0]);
+                 releaseevr = handle ? rpm_query(handle, SOLVABLE_EVR) : 0;
+                 if (releaseevr && (p = strchr(releaseevr, '-')) != 0)
+                   *p = 0;
+               }
+             rpm_state_free(rpmstate);
+             queue_free(&q);
+             if (!releaseevr)
+               {
+                 fprintf(stderr, "no installed package provides 'system-release', cannot determine $releasever\n");
+                 exit(1);
+               }
+           }
+         *p2 = 0;
+         p = pool_tmpjoin(pool, line, releaseevr, p2 + 11);
+         p2 = p + (p2 - line);
+         line = p;
+         p = p2 + strlen(releaseevr);
+         continue;
+       }
+      if (!strncmp(p2, "$basearch", 9))
+       {
+         if (!basearch)
+           {
+             struct utsname un;
+             if (uname(&un))
+               {
+                 perror("uname");
+                 exit(1);
+               }
+             basearch = strdup(un.machine);
+             if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86"))
+               basearch[1] = '3';
+           }
+         *p2 = 0;
+         p = pool_tmpjoin(pool, line, basearch, p2 + 9);
+         p2 = p + (p2 - line);
+         line = p;
+         p = p2 + strlen(basearch);
+         continue;
+       }
+      p = p2 + 1;
+    }
+  return line;
+}
+
+struct repoinfo *
+read_repoinfos_yum(Pool *pool, int *nrepoinfosp)
+{
+  const char *reposdir = REPOINFO_PATH;
+  char buf[4096];
+  char buf2[4096], *kp, *vp, *kpe;
+  DIR *dir;
+  FILE *fp;
+  struct dirent *ent;
+  int l, rdlen;
+  struct repoinfo *repoinfos = 0, *cinfo;
+  int nrepoinfos = 0;
+
+  rdlen = strlen(reposdir);
+  dir = opendir(reposdir);
+  if (!dir)
+    {
+      *nrepoinfosp = 0;
+      return 0;
+    }
+  while ((ent = readdir(dir)) != 0)
+    {
+      if (ent->d_name[0] == '.')
+       continue;
+      l = strlen(ent->d_name);
+      if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0)
+       continue;
+      snprintf(buf, sizeof(buf), "%s/%s", reposdir, ent->d_name);
+      if ((fp = fopen(buf, "r")) == 0)
+       {
+         perror(buf);
+         continue;
+       }
+      cinfo = 0;
+      while(fgets(buf2, sizeof(buf2), fp))
+       {
+         l = strlen(buf2);
+         if (l == 0)
+           continue;
+         while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
+           buf2[--l] = 0;
+         kp = buf2;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp || *kp == '#')
+           continue;
+         if (strchr(kp, '$'))
+           kp = yum_substitute(pool, kp);
+         if (*kp == '[')
+           {
+             vp = strrchr(kp, ']');
+             if (!vp)
+               continue;
+             *vp = 0;
+             repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
+             cinfo = repoinfos + nrepoinfos++;
+             memset(cinfo, 0, sizeof(*cinfo));
+             cinfo->alias = strdup(kp + 1);
+             cinfo->type = TYPE_RPMMD;
+             cinfo->autorefresh = 1;
+             cinfo->priority = 99;
+#if !defined(FEDORA) && !defined(MAGEIA)
+             cinfo->repo_gpgcheck = 1;
+#endif
+             cinfo->metadata_expire = METADATA_EXPIRE;
+             continue;
+           }
+         if (!cinfo)
+           continue;
+          vp = strchr(kp, '=');
+         if (!vp)
+           continue;
+         for (kpe = vp - 1; kpe >= kp; kpe--)
+           if (*kpe != ' ' && *kpe != '\t')
+             break;
+         if (kpe == kp)
+           continue;
+         vp++;
+         while (*vp == ' ' || *vp == '\t')
+           vp++;
+         kpe[1] = 0;
+         if (!strcmp(kp, "name"))
+           cinfo->name = strdup(vp);
+         else if (!strcmp(kp, "enabled"))
+           cinfo->enabled = *vp == '0' ? 0 : 1;
+         else if (!strcmp(kp, "autorefresh"))
+           cinfo->autorefresh = *vp == '0' ? 0 : 1;
+         else if (!strcmp(kp, "gpgcheck"))
+           cinfo->pkgs_gpgcheck = *vp == '0' ? 0 : 1;
+         else if (!strcmp(kp, "repo_gpgcheck"))
+           cinfo->repo_gpgcheck = *vp == '0' ? 0 : 1;
+         else if (!strcmp(kp, "baseurl"))
+           cinfo->baseurl = strdup(vp);
+         else if (!strcmp(kp, "mirrorlist"))
+           {
+             if (strstr(vp, "metalink"))
+               cinfo->metalink = strdup(vp);
+             else
+               cinfo->mirrorlist = strdup(vp);
+           }
+         else if (!strcmp(kp, "path"))
+           {
+             if (vp && strcmp(vp, "/") != 0)
+               cinfo->path = strdup(vp);
+           }
+         else if (!strcmp(kp, "type"))
+           {
+             if (!strcmp(vp, "yast2"))
+               cinfo->type = TYPE_SUSETAGS;
+             else if (!strcmp(vp, "rpm-md"))
+               cinfo->type = TYPE_RPMMD;
+             else if (!strcmp(vp, "plaindir"))
+               cinfo->type = TYPE_PLAINDIR;
+             else if (!strcmp(vp, "mdk"))
+               cinfo->type = TYPE_MDK;
+             else
+               cinfo->type = TYPE_UNKNOWN;
+           }
+         else if (!strcmp(kp, "priority"))
+           cinfo->priority = atoi(vp);
+         else if (!strcmp(kp, "keeppackages"))
+           cinfo->keeppackages = *vp == '0' ? 0 : 1;
+       }
+      fclose(fp);
+      cinfo = 0;
+    }
+  closedir(dir);
+  *nrepoinfosp = nrepoinfos;
+  return repoinfos;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_config_yum.h b/libsolv-0.7.2/examples/solv/repoinfo_config_yum.h
new file mode 100644 (file)
index 0000000..d7cb4f7
--- /dev/null
@@ -0,0 +1,2 @@
+extern char *yum_substitute(Pool *pool, char *line);
+extern struct repoinfo *read_repoinfos_yum(Pool *pool, int *nrepoinfosp);
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_download.c b/libsolv-0.7.2/examples/solv/repoinfo_download.c
new file mode 100644 (file)
index 0000000..f5ba8b9
--- /dev/null
@@ -0,0 +1,224 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "solv_xfopen.h"
+
+#include "repoinfo.h"
+#include "mirror.h"
+#include "checksig.h"
+#if defined(FEDORA) || defined(MAGEIA)
+#include "repoinfo_config_yum.h"
+#endif
+#include "repoinfo_download.h"
+
+static inline int
+opentmpfile()
+{
+  char tmpl[100];
+  int fd;
+
+  strcpy(tmpl, "/var/tmp/solvXXXXXX");
+  fd = mkstemp(tmpl);
+  if (fd < 0) 
+    {    
+      perror("mkstemp");
+      exit(1);
+    }    
+  unlink(tmpl);
+  return fd;
+}
+
+int
+verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype)
+{
+  char buf[1024];
+  const unsigned char *sum;
+  Chksum *h;
+  int l;
+
+  h = solv_chksum_create(chksumtype);
+  if (!h)
+    {
+      printf("%s: unknown checksum type\n", file);
+      return 0;
+    }
+  while ((l = read(fd, buf, sizeof(buf))) > 0)
+    solv_chksum_add(h, buf, l);
+  lseek(fd, 0, SEEK_SET);
+  l = 0;
+  sum = solv_chksum_get(h, &l);
+  if (memcmp(sum, chksum, l))
+    {
+      printf("%s: checksum mismatch\n", file);
+      solv_chksum_free(h, 0);
+      return 0;
+    }
+  solv_chksum_free(h, 0);
+  return 1;
+}
+
+FILE *
+curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete)
+{
+  FILE *fp;
+  pid_t pid;
+  int fd;
+  int status;
+  char url[4096];
+  const char *baseurl = cinfo->baseurl;
+
+  if (!baseurl)
+    {
+      if (!cinfo->metalink && !cinfo->mirrorlist)
+        return 0;
+      if (file != cinfo->metalink && file != cinfo->mirrorlist)
+       {
+         unsigned char mlchksum[32];
+         Id mlchksumtype = 0;
+         fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0);
+         if (!fp)
+           return 0;
+         if (cinfo->metalink)
+           cinfo->baseurl = findmetalinkurl(fp, mlchksum, &mlchksumtype);
+         else
+           cinfo->baseurl = findmirrorlisturl(fp);
+         fclose(fp);
+         if (!cinfo->baseurl)
+           return 0;
+#if defined(FEDORA) || defined(MAGEIA)
+         if (strchr(cinfo->baseurl, '$'))
+           {
+             char *b = yum_substitute(cinfo->repo->pool, cinfo->baseurl);
+             free(cinfo->baseurl);
+             cinfo->baseurl = strdup(b);
+           }
+#endif
+         if (!chksumtype && mlchksumtype && !strcmp(file, "repodata/repomd.xml"))
+           {
+             chksumtype = mlchksumtype;
+             chksum = mlchksum;
+           }
+         return curlfopen(cinfo, file, uncompress, chksum, chksumtype, markincomplete);
+       }
+      snprintf(url, sizeof(url), "%s", file);
+    }
+  else
+    {
+      const char *path = cinfo->path && strcmp(cinfo->path, "/") != 0 ? cinfo->path : "";
+      int l = strlen(baseurl);
+      int pl = strlen(path);
+      const char *sep = l && baseurl[l - 1] == '/' ? "" : "/";
+      const char *psep = pl && cinfo->path[pl - 1] == '/' ? "" : "/";
+      snprintf(url, sizeof(url), "%s%s%s%s%s", baseurl, sep, path, psep, file);
+    }
+  fd = opentmpfile();
+  // printf("url: %s\n", url);
+  if ((pid = fork()) == (pid_t)-1)
+    {
+      perror("fork");
+      exit(1);
+    }
+  if (pid == 0)
+    {
+      if (fd != 1)
+       {
+          dup2(fd, 1);
+         close(fd);
+       }
+      execlp("curl", "curl", "-f", "-s", "-L", url, (char *)0);
+      perror("curl");
+      _exit(0);
+    }
+  status = 0;
+  while (waitpid(pid, &status, 0) != pid)
+    ;
+  if (lseek(fd, 0, SEEK_END) == 0 && (!status || !chksumtype))
+    {
+      /* empty file */
+      close(fd);
+      return 0;
+    }
+  lseek(fd, 0, SEEK_SET);
+  if (status)
+    {
+      printf("%s: download error %d\n", file, status >> 8 ? status >> 8 : status);
+      if (markincomplete)
+       cinfo->incomplete = 1;
+      close(fd);
+      return 0;
+    }
+  if (chksumtype && !verify_checksum(fd, file, chksum, chksumtype))
+    {
+      if (markincomplete)
+       cinfo->incomplete = 1;
+      close(fd);
+      return 0;
+    }
+  fcntl(fd, F_SETFD, FD_CLOEXEC);
+  if (uncompress)
+    {
+      if (solv_xfopen_iscompressed(file) < 0)
+       {
+         printf("%s: unsupported compression\n", file);
+         if (markincomplete)
+           cinfo->incomplete = 1;
+         close(fd);
+         return 0;
+       }
+      fp = solv_xfopen_fd(file, fd, "r");
+    }
+  else
+    fp = fdopen(fd, "r");
+  if (!fp)
+    close(fd);
+  return fp;
+}
+
+FILE *
+downloadpackage(Solvable *s, const char *loc)
+{
+  const unsigned char *chksum;
+  Id chksumtype;
+  struct repoinfo *cinfo = s->repo->appdata;
+
+#ifdef ENABLE_SUSEREPO
+  if (cinfo->type == TYPE_SUSETAGS)
+    {
+      const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR);
+      loc = pool_tmpjoin(s->repo->pool, datadir ? datadir : "suse", "/", loc);
+    }
+#endif
+  chksumtype = 0;
+  chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
+  return curlfopen(cinfo, loc, 0, chksum, chksumtype, 0);
+}
+
+int
+downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool)
+{
+  FILE *sigfp;
+  sigfp = curlfopen(cinfo, sigurl, 0, 0, 0, 0); 
+  if (!sigfp)
+    {    
+      printf(" unsigned, skipped\n");
+      return 0;
+    }    
+  if (!*sigpool)
+    *sigpool = read_sigs();
+  if (!checksig(*sigpool, fp, sigfp))
+    {    
+      printf(" checksig failed, skipped\n");
+      fclose(sigfp);
+      return 0;
+    }    
+  fclose(sigfp);
+  return 1;
+}
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_download.h b/libsolv-0.7.2/examples/solv/repoinfo_download.h
new file mode 100644 (file)
index 0000000..2dfeaa0
--- /dev/null
@@ -0,0 +1,7 @@
+int verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype);
+
+FILE *curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete);
+
+FILE *downloadpackage(Solvable *s, const char *loc);
+int downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_system_debian.c b/libsolv-0.7.2/examples/solv/repoinfo_system_debian.c
new file mode 100644 (file)
index 0000000..f01be60
--- /dev/null
@@ -0,0 +1,108 @@
+#if defined(ENABLE_DEBIAN) && defined(DEBIAN)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_deb.h"
+#include "transaction.h"
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_system_debian.h"
+
+static void
+rundpkg(const char *arg, const char *name, int dupfd3, const char *rootdir)
+{
+  pid_t pid;
+  int status;
+
+  if ((pid = fork()) == (pid_t)-1)
+    {
+      perror("fork");
+      exit(1);
+    }
+  if (pid == 0)
+    {
+      if (!rootdir)
+       rootdir = "/";
+      if (dupfd3 != -1 && dupfd3 != 3)
+       {
+         dup2(dupfd3, 3);
+         close(dupfd3);
+       }
+      if (dupfd3 != -1)
+       fcntl(3, F_SETFD, 0);   /* clear CLOEXEC */
+      if (strcmp(arg, "--install") == 0)
+       execlp("dpkg", "dpkg", "--install", "--root", rootdir, "--force", "all", name, (char *)0);
+      else
+       execlp("dpkg", "dpkg", "--remove", "--root", rootdir, "--force", "all", name, (char *)0);
+      perror("dpkg");
+      _exit(0);
+    }
+  while (waitpid(pid, &status, 0) != pid)
+    ;
+  if (status)
+    {
+      printf("dpkg failed\n");
+      exit(1);
+    }
+}
+
+int
+read_installed_debian(struct repoinfo *cinfo)
+{
+  struct stat stb;
+  Repo *repo = cinfo->repo;
+  Pool *pool = repo->pool;
+
+  memset(&stb, 0, sizeof(stb));
+  printf("dpgk database:");
+  if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/dpkg/status"), &stb))
+    memset(&stb, 0, sizeof(stb));
+  calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, 0, cinfo->cookie);
+  cinfo->cookieset = 1;
+  if (usecachedrepo(cinfo, 0, 0))
+    {
+      printf(" cached\n");
+      return 1;
+    }
+  if (repo_add_debdb(repo, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
+    {
+      fprintf(stderr, "installed db: %s\n", pool_errstr(pool));
+      return 0;
+    }
+  repo_internalize(repo);
+  writecachedrepo(cinfo, 0, 0);
+  return 1;
+}
+
+void
+commit_transactionelement_debian(Pool *pool, Id type, Id p, FILE *fp)
+{
+  Solvable *s = pool_id2solvable(pool, p);
+  const char *rootdir = pool_get_rootdir(pool);
+
+  switch(type)
+    {   
+    case SOLVER_TRANSACTION_ERASE:
+      rundpkg("--remove", pool_id2str(pool, s->name), 0, rootdir);
+      break;
+    case SOLVER_TRANSACTION_INSTALL:
+    case SOLVER_TRANSACTION_MULTIINSTALL:
+      rewind(fp);
+      lseek(fileno(fp), 0, SEEK_SET);
+      rundpkg("--install", "/dev/fd/3", fileno(fp), rootdir);
+      break;
+    default:
+      break;
+    }   
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_system_debian.h b/libsolv-0.7.2/examples/solv/repoinfo_system_debian.h
new file mode 100644 (file)
index 0000000..c0e2b29
--- /dev/null
@@ -0,0 +1,2 @@
+int  read_installed_debian(struct repoinfo *cinfo);
+void commit_transactionelement_debian(Pool *pool, Id type, Id p, FILE *fp);
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.c b/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.c
new file mode 100644 (file)
index 0000000..b556afc
--- /dev/null
@@ -0,0 +1,164 @@
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_rpmdb.h"
+#if defined(ENABLE_SUSEREPO) && defined(SUSE)
+#include "repo_products.h"
+#endif
+#if defined(ENABLE_APPDATA)
+#include "repo_appdata.h"
+#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#include "transaction.h"
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_system_rpm.h"
+
+#ifdef SUSE
+# define PRODUCTS_PATH "/etc/products.d"
+#endif
+#ifdef ENABLE_APPDATA
+# define APPDATA_PATH "/usr/share/metainfo"
+# define APPDATA_LEGACY_PATH "/usr/share/appdata"
+#endif
+
+static void
+runrpm(const char *arg, const char *name, int dupfd3, const char *rootdir)
+{
+  pid_t pid;
+  int status;
+
+  if ((pid = fork()) == (pid_t)-1)
+    {
+      perror("fork");
+      exit(1);
+    }
+  if (pid == 0)
+    {
+      if (!rootdir)
+       rootdir = "/";
+      if (dupfd3 != -1 && dupfd3 != 3)
+       {
+         dup2(dupfd3, 3);
+         close(dupfd3);
+       }
+      if (dupfd3 != -1)
+       fcntl(3, F_SETFD, 0);   /* clear CLOEXEC */
+      if (strcmp(arg, "-e") == 0)
+       execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0);
+      else
+       execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0);
+      perror("rpm");
+      _exit(0);
+    }
+  while (waitpid(pid, &status, 0) != pid)
+    ;
+  if (status)
+    {
+      printf("rpm failed\n");
+      exit(1);
+    }
+}
+
+int
+read_installed_rpm(struct repoinfo *cinfo)
+{
+  Repo *repo = cinfo->repo;
+  Pool *pool = repo->pool;
+  FILE *ofp = 0;
+  struct stat stb;
+
+  memset(&stb, 0, sizeof(stb));
+  printf("rpm database:");
+  if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/rpm/Packages"), &stb))
+    memset(&stb, 0, sizeof(stb));
+  calc_cookie_stat(&stb, REPOKEY_TYPE_SHA256, 0, cinfo->cookie);
+  cinfo->cookieset = 1;
+  if (usecachedrepo(cinfo, 0, 0))
+    {
+      printf(" cached\n");
+      return 1;
+    }
+  printf(" reading\n");
+#if defined(ENABLE_SUSEREPO) && defined(PRODUCTS_PATH)
+  if (repo_add_products(repo, PRODUCTS_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
+    {
+      fprintf(stderr, "product reading failed: %s\n", pool_errstr(pool));
+      return 0;
+    }
+#endif
+#if defined(ENABLE_APPDATA) && defined(APPDATA_PATH)
+  if (repo_add_appdata_dir(repo, APPDATA_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
+    {
+      fprintf(stderr, "appdata reading failed: %s\n", pool_errstr(pool));
+      return 0;
+    }
+#elif defined(ENABLE_APPDATA) && defined(APPDATA_LEGACY_PATH)
+  if (repo_add_appdata_dir(repo, APPDATA_LEGACY_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
+    {
+      fprintf(stderr, "appdata reading from legacy dir failed: %s\n", pool_errstr(pool));
+      return 0;
+    }
+#endif
+  ofp = fopen(calc_cachepath(repo, 0, 0), "r");
+  if (repo_add_rpmdb_reffp(repo, ofp, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR))
+    {
+      fprintf(stderr, "installed db: %s\n", pool_errstr(pool));
+      return 0;
+    }
+  if (ofp)
+    fclose(ofp);
+  repo_internalize(repo);
+#ifdef SUSE
+  repo_add_autopattern(repo, 0);
+#endif
+  writecachedrepo(cinfo, 0, 0);
+  return 1;
+}
+
+void
+commit_transactionelement_rpm(Pool *pool, Id type, Id p, FILE *fp)
+{
+  Solvable *s = pool_id2solvable(pool, p);
+  const char *rootdir = pool_get_rootdir(pool);
+  const char *evr, *evrp, *nvra;
+
+  switch(type)
+    {
+    case SOLVER_TRANSACTION_ERASE:
+      if (!s->repo->rpmdbid || !s->repo->rpmdbid[p - s->repo->start])
+       break;
+      /* strip epoch from evr */
+      evr = evrp = pool_id2str(pool, s->evr);
+      while (*evrp >= '0' && *evrp <= '9')
+       evrp++;
+      if (evrp > evr && evrp[0] == ':' && evrp[1])
+       evr = evrp + 1;
+      nvra = pool_tmpjoin(pool, pool_id2str(pool, s->name), "-", evr);
+      nvra = pool_tmpappend(pool, nvra, ".", pool_id2str(pool, s->arch));
+      runrpm("-e", nvra, -1, rootdir);      /* too bad that --querybynumber doesn't work */
+      break;
+    case SOLVER_TRANSACTION_INSTALL:
+    case SOLVER_TRANSACTION_MULTIINSTALL:
+      rewind(fp);
+      lseek(fileno(fp), 0, SEEK_SET);
+      runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp), rootdir);
+      break;
+    default:
+      break;
+    }
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.h b/libsolv-0.7.2/examples/solv/repoinfo_system_rpm.h
new file mode 100644 (file)
index 0000000..db63a8d
--- /dev/null
@@ -0,0 +1,2 @@
+int  read_installed_rpm(struct repoinfo *cinfo);
+void commit_transactionelement_rpm(Pool *pool, Id type, Id p, FILE *fp);
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_debian.c b/libsolv-0.7.2/examples/solv/repoinfo_type_debian.c
new file mode 100644 (file)
index 0000000..7a15ff4
--- /dev/null
@@ -0,0 +1,202 @@
+#ifdef ENABLE_DEBIAN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "repo_deb.h"
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_download.h"
+#include "repoinfo_type_debian.h"
+
+static const char *
+debian_find_component(struct repoinfo *cinfo, FILE *fp, char *comp, const unsigned char **chksump, Id *chksumtypep)
+{
+  char buf[4096];
+  Id chksumtype;
+  unsigned char *chksum;
+  Id curchksumtype;
+  int l, compl;
+  char *ch, *fn, *bp;
+  char *filename;
+  static char *basearch;
+  char *binarydir;
+  int lbinarydir;
+
+  if (!basearch)
+    {
+      struct utsname un;
+      if (uname(&un))
+       {
+         perror("uname");
+         exit(1);
+       }
+      basearch = strdup(un.machine);
+      if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86"))
+       basearch[1] = '3';
+    }
+  binarydir = solv_dupjoin("binary-", basearch, "/");
+  lbinarydir = strlen(binarydir);
+  compl = strlen(comp);
+  rewind(fp);
+  curchksumtype = 0;
+  filename = 0;
+  chksum = solv_malloc(32);
+  chksumtype = 0;
+  while(fgets(buf, sizeof(buf), fp))
+    {
+      l = strlen(buf);
+      if (l == 0)
+       continue;
+      while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+       buf[--l] = 0;
+      if (!strncasecmp(buf, "MD5Sum:", 7))
+       {
+         curchksumtype = REPOKEY_TYPE_MD5;
+         continue;
+       }
+      if (!strncasecmp(buf, "SHA1:", 5))
+       {
+         curchksumtype = REPOKEY_TYPE_SHA1;
+         continue;
+       }
+      if (!strncasecmp(buf, "SHA256:", 7))
+       {
+         curchksumtype = REPOKEY_TYPE_SHA256;
+         continue;
+       }
+      if (!curchksumtype)
+       continue;
+      bp = buf;
+      if (*bp++ != ' ')
+       {
+         curchksumtype = 0;
+         continue;
+       }
+      ch = bp;
+      while (*bp && *bp != ' ' && *bp != '\t')
+       bp++;
+      if (!*bp)
+       continue;
+      *bp++ = 0;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      while (*bp && *bp != ' ' && *bp != '\t')
+       bp++;
+      if (!*bp)
+       continue;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      fn = bp;
+      if (strncmp(fn, comp, compl) != 0 || fn[compl] != '/')
+       continue;
+      bp += compl + 1;
+      if (strncmp(bp, binarydir, lbinarydir))
+       continue;
+      bp += lbinarydir;
+      if (!strcmp(bp, "Packages") || !strcmp(bp, "Packages.gz"))
+       {
+         unsigned char curchksum[32];
+         int curl;
+         if (filename && !strcmp(bp, "Packages"))
+           continue;
+         curl = solv_chksum_len(curchksumtype);
+         if (!curl || (chksumtype && solv_chksum_len(chksumtype) > curl))
+           continue;
+          if (solv_hex2bin((const char **)&ch, curchksum, sizeof(curchksum)) != curl)
+           continue;
+         solv_free(filename);
+         filename = strdup(fn);
+         chksumtype = curchksumtype;
+         memcpy(chksum, curchksum, curl);
+       }
+    }
+  free(binarydir);
+  if (filename)
+    {
+      fn = solv_dupjoin("/", filename, 0);
+      solv_free(filename);
+      filename = solv_dupjoin("dists/", cinfo->name, fn);
+      solv_free(fn);
+    }
+  if (!chksumtype)
+    chksum = solv_free(chksum);
+  *chksump = chksum;
+  *chksumtypep = chksumtype;
+  return filename;
+}
+
+int
+debian_load(struct repoinfo *cinfo, Pool **sigpoolp)
+{
+  Repo *repo = cinfo->repo;
+  Pool *pool = repo->pool;
+  const char *filename;
+  const unsigned char *filechksum;
+  Id filechksumtype;
+  FILE *fp, *fpr;
+  int j;
+
+  printf("debian repo '%s':", cinfo->alias);
+  fflush(stdout);
+  filename = solv_dupjoin("dists/", cinfo->name, "/Release");
+  if ((fpr = curlfopen(cinfo, filename, 0, 0, 0, 0)) == 0)
+    {
+      printf(" no Release file\n");
+      free((char *)filename);
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  solv_free((char *)filename);
+  if (cinfo->repo_gpgcheck)
+    {
+      filename = solv_dupjoin("dists/", cinfo->name, "/Release.gpg");
+      if (!downloadchecksig(cinfo, fpr, filename, sigpoolp))
+       {
+         fclose(fpr);
+         solv_free((char *)filename);
+         cinfo->incomplete = 1;
+         return 0;
+       }
+      solv_free((char *)filename);
+    }
+  calc_cookie_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie);
+  cinfo->cookieset = 1;
+  if (usecachedrepo(cinfo, 0, 1))
+    {
+      printf(" cached\n");
+      fclose(fpr);
+      return 1;
+    }
+  printf(" fetching\n");
+  for (j = 0; j < cinfo->ncomponents; j++)
+    {
+      if (!(filename = debian_find_component(cinfo, fpr, cinfo->components[j], &filechksum, &filechksumtype)))
+       {
+         printf("[component %s not found]\n", cinfo->components[j]);
+         continue;
+       }
+      if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
+       {
+         if (repo_add_debpackages(repo, fp, 0))
+           {
+             printf("component %s: %s\n", cinfo->components[j], pool_errstr(pool));
+             cinfo->incomplete = 1;
+           }
+         fclose(fp);
+       }
+      solv_free((char *)filechksum);
+      solv_free((char *)filename);
+    }
+  fclose(fpr);
+  writecachedrepo(cinfo, 0, 0);
+  return 1;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_debian.h b/libsolv-0.7.2/examples/solv/repoinfo_type_debian.h
new file mode 100644 (file)
index 0000000..3dfc827
--- /dev/null
@@ -0,0 +1,2 @@
+extern int debian_load(struct repoinfo *cinfo, Pool **sigpoolp);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.c b/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.c
new file mode 100644 (file)
index 0000000..69287b3
--- /dev/null
@@ -0,0 +1,220 @@
+#ifdef ENABLE_MDKREPO
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "repo_mdk.h"
+#include "solv_xfopen.h"
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_download.h"
+#include "repoinfo_type_mdk.h"
+
+static int
+mdk_find(const char *md5sums, const char *what, unsigned char *chksum)
+{
+  const char *sp, *ep;
+  int wl = strlen(what);
+  for (sp = md5sums; (ep = strchr(sp, '\n')) != 0; sp = ep + 1)
+    {
+      int l = ep - sp;
+      if (l <= 34)
+       continue;
+      if (sp[32] != ' ' || sp[33] != ' ')
+       continue;
+      if (wl != l - 34 || strncmp(what, sp + 34, wl) != 0)
+       continue;
+      if (solv_hex2bin(&sp, chksum, 16) != 16)
+       continue;
+      return 1;
+    }
+  return 0;
+}
+
+static char *
+slurp(FILE *fp)
+{
+  int l, ll;
+  char *buf = 0;
+  int bufl = 0;
+
+  for (l = 0; ; l += ll)
+    {
+      if (bufl - l < 4096)
+        {
+          bufl += 4096;
+          buf = solv_realloc(buf, bufl);
+        }
+      ll = fread(buf + l, 1, bufl - l, fp);
+      if (ll < 0)
+        {
+          buf = solv_free(buf);
+          l = 0;
+          break;
+        }
+      if (ll == 0)
+        {
+          buf[l] = 0;
+          break;
+        }
+    }
+  return buf;
+}
+
+int
+mdk_load_ext(Repo *repo, Repodata *data)
+{
+  struct repoinfo *cinfo = repo->appdata;
+  const char *type, *ext, *filename;
+  const unsigned char *filechksum;
+  Id filechksumtype;
+  int r = 0;
+  FILE *fp;
+
+  type = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE);
+  if (strcmp(type, "filelists") != 0)
+    return 0;
+  ext = "FL";
+  printf("[%s:%s", repo->name, ext);
+  if (usecachedrepo(cinfo, ext, 0))
+    {
+      printf(" cached]\n"); fflush(stdout);
+      return 1;
+    }
+  printf(" fetching]\n"); fflush(stdout);
+  filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION);
+  filechksumtype = 0;
+  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype);
+  if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 0)) == 0)
+    return 0;
+  r = repo_add_mdk_info(repo, fp, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
+  fclose(fp);
+  if (r)
+    {
+      printf("%s\n", pool_errstr(repo->pool));
+      return 0;
+    }
+  writecachedrepo(cinfo, ext, data);
+  return 1;
+}
+
+static void
+mdk_add_ext(Repo *repo, Repodata *data, const char *what, const char *ext, const char *filename, Id chksumtype, const unsigned char *chksum)
+{
+  Id handle = repodata_new_handle(data);
+  /* we mis-use the repomd ids here... need something generic in the future */
+  repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, what);
+  repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, filename);
+  repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, chksumtype, chksum);
+  add_ext_keys(data, handle, ext);
+  repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
+}
+
+int
+mdk_load(struct repoinfo *cinfo, Pool **sigpoolp)
+{
+  Repo *repo = cinfo->repo;
+  Pool *pool = repo->pool;
+  Repodata *data;
+  const char *compression;
+  FILE *fp, *cfp;
+  char *md5sums;
+  unsigned char probe[5];
+  unsigned char md5[16];
+
+  printf("mdk repo '%s':", cinfo->alias);
+  fflush(stdout);
+  if ((fp = curlfopen(cinfo, "media_info/MD5SUM", 0, 0, 0, 0)) == 0)
+    {
+      printf(" no media_info/MD5SUM file\n");
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
+  cinfo->cookieset = 1;
+  if (usecachedrepo(cinfo, 0, 1))
+    {
+      printf(" cached\n");
+      fclose(fp);
+      return 1;
+    }
+  md5sums = slurp(fp);
+  fclose(fp);
+  printf(" fetching\n");
+  if (!mdk_find(md5sums, "synthesis.hdlist.cz", md5))
+    {
+      solv_free(md5sums);
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  if ((fp = curlfopen(cinfo, "media_info/synthesis.hdlist.cz", 0, md5, REPOKEY_TYPE_MD5, 1)) == 0)
+    {
+      solv_free(md5sums);
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  /* probe compression */
+  if (fread(probe, 5, 1, fp) != 1)
+    {
+      fclose(fp);
+      solv_free(md5sums);
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  if (probe[0] == 0xfd && memcmp(probe + 1, "7zXZ", 4) == 0)
+    compression = "synthesis.hdlist.xz";
+  else
+    compression = "synthesis.hdlist.gz";
+  lseek(fileno(fp), 0, SEEK_SET);
+  cfp = solv_xfopen_fd(compression, dup(fileno(fp)), "r");
+  fclose(fp);
+  fp = cfp;
+  if (!fp)
+    {
+      solv_free(md5sums);
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  if (repo_add_mdk(repo, fp, REPO_NO_INTERNALIZE))
+    {
+      printf("synthesis.hdlist.cz: %s\n", pool_errstr(pool));
+      fclose(fp);
+      solv_free(md5sums);
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  fclose(fp);
+  /* add info, could do this on demand, but always having the summary is nice */
+  if (mdk_find(md5sums, "info.xml.lzma", md5))
+    {
+      if ((fp = curlfopen(cinfo, "media_info/info.xml.lzma", 1, md5, REPOKEY_TYPE_MD5, 1)) != 0)
+       {
+         if (repo_add_mdk_info(repo, fp, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES))
+           {
+             printf("info.xml.lzma: %s\n", pool_errstr(pool));
+             cinfo->incomplete = 1;
+           }
+         fclose(fp);
+       }
+    }
+  repo_internalize(repo);
+  data = repo_add_repodata(repo, 0);
+  /* setup on-demand loading of filelist data */
+  if (mdk_find(md5sums, "files.xml.lzma", md5))
+    {
+      repodata_extend_block(data, repo->start, repo->end - repo->start);
+      mdk_add_ext(repo, data, "filelists", "FL", "media_info/files.xml.lzma", REPOKEY_TYPE_MD5, md5);
+    }
+  solv_free(md5sums);
+  repodata_internalize(data);
+  writecachedrepo(cinfo, 0, 0);
+  repodata_create_stubs(repo_last_repodata(repo));
+  return 1;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.h b/libsolv-0.7.2/examples/solv/repoinfo_type_mdk.h
new file mode 100644 (file)
index 0000000..e98bc48
--- /dev/null
@@ -0,0 +1,3 @@
+extern int mdk_load(struct repoinfo *cinfo, Pool **sigpoolp);
+extern int mdk_load_ext(Repo *repo, Repodata *data);
+
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.c b/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.c
new file mode 100644 (file)
index 0000000..7828379
--- /dev/null
@@ -0,0 +1,214 @@
+#ifdef ENABLE_RPMMD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "repo_rpmmd.h"
+#include "repo_deltainfoxml.h"
+#include "repo_updateinfoxml.h"
+#include "repo_repomdxml.h"
+#ifdef ENABLE_APPDATA
+#include "repo_appdata.h"
+#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_download.h"
+#include "repoinfo_type_rpmmd.h"
+
+
+
+static const char *
+repomd_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep)
+{
+  Pool *pool = repo->pool;
+  Dataiterator di;
+  const char *filename;
+
+  filename = 0;
+  *chksump = 0;
+  *chksumtypep = 0;
+  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING);
+  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
+  if (dataiterator_step(&di))
+    {
+      dataiterator_setpos_parent(&di);
+      filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
+      *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, REPOSITORY_REPOMD_CHECKSUM, chksumtypep);
+    }
+  dataiterator_free(&di);
+  if (filename && !*chksumtypep)
+    {
+      printf("no %s file checksum!\n", what);
+      filename = 0;
+    }
+  return filename;
+}
+
+static void
+repomd_add_ext(Repo *repo, Repodata *data, const char *what, const char *ext)
+{
+  Id chksumtype, handle;
+  const unsigned char *chksum;
+  const char *filename;
+
+  filename = repomd_find(repo, what, &chksum, &chksumtype);
+  if (!filename && !strcmp(what, "deltainfo"))
+    filename = repomd_find(repo, "prestodelta", &chksum, &chksumtype);
+  if (!filename)
+    return;
+  handle = repodata_new_handle(data);
+  repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, what);
+  repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, filename);
+  repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, chksumtype, chksum);
+  add_ext_keys(data, handle, ext);
+  repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
+}
+
+int
+repomd_load_ext(Repo *repo, Repodata *data)
+{
+  const char *filename, *repomdtype;
+  char ext[3];
+  FILE *fp;
+  struct repoinfo *cinfo;
+  const unsigned char *filechksum;
+  Id filechksumtype;
+  int r = 0;
+
+  cinfo = repo->appdata;
+  repomdtype = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE);
+  if (!repomdtype)
+    return 0;
+  if (!strcmp(repomdtype, "filelists"))
+    strcpy(ext, "FL");
+  else if (!strcmp(repomdtype, "deltainfo"))
+    strcpy(ext, "DL");
+  else
+    return 0;
+  printf("[%s:%s", repo->name, ext);
+  if (usecachedrepo(cinfo, ext, 0))
+    {
+      printf(" cached]\n"); fflush(stdout);
+      return 1;
+    }
+  printf(" fetching]\n"); fflush(stdout);
+  filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION);
+  filechksumtype = 0;
+  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype);
+  if ((fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 0)) == 0)
+    return 0;
+  if (!strcmp(ext, "FL"))
+    r = repo_add_rpmmd(repo, fp, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
+  else if (!strcmp(ext, "DL"))
+    r = repo_add_deltainfoxml(repo, fp, REPO_USE_LOADING);
+  fclose(fp);
+  if (r)
+    {
+      printf("%s\n", pool_errstr(repo->pool));
+      return 0;
+    }
+  if (cinfo->extcookieset)
+    writecachedrepo(cinfo, ext, data);
+  return 1;
+}
+
+int
+repomd_load(struct repoinfo *cinfo, Pool **sigpoolp)
+{
+  Repo *repo = cinfo->repo;
+  Pool *pool = repo->pool;
+  Repodata *data;
+  const char *filename;
+  const unsigned char *filechksum;
+  Id filechksumtype;
+  FILE *fp;
+
+  printf("rpmmd repo '%s':", cinfo->alias);
+  fflush(stdout);
+  if ((fp = curlfopen(cinfo, "repodata/repomd.xml", 0, 0, 0, 0)) == 0)
+    {
+      printf(" no repomd.xml file\n");
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
+  cinfo->cookieset = 1;
+  if (usecachedrepo(cinfo, 0, 1))
+    {
+      printf(" cached\n");
+      fclose(fp);
+      return 1;
+    }
+  if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "repodata/repomd.xml.asc", sigpoolp))
+    {
+      fclose(fp);
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  if (repo_add_repomdxml(repo, fp, 0))
+    {
+      printf("repomd.xml: %s\n", pool_errstr(pool));
+      cinfo->incomplete = 1;
+      fclose(fp);
+      return 0;
+    }
+  fclose(fp);
+  printf(" fetching\n");
+  filename = repomd_find(repo, "primary", &filechksum, &filechksumtype);
+  if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
+    {
+      if (repo_add_rpmmd(repo, fp, 0, 0))
+       {
+         printf("primary: %s\n", pool_errstr(pool));
+         cinfo->incomplete = 1;
+       }
+      fclose(fp);
+    }
+  if (cinfo->incomplete)
+    return 0;  /* hopeless */
+
+  filename = repomd_find(repo, "updateinfo", &filechksum, &filechksumtype);
+  if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
+    {
+      if (repo_add_updateinfoxml(repo, fp, 0))
+       {
+         printf("updateinfo: %s\n", pool_errstr(pool));
+         cinfo->incomplete = 1;
+       }
+      fclose(fp);
+    }
+
+#ifdef ENABLE_APPDATA
+  filename = repomd_find(repo, "appdata", &filechksum, &filechksumtype);
+  if (filename && (fp = curlfopen(cinfo, filename, 1, filechksum, filechksumtype, 1)) != 0)
+    {
+      if (repo_add_appdata(repo, fp, 0))
+       {
+         printf("appdata: %s\n", pool_errstr(pool));
+         cinfo->incomplete = 1;
+       }
+      fclose(fp);
+    }
+#endif
+#ifdef SUSE
+  repo_add_autopattern(repo, 0);
+#endif
+  data = repo_add_repodata(repo, 0);
+  repodata_extend_block(data, repo->start, repo->end - repo->start);
+  repomd_add_ext(repo, data, "deltainfo", "DL");
+  repomd_add_ext(repo, data, "filelists", "FL");
+  repodata_internalize(data);
+  writecachedrepo(cinfo, 0, 0);
+  repodata_create_stubs(repo_last_repodata(repo));
+  return 1;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.h b/libsolv-0.7.2/examples/solv/repoinfo_type_rpmmd.h
new file mode 100644 (file)
index 0000000..275dfc1
--- /dev/null
@@ -0,0 +1,2 @@
+extern int repomd_load_ext(Repo *repo, Repodata *data);
+extern int repomd_load(struct repoinfo *cinfo, Pool **sigpoolp);
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.c b/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.c
new file mode 100644 (file)
index 0000000..af933af
--- /dev/null
@@ -0,0 +1,281 @@
+#ifdef ENABLE_SUSEREPO
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "repo_content.h"
+#include "repo_susetags.h"
+#ifdef ENABLE_APPDATA
+#include "repo_appdata.h"
+#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_download.h"
+#include "repoinfo_type_susetags.h"
+
+/* susetags helpers */
+
+static const char *
+susetags_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chksumtypep)
+{
+  Pool *pool = repo->pool;
+  Dataiterator di;
+  const char *filename;
+
+  filename = 0;
+  *chksump = 0;
+  *chksumtypep = 0;
+  dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, what, SEARCH_STRING);
+  dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
+  if (dataiterator_step(&di))
+    {
+      dataiterator_setpos_parent(&di);
+      *chksump = pool_lookup_bin_checksum(pool, SOLVID_POS, SUSETAGS_FILE_CHECKSUM, chksumtypep);
+      filename = what;
+    }
+  dataiterator_free(&di);
+  if (filename && !*chksumtypep)
+    {
+      printf("no %s file checksum!\n", what);
+      filename = 0;
+    }
+  return filename;
+}
+
+static void
+susetags_add_ext(Repo *repo, Repodata *data)
+{
+  Pool *pool = repo->pool;
+  Dataiterator di;
+  char ext[3];
+  Id handle, filechksumtype;
+  const unsigned char *filechksum;
+
+  dataiterator_init(&di, pool, repo, SOLVID_META, SUSETAGS_FILE_NAME, 0, 0);
+  dataiterator_prepend_keyname(&di, SUSETAGS_FILE);
+  while (dataiterator_step(&di))
+    {
+      if (strncmp(di.kv.str, "packages.", 9) != 0)
+       continue;
+      if (!strcmp(di.kv.str + 9, "gz"))
+       continue;
+      if (!di.kv.str[9] || !di.kv.str[10] || (di.kv.str[11] && di.kv.str[11] != '.'))
+       continue;
+      ext[0] = di.kv.str[9];
+      ext[1] = di.kv.str[10];
+      ext[2] = 0;
+      if (!strcmp(ext, "en"))
+       continue;
+      if (!susetags_find(repo, di.kv.str, &filechksum, &filechksumtype))
+       continue;
+      handle = repodata_new_handle(data);
+      repodata_set_str(data, handle, SUSETAGS_FILE_NAME, di.kv.str);
+      if (filechksumtype)
+       repodata_set_bin_checksum(data, handle, SUSETAGS_FILE_CHECKSUM, filechksumtype, filechksum);
+      add_ext_keys(data, handle, ext);
+      repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle);
+    }
+  dataiterator_free(&di);
+}
+
+int
+susetags_load_ext(Repo *repo, Repodata *data)
+{
+  const char *filename, *descrdir;
+  Id defvendor;
+  char ext[3];
+  FILE *fp;
+  struct repoinfo *cinfo;
+  const unsigned char *filechksum;
+  Id filechksumtype;
+  int flags;
+
+  cinfo = repo->appdata;
+  filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME);
+  if (!filename)
+    return 0;
+  /* susetags load */
+  ext[0] = filename[9];
+  ext[1] = filename[10];
+  ext[2] = 0;
+  printf("[%s:%s", repo->name, ext);
+  if (usecachedrepo(cinfo, ext, 0))
+    {
+      printf(" cached]\n"); fflush(stdout);
+      return 1;
+    }
+  printf(" fetching]\n"); fflush(stdout);
+  defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+  descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
+  if (!descrdir)
+    descrdir = "suse/setup/descr";
+  filechksumtype = 0;
+  filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, SUSETAGS_FILE_CHECKSUM, &filechksumtype);
+  if ((fp = curlfopen(cinfo, pool_tmpjoin(repo->pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 0)) == 0)
+    return 0;
+  flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
+  if (strcmp(ext, "DL") != 0)
+    flags |= REPO_LOCALPOOL;
+  if (repo_add_susetags(repo, fp, defvendor, ext, flags))
+    {
+      fclose(fp);
+      printf("%s\n", pool_errstr(repo->pool));
+      return 0;
+    }
+  fclose(fp);
+  writecachedrepo(cinfo, ext, data);
+  return 1;
+}
+
+int
+susetags_load(struct repoinfo *cinfo, Pool **sigpoolp)
+{
+  Repo *repo = cinfo->repo;
+  Pool *pool = repo->pool;
+  Repodata *data;
+  const char *filename;
+  const unsigned char *filechksum;
+  Id filechksumtype;
+  FILE *fp;
+  const char *descrdir;
+  int defvendor;
+
+  printf("susetags repo '%s':", cinfo->alias);
+  fflush(stdout);
+  descrdir = 0;
+  defvendor = 0;
+  if ((fp = curlfopen(cinfo, "content", 0, 0, 0, 0)) == 0)
+    {
+      printf(" no content file\n");
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  calc_cookie_fp(fp, REPOKEY_TYPE_SHA256, cinfo->cookie);
+  cinfo->cookieset = 1;
+  if (usecachedrepo(cinfo, 0, 1))
+    {
+      printf(" cached\n");
+      fclose(fp);
+      return 1;
+    }
+  if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "content.asc", sigpoolp))
+    {
+      fclose(fp);
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  if (repo_add_content(repo, fp, 0))
+    {
+      printf("content: %s\n", pool_errstr(pool));
+      fclose(fp);
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  fclose(fp);
+  defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+  descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
+  if (!descrdir)
+    descrdir = "suse/setup/descr";
+  filename = susetags_find(repo, "packages.gz", &filechksum, &filechksumtype);
+  if (!filename)
+    filename = susetags_find(repo, "packages", &filechksum, &filechksumtype);
+  if (!filename)
+    {
+      printf(" no packages file entry, skipped\n");
+      cinfo->incomplete = 1;
+      return 0;
+    }
+  printf(" fetching\n");
+  if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) == 0)
+    {
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES))
+    {
+      printf("packages: %s\n", pool_errstr(pool));
+      fclose(fp);
+      cinfo->incomplete = 1;
+      return 0;        /* hopeless */
+    }
+  fclose(fp);
+  /* add default language */
+  filename = susetags_find(repo, "packages.en.gz", &filechksum, &filechksumtype);
+  if (!filename)
+    filename = susetags_find(repo, "packages.en", &filechksum, &filechksumtype);
+  if (filename)
+    {
+      if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
+       {
+         if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES))
+           {
+             printf("packages.en: %s\n", pool_errstr(pool));
+             cinfo->incomplete = 1;
+           }
+         fclose(fp);
+       }
+    }
+  filename = susetags_find(repo, "patterns", &filechksum, &filechksumtype);
+  if (filename)
+    {
+      if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
+       {
+         char pbuf[256];
+         while (fgets(pbuf, sizeof(pbuf), fp))
+           {
+             int l = strlen(pbuf);
+             FILE *fp2;
+             if (l && pbuf[l - 1] == '\n')
+               pbuf[--l] = 0;
+             if (!*pbuf || *pbuf == '.' || strchr(pbuf, '/') != 0)
+               continue;
+             filename = susetags_find(repo, pbuf, &filechksum, &filechksumtype);
+             if (filename && (fp2 = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
+               {
+                 if (repo_add_susetags(repo, fp2, defvendor, 0, REPO_NO_INTERNALIZE))
+                   {
+                     printf("%s: %s\n", pbuf, pool_errstr(pool));
+                     cinfo->incomplete = 1;
+                   }
+                 fclose(fp2);
+               }
+           }
+         fclose(fp);
+       }
+    }
+#ifdef ENABLE_APPDATA
+  filename = susetags_find(repo, "appdata.xml.gz", &filechksum, &filechksumtype);
+  if (!filename)
+    filename = susetags_find(repo, "appdata.xml", &filechksum, &filechksumtype);
+  if (filename && (fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), 1, filechksum, filechksumtype, 1)) != 0)
+    {
+      if (repo_add_appdata(repo, fp, 0))
+       {
+         printf("appdata: %s\n", pool_errstr(pool));
+         cinfo->incomplete = 1;
+       }
+      fclose(fp);
+    }
+#endif
+  repo_internalize(repo);
+#ifdef SUSE
+  repo_add_autopattern(repo, 0);
+#endif
+  data = repo_add_repodata(repo, 0);
+  repodata_extend_block(data, repo->start, repo->end - repo->start);
+  susetags_add_ext(repo, data);
+  repodata_internalize(data);
+  writecachedrepo(cinfo, 0, 0);
+  repodata_create_stubs(repo_last_repodata(repo));
+  return 1;
+}
+
+#endif
diff --git a/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.h b/libsolv-0.7.2/examples/solv/repoinfo_type_susetags.h
new file mode 100644 (file)
index 0000000..2ad5778
--- /dev/null
@@ -0,0 +1,2 @@
+extern int susetags_load_ext(Repo *repo, Repodata *data);
+extern int susetags_load(struct repoinfo *cinfo, Pool **sigpoolp);
diff --git a/libsolv-0.7.2/examples/solv/solv.c b/libsolv-0.7.2/examples/solv/solv.c
new file mode 100644 (file)
index 0000000..3deb1a0
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (c) 2009-2015, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* solv, a little software installer demoing the sat solver library */
+
+/* things it does:
+ * - understands globs for package names / dependencies
+ * - understands .arch suffix
+ * - installation of commandline packages
+ * - repository data caching
+ * - on demand loading of secondary repository data
+ * - gpg and checksum verification
+ * - file conflicts
+ * - deltarpm support
+ * - fastestmirror implementation
+ *
+ * things available in the library but missing from solv:
+ * - vendor policy loading
+ * - multi version handling
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+#include "pool.h"
+#include "poolarch.h"
+#include "evr.h"
+#include "selection.h"
+#include "repo.h"
+#include "solver.h"
+#include "solverdebug.h"
+#include "transaction.h"
+#include "testcase.h"
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+
+#include "repoinfo.h"
+#include "repoinfo_cache.h"
+#include "repoinfo_download.h"
+
+#if defined(ENABLE_RPMDB)
+#include "fileprovides.h"
+#include "fileconflicts.h"
+#include "deltarpm.h"
+#endif
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+#include "patchjobs.h"
+#endif
+
+void
+setarch(Pool *pool)
+{
+  struct utsname un;
+  if (uname(&un))
+    {
+      perror("uname");
+      exit(1);
+    }
+  pool_setarch(pool, un.machine);
+}
+
+
+int
+yesno(const char *str, int other)
+{
+  char inbuf[128], *ip;
+
+  for (;;)
+    {
+      printf("%s", str);
+      fflush(stdout);
+      *inbuf = 0;
+      if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
+       {
+         printf("Abort.\n");
+         exit(1);
+       }
+      while (*ip == ' ' || *ip == '\t')
+       ip++;
+      if (*ip == 'q')
+       {
+         printf("Abort.\n");
+         exit(1);
+       }
+      if (*ip == 'y' || *ip == 'n' || *ip == other)
+       return *ip == 'n' ? 0 : *ip;
+    }
+}
+
+#ifdef SUSE
+static Id
+nscallback(Pool *pool, void *data, Id name, Id evr)
+{
+#if 0
+  if (name == NAMESPACE_LANGUAGE)
+    {
+      if (!strcmp(pool_id2str(pool, evr), "ja"))
+       return 1;
+      if (!strcmp(pool_id2str(pool, evr), "de"))
+       return 1;
+      if (!strcmp(pool_id2str(pool, evr), "en"))
+       return 1;
+      if (!strcmp(pool_id2str(pool, evr), "en_US"))
+       return 1;
+    }
+#endif
+  return 0;
+}
+#endif
+
+#ifdef SUSE
+static void
+showdiskusagechanges(Transaction *trans)
+{
+  DUChanges duc[4];
+  int i;
+
+  /* XXX: use mountpoints here */
+  memset(duc, 0, sizeof(duc));
+  duc[0].path = "/";
+  duc[1].path = "/usr/share/man";
+  duc[2].path = "/sbin";
+  duc[3].path = "/etc";
+  transaction_calc_duchanges(trans, duc, 4);
+  for (i = 0; i < 4; i++)
+    printf("duchanges %s: %lld K  %lld inodes\n", duc[i].path, duc[i].kbytes, duc[i].files);
+}
+#endif
+
+static Id
+find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
+{
+  const char *rp;
+  int i;
+
+  for (rp = name; *rp; rp++)
+    if (*rp <= '0' || *rp >= '9')
+      break;
+  if (!*rp)
+    {
+      /* repo specified by number */
+      int rnum = atoi(name);
+      for (i = 0; i < nrepoinfos; i++)
+       {
+         struct repoinfo *cinfo = repoinfos + i;
+         if (!cinfo->enabled || !cinfo->repo)
+           continue;
+         if (--rnum == 0)
+           return cinfo->repo->repoid;
+       }
+    }
+  else
+    {
+      /* repo specified by alias */
+      Repo *repo;
+      FOR_REPOS(i, repo)
+       {
+         if (!strcasecmp(name, repo->name))
+           return repo->repoid;
+       }
+    }
+  return 0;
+}
+
+#define MODE_LIST        0
+#define MODE_INSTALL     1
+#define MODE_ERASE       2
+#define MODE_UPDATE      3
+#define MODE_DISTUPGRADE 4
+#define MODE_VERIFY      5
+#define MODE_PATCH       6
+#define MODE_INFO        7
+#define MODE_REPOLIST    8
+#define MODE_SEARCH     9
+
+void
+usage(int r)
+{
+  fprintf(stderr, "Usage: solv COMMAND <select>\n");
+  fprintf(stderr, "\n");
+  fprintf(stderr, "    dist-upgrade: replace installed packages with\n");
+  fprintf(stderr, "                  versions from the repositories\n");
+  fprintf(stderr, "    erase:        erase installed packages\n");
+  fprintf(stderr, "    info:         display package information\n");
+  fprintf(stderr, "    install:      install packages\n");
+  fprintf(stderr, "    list:         list packages\n");
+  fprintf(stderr, "    repos:        list enabled repositories\n");
+  fprintf(stderr, "    search:       search name/summary/description\n");
+  fprintf(stderr, "    update:       update installed packages\n");
+  fprintf(stderr, "    verify:       check dependencies of installed packages\n");
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+  fprintf(stderr, "    patch:        install newest maintenance updates\n");
+#endif
+  fprintf(stderr, "\n");
+  exit(r);
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Repo *commandlinerepo = 0;
+  Id *commandlinepkgs = 0;
+  Id p;
+  struct repoinfo *repoinfos, installedrepoinfo;
+  int nrepoinfos = 0;
+  int mainmode = 0, mode = 0;
+  int i, newpkgs;
+  Queue job, checkq;
+  Solver *solv = 0;
+  Transaction *trans;
+  FILE **newpkgsfps;
+  Queue repofilter;
+  Queue kindfilter;
+  Queue archfilter;
+  int archfilter_src = 0;
+  int cleandeps = 0;
+  int forcebest = 0;
+  char *rootdir = 0;
+  char *keyname = 0;
+  int keyname_depstr = 0;
+  int keyname_alldeps = 0;             /* dnf repoquesy --alldeps */
+  int debuglevel = 0;
+  int answer, acnt = 0;
+  char *testcase = 0;
+
+  argc--;
+  argv++;
+  while (argc && !strcmp(argv[0], "-d"))
+    {
+      debuglevel++;
+      argc--;
+      argv++;
+    }
+  if (!argv[0])
+    usage(1);
+  if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in"))
+    {
+      mainmode = MODE_INSTALL;
+      mode = SOLVER_INSTALL;
+    }
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+  else if (!strcmp(argv[0], "patch"))
+    {
+      mainmode = MODE_PATCH;
+      mode = SOLVER_INSTALL;
+    }
+#endif
+  else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm"))
+    {
+      mainmode = MODE_ERASE;
+      mode = SOLVER_ERASE;
+    }
+  else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "ls"))
+    {
+      mainmode = MODE_LIST;
+      mode = 0;
+    }
+  else if (!strcmp(argv[0], "info"))
+    {
+      mainmode = MODE_INFO;
+      mode = 0;
+    }
+  else if (!strcmp(argv[0], "search") || !strcmp(argv[0], "se"))
+    {
+      mainmode = MODE_SEARCH;
+      mode = 0;
+    }
+  else if (!strcmp(argv[0], "verify"))
+    {
+      mainmode = MODE_VERIFY;
+      mode = SOLVER_VERIFY;
+    }
+  else if (!strcmp(argv[0], "update") || !strcmp(argv[0], "up"))
+    {
+      mainmode = MODE_UPDATE;
+      mode = SOLVER_UPDATE;
+    }
+  else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup"))
+    {
+      mainmode = MODE_DISTUPGRADE;
+      mode = SOLVER_DISTUPGRADE;
+    }
+  else if (!strcmp(argv[0], "repos") || !strcmp(argv[0], "repolist") || !strcmp(argv[0], "lr"))
+    {
+      mainmode = MODE_REPOLIST;
+      mode = 0;
+    }
+  else
+    usage(1);
+
+  for (;;)
+    {
+      if (argc > 2 && !strcmp(argv[1], "--root"))
+       {
+         rootdir = argv[2];
+         argc -= 2;
+         argv += 2;
+       }
+      else if (argc > 1 && !strcmp(argv[1], "--clean"))
+       {
+         cleandeps = 1;
+         argc--;
+         argv++;
+       }
+      else if (argc > 1 && !strcmp(argv[1], "--best"))
+       {
+         forcebest = 1;
+         argc--;
+         argv++;
+       }
+      else if (argc > 1 && !strcmp(argv[1], "--alldeps"))
+       {
+         keyname_alldeps = 1;          /* dnf repoquesy --alldeps */
+         argc--;
+         argv++;
+       }
+      else if (argc > 1 && !strcmp(argv[1], "--depstr"))
+       {
+         keyname_depstr = 1;   /* do literal matching instead of dep intersection */
+         argc--;
+         argv++;
+       }
+      else if (argc > 2 && !strcmp(argv[1], "--keyname"))
+       {
+         keyname = argv[2];
+         argc -= 2;
+         argv += 2;
+       }
+      else if (argc > 2 && !strcmp(argv[1], "--testcase"))
+       {
+         testcase = argv[2];
+         argc -= 2;
+         argv += 2;
+       }
+      else
+       break;
+    }
+
+  set_userhome();
+  pool = pool_create();
+  pool_set_rootdir(pool, rootdir);
+
+#if 0
+  {
+    const char *langs[] = {"de_DE", "de", "en"};
+    pool_set_languages(pool, langs, sizeof(langs)/sizeof(*langs));
+  }
+#endif
+
+  pool_setloadcallback(pool, load_stub, 0);
+#ifdef SUSE
+  pool->nscallback = nscallback;
+#endif
+  if (debuglevel)
+    pool_setdebuglevel(pool, debuglevel);
+  setarch(pool);
+  pool_set_flag(pool, POOL_FLAG_ADDFILEPROVIDESFILTERED, 1);
+  repoinfos = read_repoinfos(pool, &nrepoinfos);
+  sort_repoinfos(repoinfos, nrepoinfos);
+
+  if (mainmode == MODE_REPOLIST)
+    {
+      int j = 1;
+      for (i = 0; i < nrepoinfos; i++)
+       {
+         struct repoinfo *cinfo = repoinfos + i;
+         if (!cinfo->enabled)
+           continue;
+         printf("%d: %-20s %s (prio %d)\n", j++, cinfo->alias, cinfo->name, cinfo->priority);
+       }
+      exit(0);
+    }
+  memset(&installedrepoinfo, 0, sizeof(installedrepoinfo));
+  if (!read_installed_repo(&installedrepoinfo, pool))
+    exit(1);
+  read_repos(pool, repoinfos, nrepoinfos);
+
+  /* setup filters */
+  queue_init(&repofilter);
+  queue_init(&kindfilter);
+  queue_init(&archfilter);
+  while (argc > 1)
+    {
+      if (!strcmp(argv[1], "-i"))
+       {
+         queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, pool->installed->repoid);
+         argc--;
+         argv++;
+       }
+      else if (argc > 2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "--repo")))
+       {
+         Id repoid = find_repo(argv[2], pool, repoinfos, nrepoinfos);
+         if (!repoid)
+           {
+             fprintf(stderr, "%s: no such repo\n", argv[2]);
+             exit(1);
+           }
+         /* SETVENDOR is actually wrong but useful */
+         queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO | SOLVER_SETVENDOR, repoid);
+         argc -= 2;
+         argv += 2;
+       }
+      else if (argc > 2 && !strcmp(argv[1], "--arch"))
+       {
+         if (!strcmp(argv[2], "src") || !strcmp(argv[2], "nosrc"))
+           archfilter_src = 1;
+         queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, argv[2], 1), REL_ARCH, 1));
+         argc -= 2;
+         argv += 2;
+       }
+      else if (argc > 2 && (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--type")))
+       {
+         const char *kind = argv[2];
+         if (!strcmp(kind, "srcpackage"))
+           {
+             /* hey! should use --arch! */
+             queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, ARCH_SRC, REL_ARCH, 1));
+             archfilter_src = 1;
+             argc -= 2;
+             argv += 2;
+             continue;
+           }
+         if (!strcmp(kind, "package"))
+           kind = "";
+         if (!strcmp(kind, "all"))
+           queue_push2(&kindfilter, SOLVER_SOLVABLE_ALL, 0);
+         else
+           queue_push2(&kindfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, kind, 1), REL_KIND, 1));
+         argc -= 2;
+         argv += 2;
+       }
+      else
+       break;
+    }
+
+  if (mainmode == MODE_SEARCH)
+    {
+      Queue sel, q;
+      Dataiterator di;
+      if (argc != 2)
+       usage(1);
+      pool_createwhatprovides(pool);
+      queue_init(&sel);
+      dataiterator_init(&di, pool, 0, 0, 0, argv[1], SEARCH_SUBSTRING|SEARCH_NOCASE);
+      dataiterator_set_keyname(&di, SOLVABLE_NAME);
+      dataiterator_set_search(&di, 0, 0);
+      while (dataiterator_step(&di))
+       queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
+      dataiterator_set_keyname(&di, SOLVABLE_SUMMARY);
+      dataiterator_set_search(&di, 0, 0);
+      while (dataiterator_step(&di))
+       queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
+      dataiterator_set_keyname(&di, SOLVABLE_DESCRIPTION);
+      dataiterator_set_search(&di, 0, 0);
+      while (dataiterator_step(&di))
+       queue_push2(&sel, SOLVER_SOLVABLE, di.solvid);
+      dataiterator_free(&di);
+      if (repofilter.count)
+       selection_filter(pool, &sel, &repofilter);
+      if (archfilter.count)
+       selection_filter(pool, &sel, &archfilter);
+      if (kindfilter.count)
+       selection_filter(pool, &sel, &kindfilter);
+       
+      queue_init(&q);
+      selection_solvables(pool, &sel, &q);
+      queue_free(&sel);
+      for (i = 0; i < q.count; i++)
+       {
+         Solvable *s = pool_id2solvable(pool, q.elements[i]);
+         printf("  - %s [%s]: %s\n", pool_solvable2str(pool, s), s->repo->name, solvable_lookup_str(s, SOLVABLE_SUMMARY));
+       }
+      queue_free(&q);
+      exit(0);
+    }
+
+  /* process command line packages */
+  if (mainmode == MODE_LIST || mainmode == MODE_INFO || mainmode == MODE_INSTALL)
+    {
+      for (i = 1; i < argc; i++)
+       {
+         if (!is_cmdline_package((const char *)argv[i]))
+           continue;
+         if (access(argv[i], R_OK))
+           {
+             perror(argv[i]);
+             exit(1);
+           }
+         if (!commandlinepkgs)
+           commandlinepkgs = solv_calloc(argc, sizeof(Id));
+         if (!commandlinerepo)
+           commandlinerepo = repo_create(pool, "@commandline");
+         p = add_cmdline_package(commandlinerepo, (const char *)argv[i]);
+         if (!p)
+           {
+             fprintf(stderr, "could not add '%s'\n", argv[i]);
+             exit(1);
+           }
+         commandlinepkgs[i] = p;
+       }
+      if (commandlinerepo)
+       {
+         repo_internalize(commandlinerepo);
+#ifdef SUSE
+         repo_add_autopattern(commandlinerepo, 0);
+#endif
+       }
+    }
+
+#if defined(ENABLE_RPMDB)
+  if (pool->disttype == DISTTYPE_RPM)
+    addfileprovides(pool);
+#endif
+  pool_createwhatprovides(pool);
+
+  if (keyname)
+    keyname = solv_dupjoin("solvable:", keyname, 0);
+  queue_init(&job);
+  for (i = 1; i < argc; i++)
+    {
+      Queue job2;
+      int flags, rflags;
+
+      if (commandlinepkgs && commandlinepkgs[i])
+       {
+         queue_push2(&job, SOLVER_SOLVABLE, commandlinepkgs[i]);
+         continue;
+       }
+      queue_init(&job2);
+      flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB;
+      flags |= SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL;
+      if (kindfilter.count)
+       flags |= SELECTION_SKIP_KIND;
+      if (mode == MODE_LIST || archfilter_src)
+       flags |= SELECTION_WITH_SOURCE;
+      if (argv[i][0] == '/')
+       flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
+      if (keyname && keyname_depstr)
+       flags |= SELECTION_MATCH_DEPSTR;
+      if (!keyname || keyname_alldeps)
+        rflags = selection_make(pool, &job2, argv[i], flags);
+      else
+        rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
+      if (repofilter.count)
+       selection_filter(pool, &job2, &repofilter);
+      if (archfilter.count)
+       selection_filter(pool, &job2, &archfilter);
+      if (kindfilter.count)
+       selection_filter(pool, &job2, &kindfilter);
+      if (!job2.count)
+       {
+         flags |= SELECTION_NOCASE;
+         if (!keyname || keyname_alldeps)
+            rflags = selection_make(pool, &job2, argv[i], flags);
+         else
+           rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
+         if (repofilter.count)
+           selection_filter(pool, &job2, &repofilter);
+         if (archfilter.count)
+           selection_filter(pool, &job2, &archfilter);
+         if (kindfilter.count)
+           selection_filter(pool, &job2, &kindfilter);
+         if (job2.count)
+           printf("[ignoring case for '%s']\n", argv[i]);
+       }
+      if (!job2.count)
+       {
+         fprintf(stderr, "nothing matches '%s'\n", argv[i]);
+         exit(1);
+       }
+      if (rflags & SELECTION_FILELIST)
+        printf("[using file list match for '%s']\n", argv[i]);
+      if (rflags & SELECTION_PROVIDES)
+       printf("[using capability match for '%s']\n", argv[i]);
+      if (keyname && keyname_alldeps)
+       {
+         Queue q;
+         queue_init(&q);
+         selection_solvables(pool, &job2, &q);
+         selection_make_matchsolvablelist(pool, &job2, &q, 0, pool_str2id(pool, keyname, 1), 0);
+         queue_free(&q);
+       }
+      queue_insertn(&job, job.count, job2.count, job2.elements);
+      queue_free(&job2);
+    }
+  keyname = solv_free(keyname);
+
+  if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count || archfilter.count || kindfilter.count))
+    {
+      queue_push2(&job, SOLVER_SOLVABLE_ALL, 0);
+      if (repofilter.count)
+       selection_filter(pool, &job, &repofilter);
+      if (archfilter.count)
+       selection_filter(pool, &job, &archfilter);
+      if (kindfilter.count)
+       selection_filter(pool, &job, &kindfilter);
+    }
+  queue_free(&repofilter);
+  queue_free(&archfilter);
+  queue_free(&kindfilter);
+
+  if (!job.count && mainmode != MODE_PATCH)
+    {
+      printf("no package matched\n");
+      exit(1);
+    }
+
+  if (mainmode == MODE_LIST || mainmode == MODE_INFO)
+    {
+      /* list mode, no solver needed */
+      Queue q;
+      queue_init(&q);
+      for (i = 0; i < job.count; i += 2)
+       {
+         int j;
+         queue_empty(&q);
+         pool_job2solvables(pool, &q, job.elements[i], job.elements[i + 1]);
+         for (j = 0; j < q.count; j++)
+           {
+             Solvable *s = pool_id2solvable(pool, q.elements[j]);
+             if (mainmode == MODE_INFO)
+               {
+                 const char *str;
+                 printf("Name:        %s\n", pool_solvable2str(pool, s));
+                 printf("Repo:        %s\n", s->repo->name);
+                 printf("Summary:     %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY));
+                 str = solvable_lookup_str(s, SOLVABLE_URL);
+                 if (str)
+                   printf("Url:         %s\n", str);
+                 str = solvable_lookup_str(s, SOLVABLE_LICENSE);
+                 if (str)
+                   printf("License:     %s\n", str);
+                 printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION));
+                 printf("\n");
+               }
+             else
+               {
+#if 1
+                 const char *sum = solvable_lookup_str_lang(s, SOLVABLE_SUMMARY, "de", 1);
+#else
+                 const char *sum = solvable_lookup_str_poollang(s, SOLVABLE_SUMMARY);
+#endif
+                 printf("  - %s [%s]\n", pool_solvable2str(pool, s), s->repo->name);
+                 if (sum)
+                   printf("    %s\n", sum);
+               }
+           }
+       }
+      queue_free(&q);
+      queue_free(&job);
+      pool_free(pool);
+      free_repoinfos(repoinfos, nrepoinfos);
+      solv_free(commandlinepkgs);
+      exit(0);
+    }
+
+#if defined(SUSE) || defined(FEDORA) || defined(MAGEIA)
+  if (mainmode == MODE_PATCH)
+    add_patchjobs(pool, &job);
+#endif
+
+  // add mode
+  for (i = 0; i < job.count; i += 2)
+    {
+      job.elements[i] |= mode;
+      if (mode == SOLVER_UPDATE && pool_isemptyupdatejob(pool, job.elements[i], job.elements[i + 1]))
+       job.elements[i] ^= SOLVER_UPDATE ^ SOLVER_INSTALL;
+      if (cleandeps)
+        job.elements[i] |= SOLVER_CLEANDEPS;
+      if (forcebest)
+        job.elements[i] |= SOLVER_FORCEBEST;
+    }
+
+#if 0
+  // multiversion test
+  queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_PROVIDES, pool_str2id(pool, "multiversion(kernel)", 1));
+#endif
+#if 0
+  queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
+  queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1));
+#endif
+
+rerunsolver:
+  solv = solver_create(pool);
+  solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1);
+#if 0
+  solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
+#endif
+#if defined(FEDORA) || defined(MAGEIA)
+  solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1);
+#endif
+  if (mainmode == MODE_ERASE)
+    solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1);     /* don't nag */
+  solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+
+  for (;;)
+    {
+      Id problem, solution;
+      int pcnt, scnt;
+
+      pcnt = solver_solve(solv, &job);
+      if (testcase)
+       {
+         printf("Writing solver testcase:\n");
+         if (!testcase_write(solv, testcase, TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, 0, 0))
+           printf("%s\n", pool_errstr(pool));
+         testcase = 0;
+       }
+      if (!pcnt)
+       break;
+      pcnt = solver_problem_count(solv);
+      printf("Found %d problems:\n", pcnt);
+      for (problem = 1; problem <= pcnt; problem++)
+       {
+         int take = 0;
+         printf("Problem %d/%d:\n", problem, pcnt);
+         solver_printprobleminfo(solv, problem);
+         printf("\n");
+         scnt = solver_solution_count(solv, problem);
+         for (solution = 1; solution <= scnt; solution++)
+           {
+             printf("Solution %d:\n", solution);
+             solver_printsolution(solv, problem, solution);
+             printf("\n");
+           }
+         for (;;)
+           {
+             char inbuf[128], *ip;
+             printf("Please choose a solution: ");
+             fflush(stdout);
+             *inbuf = 0;
+             if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
+               {
+                 printf("Abort.\n");
+                 exit(1);
+               }
+             while (*ip == ' ' || *ip == '\t')
+               ip++;
+             if (*ip >= '0' && *ip <= '9')
+               {
+                 take = atoi(ip);
+                 if (take >= 1 && take <= scnt)
+                   break;
+               }
+             if (*ip == 's')
+               {
+                 take = 0;
+                 break;
+               }
+             if (*ip == 'q')
+               {
+                 printf("Abort.\n");
+                 exit(1);
+               }
+           }
+         if (!take)
+           continue;
+         solver_take_solution(solv, problem, take, &job);
+       }
+    }
+
+  trans = solver_create_transaction(solv);
+  if (!trans->steps.count)
+    {
+      printf("Nothing to do.\n");
+      transaction_free(trans);
+      solver_free(solv);
+      queue_free(&job);
+      pool_free(pool);
+      free_repoinfos(repoinfos, nrepoinfos);
+      solv_free(commandlinepkgs);
+      exit(1);
+    }
+
+  /* display transaction to the user and ask for confirmation */
+  printf("\n");
+  printf("Transaction summary:\n\n");
+  transaction_print(trans);
+#if defined(SUSE)
+  showdiskusagechanges(trans);
+#endif
+  printf("install size change: %lld K\n", transaction_calc_installsizechange(trans));
+  printf("\n");
+
+  acnt = solver_alternatives_count(solv);
+  if (acnt)
+    {
+      if (acnt == 1)
+        printf("Have one alternative:\n");
+      else
+        printf("Have %d alternatives:\n", acnt);
+      for (i = 1; i <= acnt; i++)
+       {
+         Id id, from;
+         int atype = solver_get_alternative(solv, i, &id, &from, 0, 0, 0);
+         printf("  - %s\n", solver_alternative2str(solv, atype, id, from));
+       }
+      printf("\n");
+      answer = yesno("OK to continue (y/n/a)? ", 'a');
+    }
+  else
+    answer = yesno("OK to continue (y/n)? ", 0);
+  if (answer == 'a')
+    {
+      Queue choicesq;
+      Queue answerq;
+      Id id, from, chosen;
+      int j;
+
+      queue_init(&choicesq);
+      queue_init(&answerq);
+      for (i = 1; i <= acnt; i++)
+       {
+         int atype = solver_get_alternative(solv, i, &id, &from, &chosen, &choicesq, 0);
+         printf("\n%s\n", solver_alternative2str(solv, atype, id, from));
+         for (j = 0; j < choicesq.count; j++)
+           {
+             Id p = choicesq.elements[j];
+             if (p < 0)
+               p = -p;
+             queue_push(&answerq, p);
+             printf("%6d: %s\n", answerq.count, pool_solvid2str(pool, p));
+           }
+       }
+      queue_free(&choicesq);
+      printf("\n");
+      for (;;)
+       {
+         char inbuf[128], *ip;
+         int neg = 0;
+         printf("OK to continue (y/n), or number to change alternative: ");
+         fflush(stdout);
+         *inbuf = 0;
+         if (!(ip = fgets(inbuf, sizeof(inbuf), stdin)))
+           {
+             printf("Abort.\n");
+             exit(1);
+           }
+         while (*ip == ' ' || *ip == '\t')
+           ip++;
+         if (*ip == '-' && ip[1] >= '0' && ip[1] <= '9')
+           {
+             neg = 1;
+             ip++;
+           }
+         if (*ip >= '0' && *ip <= '9')
+           {
+             int take = atoi(ip);
+             if (take > 0 && take <= answerq.count)
+               {
+                 Id p = answerq.elements[take - 1];
+                 queue_free(&answerq);
+                 queue_push2(&job, (neg ? SOLVER_DISFAVOR : SOLVER_FAVOR) | SOLVER_SOLVABLE_NAME, pool->solvables[p].name);
+                 solver_free(solv);
+                 solv = 0;
+                 goto rerunsolver;
+                 break;
+               }
+           }
+         if (*ip == 'n' || *ip == 'y')
+           {
+             answer = *ip == 'n' ? 0 : *ip;
+             break;
+           }
+       }
+      queue_free(&answerq);
+    }
+  if (!answer)
+    {
+      printf("Abort.\n");
+      transaction_free(trans);
+      solver_free(solv);
+      queue_free(&job);
+      pool_free(pool);
+      free_repoinfos(repoinfos, nrepoinfos);
+      solv_free(commandlinepkgs);
+      exit(1);
+    }
+
+  /* download all new packages */
+  queue_init(&checkq);
+  newpkgs = transaction_installedresult(trans, &checkq);
+  newpkgsfps = 0;
+  if (newpkgs)
+    {
+      int downloadsize = 0;
+      for (i = 0; i < newpkgs; i++)
+       {
+         Solvable *s;
+
+         p = checkq.elements[i];
+         s = pool_id2solvable(pool, p);
+         downloadsize += solvable_lookup_sizek(s, SOLVABLE_DOWNLOADSIZE, 0);
+       }
+      printf("Downloading %d packages, %d K\n", newpkgs, downloadsize);
+      newpkgsfps = solv_calloc(newpkgs, sizeof(*newpkgsfps));
+      for (i = 0; i < newpkgs; i++)
+       {
+         const char *loc;
+         Solvable *s;
+         struct repoinfo *cinfo;
+
+         p = checkq.elements[i];
+         s = pool_id2solvable(pool, p);
+         if (s->repo == commandlinerepo)
+           {
+             loc = solvable_lookup_location(s, 0);
+             if (!loc)
+               continue;
+             if (!(newpkgsfps[i] = fopen(loc, "r")))
+               {
+                 perror(loc);
+                 exit(1);
+               }
+             putchar('.');
+             continue;
+           }
+         cinfo = s->repo->appdata;
+         if (!cinfo || cinfo->type == TYPE_INSTALLED)
+           {
+             printf("%s: no repository information\n", s->repo->name);
+             exit(1);
+           }
+         loc = solvable_lookup_location(s, 0);
+         if (!loc)
+            continue;  /* pseudo package? */
+#if defined(ENABLE_RPMDB)
+         if (pool->installed && pool->installed->nsolvables)
+           {
+             if ((newpkgsfps[i] = trydeltadownload(s, loc)) != 0)
+               {
+                 putchar('d');
+                 fflush(stdout);
+                 continue;             /* delta worked! */
+               }
+           }
+#endif
+         if ((newpkgsfps[i] = downloadpackage(s, loc)) == 0)
+           {
+             printf("\n%s: %s not found in repository\n", s->repo->name, loc);
+             exit(1);
+           }
+         putchar('.');
+         fflush(stdout);
+       }
+      putchar('\n');
+    }
+
+#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA) || defined(MANDRIVA) || defined(MAGEIA))
+  /* check for file conflicts */
+  if (newpkgs)
+    {
+      Queue conflicts;
+      queue_init(&conflicts);
+      if (checkfileconflicts(pool, &checkq, newpkgs, newpkgsfps, &conflicts))
+       {
+         if (yesno("Re-run solver (y/n/q)? ", 0))
+           {
+             for (i = 0; i < newpkgs; i++)
+               if (newpkgsfps[i])
+                 fclose(newpkgsfps[i]);
+             newpkgsfps = solv_free(newpkgsfps);
+             solver_free(solv);
+             solv = 0;
+             pool_add_fileconflicts_deps(pool, &conflicts);
+             queue_free(&conflicts);
+             goto rerunsolver;
+           }
+       }
+      queue_free(&conflicts);
+    }
+#endif
+
+  /* and finally commit the transaction */
+  printf("Committing transaction:\n\n");
+  transaction_order(trans, 0);
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      int j;
+      FILE *fp;
+      Id type;
+
+      p = trans->steps.elements[i];
+      type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY);
+      switch(type)
+       {
+       case SOLVER_TRANSACTION_ERASE:
+         printf("erase %s\n", pool_solvid2str(pool, p));
+         commit_transactionelement(pool, type, p, 0);
+         break;
+       case SOLVER_TRANSACTION_INSTALL:
+       case SOLVER_TRANSACTION_MULTIINSTALL:
+         printf("install %s\n", pool_solvid2str(pool, p));
+         for (j = 0; j < newpkgs; j++)
+           if (checkq.elements[j] == p)
+             break;
+         fp = j < newpkgs ? newpkgsfps[j] : 0;
+         if (!fp)
+           continue;
+         commit_transactionelement(pool, type, p, fp);
+         fclose(fp);
+         newpkgsfps[j] = 0;
+         break;
+       default:
+         break;
+       }
+    }
+
+  for (i = 0; i < newpkgs; i++)
+    if (newpkgsfps[i])
+      fclose(newpkgsfps[i]);
+  solv_free(newpkgsfps);
+  queue_free(&checkq);
+  transaction_free(trans);
+  solver_free(solv);
+  queue_free(&job);
+  pool_free(pool);
+  free_repoinfos(repoinfos, nrepoinfos);
+  solv_free(commandlinepkgs);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/examples/tclsolv b/libsolv-0.7.2/examples/tclsolv
new file mode 100755 (executable)
index 0000000..e24c1d8
--- /dev/null
@@ -0,0 +1,805 @@
+#!/usr/bin/tclsh
+
+package require solv
+package require inifile
+package require fileutil
+
+set reposdir /etc/zypp/repos.d
+
+### some helpers
+
+proc fileno {file} {
+  if [regexp -- {^file(\d+)$} $file match fd] {
+    return $fd
+  }
+  error "file not open"
+}
+
+set ::globalarray_cnt 0
+
+proc globalarray {} {
+  set name "::globalarray_[incr ::globalarray_cnt]"
+  array set $name [list varName $name]
+  return $name
+}
+
+### generic repo handling (cache reading/writing)
+
+proc repo_calc_cookie_file {selfName filename} {
+  upvar $selfName self
+  set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256]
+  $chksum add "1.1"
+  $chksum add_stat $filename
+  return [$chksum raw]
+}
+
+proc repo_calc_cookie_fp {selfName fp} {
+  upvar $selfName self
+  set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256]
+  $chksum add "1.1"
+  $chksum add_fp $fp
+  return [$chksum raw]
+}
+
+proc repo_calc_cookie_ext {selfName f cookie} {
+  upvar $selfName self
+  set chksum [solv::new_Chksum $solv::REPOKEY_TYPE_SHA256]
+  $chksum add "1.1"
+  $chksum add $cookie
+  $chksum add_fstat [$f fileno]
+  return [$chksum raw]
+}
+
+proc repo_cachepath {selfName {ext "-"}} {
+  upvar $selfName self
+  regsub {^\.} $self(name) _ path
+  if {$ext ne "-"} {
+    set path "${path}_$ext.solvx"
+  } else {
+    set path "${path}.solv"
+  }
+  regsub -all / $path _ path
+  return "/var/cache/solv/$path"
+}
+
+proc repo_generic_load {selfName pool} {
+  upvar $selfName self
+  set handle [ $pool add_repo $self(name) ]
+  set self(handle) $handle
+  $handle configure -priority [expr 99 - $self(priority)] -appdata $self(varName)
+  set dorefresh $self(autorefresh)
+  set metadata_expire $self(metadata_expire)
+  catch {
+    if {$metadata_expire == -1 || [clock seconds] - [file mtime [repo_cachepath self]] < $metadata_expire} {
+      set dorefresh 0
+    }
+  }
+  set self(cookie) {}
+  set self(extcookie) {}
+  if { !$dorefresh && [repo_usecachedrepo self] } {
+    puts "repo $self(name): cached"
+    return 1 
+  }
+  return 0 
+}
+
+proc repo_free_handle {selfName} {
+  upvar $selfName self
+  set handle $self(handle)
+  unset self(handle)
+  $handle free 1
+}
+
+proc repo_usecachedrepo {selfName {ext "-"} {mark 0}} {
+  upvar $selfName self
+  set repopath [repo_cachepath self $ext]
+  set code [catch {
+    set f [open $repopath "rb"]
+    seek $f -32 end
+    set fcookie [read $f 32]
+    set cookie [expr {$ext eq "-" ? $self(cookie) : $self(extcookie)}]
+    if {$cookie ne {} && $cookie ne $fcookie} {
+      close $f
+      return 0
+    }
+    set fextcookie {}
+    if {$ext eq "-" && $self(type) ne "system"} {
+      seek $f -64 end
+      set fextcookie [read $f 32]
+    }
+    seek $f 0 start
+    set ff [solv::xfopen_fd {} [fileno $f]]
+    close $f
+    set flags 0
+    if {$ext ne "-"} {
+      set flags [expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES]
+      if {$ext ne "DL"} {
+       set flags [expr $flags | $solv::Repo_REPO_LOCALPOOL]
+      }
+    }
+    if {! [$self(handle) add_solv $ff $flags]} {
+      $ff close
+      return 0
+    }
+    $ff close
+    if {$self(type) ne "system" && $ext eq "-"} {
+      set self(cookie) $fcookie
+      set self(extcookie) $fextcookie
+    }
+    if {$mark} {
+      catch {
+        ::fileutil::touch -c -m -t [clock seconds] $repopath
+      }
+    }
+    return 1
+  } res]
+  return [expr {$code == 2 ? $res : 0}]
+}
+
+proc repo_writecachedrepo {selfName {ext "-"} {repodata "NULL"}} {
+  upvar $selfName self
+  if [info exists self(incomplete)] {
+    return
+  }
+  file mkdir "/var/cache/solv"
+  ::fileutil::tempdir "/var/cache/solv"
+  set tempfilename [::fileutil::tempfile ".newsolv-"]
+  ::fileutil::tempdirReset
+  set f [solv::xfopen $tempfilename "w+"]
+  file attributes $tempfilename -permissions 0444
+  if {$repodata eq {NULL}} {
+    $self(handle) write $f
+  } else {
+    $repodata write $f
+  }
+  $f flush
+  if {$self(type) ne "system" && $ext eq "-"} {
+    if {$self(extcookie) eq {}} {
+      set self(extcookie) [repo_calc_cookie_ext self $f $self(cookie)]
+    }
+    $f write $self(extcookie)
+  }
+  $f write [expr {$ext eq "-" ? $self(cookie) : $self(extcookie)}]
+  $f close
+  file rename -force -- $tempfilename [repo_cachepath self $ext]
+}
+
+proc repo_download {selfName file uncompress chksum {markincomplete 0}} {
+  upvar $selfName self
+  regsub {/$} $self(baseurl) {} url
+  set url "$url/$file"
+  set tempfilename [::fileutil::tempfile]
+  set f [open $tempfilename rb+]
+  file delete -- $tempfilename
+  if [catch {
+    exec -ignorestderr -- curl -f -s -L $url ">@$f"
+  }] {
+    seek $f 0 end
+    if {($chksum ne "" && $chksum ne "NULL") || [tell $f] != 0} {
+      puts "$file: download error"
+    }
+    close $f
+    return {NULL}
+  }
+  seek $f 0 start
+  if {$chksum ne "" && $chksum ne "NULL"} {
+    set fchksum [solv::new_Chksum [$chksum cget -type]]
+    if {$fchksum eq "" || $fchksum eq "NULL"} {
+      puts "$file: unknown checksum type"
+      if {$markincomplete} {
+       set self(incomplete) 1
+      }
+      close $f
+      return {NULL}
+    }
+    $fchksum add_fd [fileno $f]
+    if {[$fchksum != $chksum]} {
+      puts "$file: checksum mismatch"
+      if {$markincomplete} {
+       set self(incomplete) 1
+      }
+      close $f
+      return {NULL}
+    }
+  }
+  set ff [solv::xfopen_fd [expr {$uncompress ? $file : ""}] [fileno $f]]
+  close $f
+  return $ff
+}
+
+proc repo_generic_add_ext_keys {selfName ext repodata h} {
+  upvar $selfName self
+  if {$ext eq "DL"} {
+    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOSITORY_DELTAINFO
+    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_FLEXARRAY
+  } elseif {$ext eq "DU"} {
+    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::SOLVABLE_DISKUSAGE
+    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_DIRNUMNUMARRAY
+  } elseif {$ext eq "FL"} {
+    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::SOLVABLE_FILELIST
+    $repodata add_idarray $h $solv::REPOSITORY_KEYS $solv::REPOKEY_TYPE_DIRSTRARRAY
+  }
+}
+
+### system
+
+proc repo_system_load {selfName pool} {
+  upvar $selfName self
+  set handle [ $pool add_repo $self(name) ]
+  set self(handle) $handle
+  $handle configure -appdata $self(varName)
+  $pool configure -installed $handle
+  puts -nonewline "rpm database: "
+  set self(cookie) [repo_calc_cookie_file self "/var/lib/rpm/Packages"]
+  if [repo_usecachedrepo self] {
+    puts "cached"
+    return 1
+  }
+  puts "reading"
+  set f [solv::xfopen [repo_cachepath self]]
+  $handle add_rpmdb_reffp $f $solv::Repo_REPO_REUSE_REPODATA
+  repo_writecachedrepo self
+}
+
+### repomd
+
+proc repo_repomd_add_ext {selfName repodata what ext} {
+  upvar $selfName self
+  set where [repo_repomd_find self $what]
+  if {$where eq {}} {
+    return
+  }
+  set h [$repodata new_handle]
+  $repodata set_poolstr $h $solv::REPOSITORY_REPOMD_TYPE $what
+  $repodata set_str $h $solv::REPOSITORY_REPOMD_LOCATION [lindex $where 0]
+  $repodata set_checksum $h $solv::REPOSITORY_REPOMD_CHECKSUM [lindex $where 1]
+  repo_generic_add_ext_keys self $ext $repodata $h
+  $repodata add_flexarray $solv::SOLVID_META $solv::REPOSITORY_EXTERNAL $h
+}
+
+proc repo_repomd_add_exts {selfName} {
+  upvar $selfName self
+  set repodata [$self(handle) add_repodata 0]
+  $repodata extend_to_repo
+  repo_repomd_add_ext self $repodata "filelists" "FL"
+  $repodata internalize
+}
+
+proc repo_repomd_find {selfName what} {
+  upvar $selfName self
+  set di [$self(handle) Dataiterator_meta $solv::REPOSITORY_REPOMD_TYPE $what $solv::Dataiterator_SEARCH_STRING]
+  $di prepend_keyname $solv::REPOSITORY_REPOMD
+  solv::iter d $di {
+    set dp [$d parentpos]
+    set filename [$dp lookup_str $solv::REPOSITORY_REPOMD_LOCATION]
+    set checksum [$dp lookup_checksum $solv::REPOSITORY_REPOMD_CHECKSUM]
+    if {$filename ne "" && $checksum eq "NULL"} {
+      puts "no $filename file checksum"
+    } elseif {$filename ne ""} {
+      return [list $filename $checksum]
+    }
+  }
+  return {}
+}
+
+proc repo_repomd_load {selfName pool} {
+  upvar $selfName self
+  if [repo_generic_load self $pool] {
+    return 1
+  }
+  puts -nonewline "rpmmd repo '$self(name)': "
+  set f [repo_download self {repodata/repomd.xml} 0 {}]
+  if {$f eq {NULL}} {
+    puts "no repomd.xml file, skipped"
+    repo_free_handle self
+    return 0
+  }
+  set self(cookie) [repo_calc_cookie_fp self $f]
+  if [repo_usecachedrepo self "-" 1] {
+    puts "cached"
+    return 1
+  }
+  set handle $self(handle)
+  $handle add_repomdxml $f
+  puts "fetching"
+  set primary [repo_repomd_find self primary]
+  if {$primary ne {}} {
+    set f [repo_download self [lindex $primary 0] 1 [lindex $primary 1] 1]
+    if {$f ne {NULL}} {
+      $handle add_rpmmd $f {}
+      $f close
+    }
+    if [info exists self(incomplete)] {
+      return 0
+    }
+  }
+  set updateinfo [repo_repomd_find self primary]
+  if {$updateinfo ne {}} {
+    set f [repo_download self [lindex $updateinfo  0] 1 [lindex $updateinfo 1] 1]
+    if {$f ne {NULL}} {
+      $handle add_updateinfoxml $f
+      $f close
+    }
+  }
+  repo_repomd_add_exts self
+  repo_writecachedrepo self
+  $self(handle) create_stubs
+  return 1
+}
+
+proc repo_repomd_packagespath {selfName} {
+  return ""
+}
+
+proc repo_repomd_load_ext {selfName repodata} {
+  upvar $selfName self
+  switch -- [$repodata lookup_str $solv::SOLVID_META $solv::REPOSITORY_REPOMD_TYPE] {
+    "deltainfo" {
+      set ext DL
+    }
+    "filelists" {
+      set ext FL
+    }
+    default {
+      return 0
+    }
+  }
+  puts -nonewline "\[$self(name):$ext: "
+  flush stdout
+  if [repo_usecachedrepo self $ext] {
+    puts "cached]"
+    return 1
+  }
+  puts "fetching]"
+  set handle $self(handle)
+  set filename [$repodata lookup_str $solv::SOLVID_META $solv::REPOSITORY_REPOMD_LOCATION]
+  set filechecksum [$repodata lookup_checksum $solv::SOLVID_META $solv::REPOSITORY_REPOMD_CHECKSUM]
+  set f [repo_download self $filename 1 $filechecksum]
+  if {$f eq {NULL}} {
+    return 0
+  }
+  if {$ext eq "FL"} {
+    $handle add_rpmmd $f "FL" [ expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES | $solv::Repo_REPO_LOCALPOOL]
+  }
+  $f close
+  repo_writecachedrepo self $ext $repodata
+  return 1
+}
+
+### susetags
+
+proc repo_susetags_add_ext {selfName repodata what ext} {
+  upvar $selfName self
+  set where [repo_susetags_find self $what]
+  if {$where eq {}} {
+    return
+  }
+  set h [$repodata new_handle]
+  $repodata set_str $h $solv::SUSETAGS_FILE_NAME [lindex $where 0]
+  $repodata set_checksum $h $solv::SUSETAGS_FILE_CHECKSUM [lindex $where 1]
+  repo_generic_add_ext_keys self $ext $repodata $h
+  $repodata add_flexarray $solv::SOLVID_META $solv::REPOSITORY_EXTERNAL $h
+}
+
+proc repo_susetags_add_exts {selfName} {
+  upvar $selfName self
+  set repodata [$self(handle) add_repodata 0]
+  $repodata extend_to_repo
+  repo_susetags_add_ext self $repodata "packages.FL" "FL"
+  repo_susetags_add_ext self $repodata "packages.FL.gz" "FL"
+  $repodata internalize
+}
+
+proc repo_susetags_find {selfName what} {
+  upvar $selfName self
+  set di [$self(handle) Dataiterator_meta $solv::SUSETAGS_FILE_NAME $what $solv::Dataiterator_SEARCH_STRING]
+  $di prepend_keyname $solv::SUSETAGS_FILE
+  solv::iter d $di {
+    set dp [$d parentpos]
+    set checksum [$dp lookup_checksum $solv::SUSETAGS_FILE_CHECKSUM]
+    return [list $what $checksum]
+  }
+  return {}
+}
+
+proc repo_susetags_load {selfName pool} {
+  upvar $selfName self
+  if [repo_generic_load self $pool] {
+    return 1
+  }
+  puts -nonewline "susetags repo '$self(name)': "
+  set f [repo_download self {content} 0 {}]
+  if {$f eq {NULL}} {
+    puts "no content file, skipped"
+    repo_free_handle self
+    return 0
+  }
+  set self(cookie) [repo_calc_cookie_fp self $f]
+  if [repo_usecachedrepo self "-" 1] {
+    puts "cached"
+    return 1
+  }
+  set handle $self(handle)
+  $handle add_content $f
+  puts "fetching"
+  set defvendorid [[$handle cget -meta] lookup_id $solv::SUSETAGS_DEFAULTVENDOR]
+  set descrdir [[$handle cget -meta] lookup_str $solv::SUSETAGS_DESCRDIR]
+  if {$descrdir eq {NULL}} {
+    set descrdir "suse/setup/descr"
+  }
+  set packages [repo_susetags_find self "packages.gz"]
+  if {$packages eq {}} {
+    set packages [repo_susetags_find self "packages"]
+  }
+  if {$packages ne {}} {
+    set f [repo_download self "$descrdir/[lindex $packages 0]" 1 [lindex $packages 1] 1]
+    if {$f ne {NULL}} {
+      $handle add_susetags $f $defvendorid {} [expr $solv::Repo_REPO_NO_INTERNALIZE | $solv::Repo_SUSETAGS_RECORD_SHARES]
+      $f close
+      set packages [repo_susetags_find self "packages.en.gz"]
+      if {$packages eq {}} {
+       set packages [repo_susetags_find self "packages.en"]
+      }
+      if {$packages ne {}} {
+       set f [repo_download self "$descrdir/[lindex $packages 0]" 1 [lindex $packages 1] 1]
+       if {$f ne {NULL}} {
+          $handle add_susetags $f $defvendorid {} [expr $solv::Repo_REPO_NO_INTERNALIZE | $solv::Repo_REPO_REUSE_REPODATA | $solv::Repo_REPO_EXTEND_SOLVABLES ]
+         $f close
+       }
+      }
+      $handle internalize
+    }
+  }
+  repo_susetags_add_exts self
+  repo_writecachedrepo self
+  $self(handle) create_stubs
+  return 1
+}
+
+proc repo_susetags_packagespath {selfName} {
+  upvar $selfName self
+  set datadir [[$self(handle) cget -meta] lookup_str $solv::SUSETAGS_DATADIR]
+  return [expr {$datadir ne {} ? "$datadir/" : "suse/"}]
+}
+
+proc repo_susetags_load_ext {selfName repodata} {
+  upvar $selfName self
+  set filename [$repodata lookup_str $solv::SOLVID_META $solv::SUSETAGS_FILE_NAME]
+  set ext [string range $filename 9 10]
+  puts -nonewline "\[$self(name):$ext: "
+  flush stdout
+  if [repo_usecachedrepo self $ext] {
+    puts "cached]"
+    return 1
+  }
+  puts "fetching]"
+  set handle $self(handle)
+  set defvendorid [[$handle cget -meta] lookup_id $solv::SUSETAGS_DEFAULTVENDOR]
+  set descrdir [[$handle cget -meta] lookup_str $solv::SUSETAGS_DESCRDIR]
+  if {$descrdir eq {NULL}} {
+    set descrdir "suse/setup/descr"
+  }
+  set filechecksum [$repodata lookup_checksum $solv::SOLVID_META $solv::SUSETAGS_FILE_CHECKSUM]
+  set f [repo_download self "$descrdir/$filename" 1 $filechecksum]
+  if {$f eq {NULL}} {
+    return 0
+  }
+  set flags [expr $solv::Repo_REPO_USE_LOADING | $solv::Repo_REPO_EXTEND_SOLVABLES]
+  if {$ext ne "DL"} {
+    set flags [expr $flags | $solv::Repo_REPO_LOCALPOOL]
+  }
+  $handle add_susetags $f $defvendorid $ext $flags
+  $f close
+  repo_writecachedrepo self $ext $repodata
+  return 1
+}
+
+### unknown
+
+proc repo_unknown_load {selfName pool} {
+  upvar $selfName self
+  puts "unsupported repo '$self(name)': skipped"
+  return 0
+}
+
+### poor man's OO
+
+proc repo_load {selfName pool} {
+  upvar $selfName self
+  "repo_$self(type)_load" self $pool
+}
+
+proc repo_packagespath {selfName} {
+  upvar $selfName self
+  "repo_$self(type)_packagespath" self
+}
+
+proc repo_load_ext {selfName repodata} {
+  upvar $selfName self
+  "repo_$self(type)_load_ext" self $repodata
+}
+
+###
+
+proc load_stub {repodata} {
+  set code [catch {
+    upvar #0 [[$repodata cget -repo] cget -appdata] repo
+    if [info exists repo(handle)] {
+      return [repo_load_ext repo $repodata]
+    }
+    return 0
+  } res]
+  if {$code == 2} {
+    return $res
+  }
+  puts stderr $res
+  return 0
+}
+
+###
+
+set repoNames {}
+foreach reponame [lsort [glob -nocomplain -directory $reposdir *.repo]] {
+  set ini [::ini::open $reponame r]
+  foreach alias [::ini::sections $ini] {
+    upvar #0 [globalarray] repo
+    array set repo {enabled 0 priority 99 autorefresh 1 type rpm-md metadata_expire 900}
+    array set repo [::ini::get $ini $alias]
+    set repo(name) $alias
+    switch -exact -- $repo(type) {
+      rpm-md  { set repo(type) repomd }
+      yast2   { set repo(type) susetags }
+      default { set repo(type) unknown }
+    }
+    lappend repoNames $repo(varName)
+  }
+  ::ini::close $ini
+}
+
+set pool [solv::new_Pool]
+$pool setarch
+$pool set_loadcallback load_stub
+
+upvar #0 [globalarray] sysrepo
+array set sysrepo [list name {@System} type system]
+repo_load sysrepo $pool
+
+foreach repoName $repoNames {
+  upvar 0 $repoName repo
+  if {$repo(enabled)} {
+    repo_load repo $pool
+  }
+}
+
+
+set cmd [lindex $::argv 0]
+set ::argv [lreplace $::argv 0 0]
+
+array set cmdabbrev [ list \
+  in install \
+  rm erase \
+  ls list \
+  ve verify \
+  se search \
+]
+if [info exists cmdabbrev($cmd)] {
+  set cmd $cmdabbrev($cmd)
+}
+
+if {$cmd eq "search"} {
+  set arg [lindex $::argv 0]
+  $pool createwhatprovides
+  set sel [$pool Selection]
+  set di [$pool Dataiterator $solv::SOLVABLE_NAME $arg [ expr $solv::Dataiterator_SEARCH_SUBSTRING | $solv::Dataiterator_SEARCH_NOCASE ]]
+  solv::iter d $di {
+    $sel add_raw $solv::Job_SOLVER_SOLVABLE [$d cget -solvid]
+  }
+  foreach s [$sel solvables] {
+    puts [format { - %s [%s]: %s} [$s str] [[$s cget -repo] cget -name] [$s lookup_str $solv::SOLVABLE_SUMMARY]]
+  }
+  exit
+}
+
+$pool addfileprovides
+$pool createwhatprovides
+
+array set cmdactionmap [ list \
+  install $solv::Job_SOLVER_INSTALL \
+  erase $solv::Job_SOLVER_ERASE \
+  up $solv::Job_SOLVER_UPDATE \
+  dup $solv::Job_SOLVER_DISTUPGRADE \
+  verify $solv::Job_SOLVER_VERIFY \
+  list 0 \
+  info 0 \
+]
+
+set jobs {}
+foreach arg $::argv {
+  set flags [expr $solv::Selection_SELECTION_NAME | $solv::Selection_SELECTION_PROVIDES | $solv::Selection_SELECTION_GLOB | \
+                  $solv::Selection_SELECTION_CANON | $solv::Selection_SELECTION_DOTARCH | $solv::Selection_SELECTION_REL ]
+  switch -glob -- $arg {
+    "/*" {
+      set flags [expr $flags | $solv::Selection_SELECTION_FILELIST ]
+      if {$cmd eq "erase"} {
+        set flags [expr $flags | $solv::Selection_SELECTION_INSTALLED_ONLY ]
+      }
+    }
+  }
+  set sel [$pool select $arg $flags]
+  if [$sel isempty] {
+    set sel [$pool select $arg [expr $flags | $solv::Selection_SELECTION_NOCASE]]
+    if {![$sel isempty]} {
+      puts "\[ignoring case for '$arg']"
+    }
+  }
+  if [$sel isempty] {
+    puts "nothing matches '$arg'"
+    exit 1
+  }
+  if {[$sel cget -flags] & $solv::Selection_SELECTION_FILELIST} {
+    puts "\[using file list match for '$arg']"
+  }
+  if {[$sel cget -flags] & $solv::Selection_SELECTION_PROVIDES} {
+    puts "\[using capability match for '$arg']"
+  }
+  lappend jobs {*}[$sel jobs $cmdactionmap($cmd)]
+}
+
+if {$jobs eq {} && ($cmd eq "up" || $cmd eq "dup" || $cmd eq "verify") } {
+  set sel [$pool Selection_all]
+  lappend jobs {*}[$sel jobs $cmdactionmap($cmd)]
+}
+
+if {$jobs eq {}} {
+  puts "no package matched."
+  exit 1
+}
+
+if {$cmd eq "list" || $cmd eq "info"} {
+  foreach job $jobs {
+    foreach s [$job solvables] {
+      if {$cmd eq "info"} {
+        puts [format {Name:        %s} [$s str]]
+        puts [format {Repo:        %s} [[$s cget -repo] cget -name]]
+        puts [format {Summary:     %s} [$s lookup_str $solv::SOLVABLE_SUMMARY]]
+        set str [$s lookup_str $solv::SOLVABLE_URL]
+       if {$str ne {}} {
+          puts [format {Url:         %s} $str]
+       }
+        set str [$s lookup_str $solv::SOLVABLE_LICENSE]
+       if {$str ne {}} {
+          puts [format {License      %s} $str]
+       }
+        puts [format {Description: %s} [$s lookup_str $solv::SOLVABLE_DESCRIPTION]]
+       puts {}
+      } else {
+        puts [format {  - %s [%s]} [$s str] [[$s cget -repo] cget -name]]
+        puts [format {    %s} [$s lookup_str $solv::SOLVABLE_SUMMARY]]
+      }
+    }
+  }
+  exit
+}
+
+#$pool set_debuglevel 1
+set solver [$pool Solver]
+$solver set_flag $solv::Solver_SOLVER_FLAG_SPLITPROVIDES 1
+if {$cmd eq "erase"} {
+  $solver set_flag $solv::Solver_SOLVER_FLAG_ALLOW_UNINSTALL 1
+}
+
+set problems [$solver solve $jobs]
+if {$problems ne {}} {
+  set pcnt 1
+  foreach problem $problems {
+    puts [format {Problem %d/%d:} $pcnt [llength $problems]]
+    puts [$problem str]
+    incr pcnt
+  }
+  exit 1
+}
+
+set trans [$solver transaction]
+
+if [$trans isempty] {
+  puts "Nothing to do."
+  exit
+}
+
+puts {}
+puts "Transaction summary:"
+puts {}
+foreach cl [$trans classify [expr $solv::Transaction_SOLVER_TRANSACTION_SHOW_OBSOLETES | $solv::Transaction_SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE]] {
+  switch -- [$cl cget -type] \
+    $solv::Transaction_SOLVER_TRANSACTION_ERASE {
+      puts [format {%d erased packages:} [$cl cget -count]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_INSTALL {
+      puts [format {%d installed packages:} [$cl cget -count]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_REINSTALLED {
+      puts [format {%d reinstalled packages:} [$cl cget -count]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_DOWNGRADED {
+      puts [format {%d downgraded packages:} [$cl cget -count]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_CHANGED {
+      puts [format {%d changed packages:} [$cl cget -count]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_UPGRADED {
+      puts [format {%d upgraded packages:} [$cl cget -count]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_VENDORCHANGE {
+      puts [format {%d vendor changes from '%s' to '%s':} [$cl cget -count] [$cl cget -fromstr] [$cl cget -tostr]]
+    } \
+    $solv::Transaction_SOLVER_TRANSACTION_ARCHCHANGE {
+      puts [format {%d archchanges from '%s' to '%s':} [$cl cget -count] [$cl cget -fromstr] [$cl cget -tostr]]
+    } \
+    default continue
+  foreach p [$cl solvables] {
+    set cltype [$cl cget -type]
+    if {$cltype == $solv::Transaction_SOLVER_TRANSACTION_UPGRADED || $cltype ==$solv::Transaction_SOLVER_TRANSACTION_DOWNGRADED} {
+      set op [$trans othersolvable $p]
+      puts [format {  - %s -> %s} [$p str] [$op str]]
+    } else {
+      puts [format {  - %s} [$p str]]
+    }
+  }
+  puts {}
+}
+puts [format {install size change: %d K} [$trans calc_installsizechange]]
+puts {}
+
+while 1 {
+  puts -nonewline "OK to continue (y/n)? "
+  flush stdout
+  set yn [gets stdin]
+  if {$yn eq "y"} {
+    break
+  }
+  if {$yn eq "n" || $yn eq "q"} {
+    exit
+  }
+}
+
+set newpkgs [$trans newsolvables]
+array set newpkgs_f {}
+if {$newpkgs ne {}} {
+  set downloadsize 0
+  foreach p $newpkgs {
+    set downloadsize [expr $downloadsize + [$p lookup_num $solv::SOLVABLE_DOWNLOADSIZE]]
+  }
+  puts [format {Downloading %d packages, %d K} [llength $newpkgs] [expr $downloadsize / 1024]]
+  foreach p $newpkgs {
+    upvar #0 [[$p cget -repo] cget -appdata] repo
+    set location [$p lookup_location]
+    if {$location eq {}} {
+      continue
+    }
+    set location "[repo_packagespath repo][lindex $location 0]"
+    set checksum [$p lookup_checksum $solv::SOLVABLE_CHECKSUM]
+    set f [repo_download repo $location 0 $checksum]
+    set newpkgs_f([$p cget -id]) $f
+    puts -nonewline "."
+    flush stdout
+  }
+  puts {}
+}
+
+puts "Committing transaction:"
+$trans order
+foreach p [$trans steps] {
+  set steptype [$trans steptype $p $solv::Transaction_SOLVER_TRANSACTION_RPM_ONLY]
+  if {$steptype == $solv::Transaction_SOLVER_TRANSACTION_ERASE} {
+    puts "erase [$p str]"
+    regsub {^[0-9]+:} [$p cget -evr] {} nvr
+    set nvr "[$p cget -name]-$nvr.[$p cget -arch]"
+    exec -ignorestderr -- rpm -e --nodeps --nodigest --nosignature $nvr
+  } elseif {$steptype == $solv::Transaction_SOLVER_TRANSACTION_INSTALL || $steptype == $solv::Transaction_SOLVER_TRANSACTION_MULTIINSTALL} {
+    puts "install [$p str]"
+    set f $newpkgs_f([$p cget -id])
+    set mode [expr {$steptype == $solv::Transaction_SOLVER_TRANSACTION_INSTALL ? "-U" : "-i"}]
+    $f cloexec 0
+    exec -ignorestderr -- rpm $mode --force --nodeps --nodigest --nosignature "/dev/fd/[$f fileno]"
+  }
+}
diff --git a/libsolv-0.7.2/ext/CMakeLists.txt b/libsolv-0.7.2/ext/CMakeLists.txt
new file mode 100644 (file)
index 0000000..edc2b9f
--- /dev/null
@@ -0,0 +1,158 @@
+SET (libsolvext_SRCS
+    solv_xfopen.c testcase.c)
+
+SET (libsolvext_HEADERS
+    tools_util.h solv_xfopen.h testcase.h)
+
+IF (ENABLE_RPMDB OR ENABLE_RPMPKG)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+        pool_fileconflicts.c repo_rpmdb.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+        pool_fileconflicts.h repo_rpmdb.h)
+ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG)
+
+IF (ENABLE_PUBKEY)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_pubkey.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_pubkey.h)
+ENDIF (ENABLE_PUBKEY)
+
+IF (ENABLE_PGPVRFY)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       solv_pgpvrfy.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       solv_pgpvrfy.h)
+ENDIF (ENABLE_PGPVRFY)
+
+IF (ENABLE_RPMMD)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_repomdxml.c repo_rpmmd.c
+       repo_deltainfoxml.c repo_updateinfoxml.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_repomdxml.h repo_rpmmd.h
+       repo_deltainfoxml.h repo_updateinfoxml.h)
+ENDIF (ENABLE_RPMMD)
+
+IF (ENABLE_SUSEREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_content.c repo_products.c repo_releasefile_products.c
+       repo_susetags.c repo_zyppdb.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_content.h repo_products.h repo_releasefile_products.h
+       repo_susetags.h repo_zyppdb.h)
+ENDIF (ENABLE_SUSEREPO)
+
+# old cmake does not support parenthetical expressions...
+IF (ENABLE_COMPLEX_DEPS)
+IF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB OR ENABLE_RPMPKG)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       pool_parserpmrichdep.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       pool_parserpmrichdep.h)
+ENDIF (ENABLE_SUSEREPO OR ENABLE_RPMMD OR ENABLE_RPMDB OR ENABLE_RPMPKG)
+ENDIF (ENABLE_COMPLEX_DEPS)
+
+IF (SUSE)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_autopattern.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_autopattern.h)
+ENDIF (SUSE)
+
+IF (ENABLE_COMPS)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_comps.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_comps.h)
+ENDIF (ENABLE_COMPS)
+
+IF (ENABLE_DEBIAN)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_deb.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_deb.h)
+ENDIF (ENABLE_DEBIAN)
+
+IF (ENABLE_HELIXREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_helix.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_helix.h)
+ENDIF (ENABLE_HELIXREPO)
+
+IF (ENABLE_MDKREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_mdk.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_mdk.h)
+ENDIF (ENABLE_MDKREPO)
+
+IF (ENABLE_ARCHREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_arch.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_arch.h)
+ENDIF (ENABLE_ARCHREPO)
+
+IF (ENABLE_CUDFREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_cudf.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_cudf.h)
+ENDIF (ENABLE_CUDFREPO)
+
+IF (ENABLE_HAIKU)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_haiku.cpp)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_haiku.h)
+ENDIF (ENABLE_HAIKU)
+
+IF (ENABLE_APPDATA)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_appdata.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_appdata.h)
+ENDIF (ENABLE_APPDATA)
+
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repodata_diskusage.c)
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       solv_xmlparser.c)
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
+
+IF (ENABLE_ZCHUNK_COMPRESSION)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       solv_zchunk.c)
+ENDIF (ENABLE_ZCHUNK_COMPRESSION)
+
+SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+IF (HAVE_LINKER_VERSION_SCRIPT)
+SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
+ENDIF (HAVE_LINKER_VERSION_SCRIPT)
+
+IF (DISABLE_SHARED)
+ADD_LIBRARY (libsolvext STATIC ${libsolvext_SRCS})
+ELSE (DISABLE_SHARED)
+ADD_LIBRARY (libsolvext SHARED ${libsolvext_SRCS})
+TARGET_LINK_LIBRARIES(libsolvext libsolv ${SYSTEM_LIBRARIES})
+ENDIF (DISABLE_SHARED)
+
+SET_TARGET_PROPERTIES(libsolvext PROPERTIES OUTPUT_NAME "solvext")
+SET_TARGET_PROPERTIES(libsolvext PROPERTIES SOVERSION ${LIBSOLVEXT_SOVERSION})
+SET_TARGET_PROPERTIES(libsolvext PROPERTIES INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
+
+INSTALL (FILES ${libsolvext_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/solv")
+INSTALL (TARGETS libsolvext LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION bin)
+
+IF (ENABLE_STATIC AND NOT DISABLE_SHARED)
+ADD_LIBRARY (libsolvext_static STATIC ${libsolvext_SRCS})
+SET_TARGET_PROPERTIES(libsolvext_static PROPERTIES OUTPUT_NAME "solvext")
+SET_TARGET_PROPERTIES(libsolvext_static PROPERTIES SOVERSION ${LIBSOLVEXT_SOVERSION})
+INSTALL (TARGETS libsolvext_static LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
+ENDIF (ENABLE_STATIC AND NOT DISABLE_SHARED)
diff --git a/libsolv-0.7.2/ext/libsolvext.ver b/libsolv-0.7.2/ext/libsolvext.ver
new file mode 100644 (file)
index 0000000..4896e85
--- /dev/null
@@ -0,0 +1,77 @@
+SOLV_1.0 {
+       global:
+               pool_deb_get_autoinstalled;
+               pool_findfileconflicts;
+               pool_parserpmrichdep;
+               repo_add_appdata;
+               repo_add_appdata_dir;
+               repo_add_arch_local;
+               repo_add_arch_pkg;
+               repo_add_arch_repo;
+               repo_add_autopattern;
+               repo_add_code11_products;
+               repo_add_content;
+               repo_add_comps;
+               repo_add_cudf;
+               repo_add_deb;
+               repo_add_debdb;
+               repo_add_debpackages;
+               repo_add_deltainfoxml;
+               repo_add_haiku_installed_packages;
+               repo_add_haiku_package;
+               repo_add_haiku_package_info;
+               repo_add_haiku_packages;
+               repo_add_helix;
+               repo_add_keydir;
+               repo_add_keyring;
+               repo_add_mdk;
+               repo_add_mdk_info;
+               repo_add_products;
+               repo_add_pubkey;
+               repo_add_releasefile_products;
+               repo_add_repomdxml;
+               repo_add_rpm;
+               repo_add_rpm_handle;
+               repo_add_rpmdb;
+               repo_add_rpmdb_pubkeys;
+               repo_add_rpmdb_reffp;
+               repo_add_rpmmd;
+               repo_add_susetags;
+               repo_add_updateinfoxml;
+               repo_add_zyppdb_products;
+               repo_find_all_pubkeys;
+               repo_find_pubkey;
+               repo_verify_sigdata;
+               rpm_byfp;
+               rpm_byrpmdbid;
+               rpm_byrpmh;
+               rpm_installedrpmdbids;
+               rpm_iterate_filelist;
+               rpm_query;
+               rpm_query_num;
+               rpm_state_create;
+               rpm_state_free;
+               solv_verify_sig;
+               solv_xfopen;
+               solv_xfopen_buf;
+               solv_xfopen_fd;
+               solv_xfopen_iscompressed;
+               solvsig_create;
+               solvsig_free;
+               solvsig_verify;
+               testcase_add_testtags;
+               testcase_dep2str;
+               testcase_job2str;
+               testcase_solvid2str;
+               testcase_str2dep;
+               testcase_str2job;
+               testcase_str2repo;
+               testcase_str2solvid;
+               testcase_read;
+               testcase_resultdiff;
+               testcase_solverresult;
+               testcase_write;
+               testcase_write_testtags;
+       local:
+               *;
+};
diff --git a/libsolv-0.7.2/ext/pool_fileconflicts.c b/libsolv-0.7.2/ext/pool_fileconflicts.c
new file mode 100644 (file)
index 0000000..eaeb52b
--- /dev/null
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2009-2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "hash.h"
+#include "repo_rpmdb.h"
+#include "pool_fileconflicts.h"
+
+struct cbdata {
+  Pool *pool;
+  int create;
+  int aliases;
+
+  Queue lookat;                /* conflict candidates */
+  Queue lookat_dir;    /* not yet conflicting directories */
+
+  Hashtable cflmap;
+  Hashval cflmapn;
+  unsigned int cflmapused;
+
+  Hashtable dirmap;
+  Hashval dirmapn;
+  unsigned int dirmapused;
+  int dirconflicts;
+
+  Map idxmap;
+
+  unsigned int lastdiridx;     /* last diridx we have seen */
+  unsigned int lastdirhash;    /* strhash of last dir we have seen */
+  int lastdiridxbad;
+
+  Id idx;      /* index of package we're looking at */
+
+  unsigned char *filesspace;
+  unsigned int filesspacen;
+
+  Hashtable normap;
+  Hashval normapn;
+  unsigned int normapused;
+  Queue norq;
+
+  Hashtable statmap;
+  Hashval statmapn;
+  unsigned int statmapused;
+
+  int usestat;
+  int statsmade;
+
+  const char *rootdir;
+  int rootdirl;
+
+  char *canonspace;
+  int canonspacen;
+
+  Hashtable fetchmap;
+  Hashval fetchmapn;
+  Map fetchdirmap;
+  int fetchdirmapn;
+  Queue newlookat;
+};
+
+#define FILESSPACE_BLOCK 255
+
+static Hashtable
+growhash(Hashtable map, Hashval *mapnp)
+{
+  Hashval mapn = *mapnp;
+  Hashval newn = (mapn + 1) * 2 - 1;
+  Hashval i, h, hh;
+  Hashtable m;
+  Id hx, qx;
+
+  m = solv_calloc(newn + 1, 2 * sizeof(Id));
+  for (i = 0; i <= mapn; i++)
+    {
+      hx = map[2 * i];
+      if (!hx)
+       continue;
+      h = hx & newn;
+      hh = HASHCHAIN_START;
+      for (;;)
+       {
+         qx = m[2 * h];
+         if (!qx)
+           break;
+         h = HASHCHAIN_NEXT(h, hh, newn);
+       }
+      m[2 * h] = hx;
+      m[2 * h + 1] = map[2 * i + 1];
+    }
+  solv_free(map);
+  *mapnp = newn;
+  return m;
+}
+
+/* first pass for non-alias mode:
+ * create hash (dhx, idx) of directories that may have conflicts.
+ * also create map "ixdmap" of packages involved
+ */
+static void
+finddirs_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
+{
+  struct cbdata *cbdata = cbdatav;
+  Hashval h, hh;
+  Id dhx, qx;
+  Id oidx, idx = cbdata->idx;
+
+  dhx = strhash(fn);
+  if (!dhx)
+    dhx = strlen(fn) + 1;      /* make sure dhx is not zero */
+  h = dhx & cbdata->dirmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->dirmap[2 * h];
+      if (!qx)
+       break;
+      if (qx == dhx)
+       break;
+      h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn);
+    }
+  if (!qx)
+    {
+      /* a miss */
+      if (!cbdata->create)
+       return;
+      cbdata->dirmap[2 * h] = dhx;
+      cbdata->dirmap[2 * h + 1] = idx;
+      if (++cbdata->dirmapused * 2 > cbdata->dirmapn)
+       cbdata->dirmap = growhash(cbdata->dirmap, &cbdata->dirmapn);
+      return;
+    }
+  /* we saw this dir before */
+  oidx = cbdata->dirmap[2 * h + 1];
+  if (oidx == idx)
+    return;
+  /* found a conflict, this dir may be used in multiple packages */
+  if (oidx != -1)
+    {
+      MAPSET(&cbdata->idxmap, oidx);
+      cbdata->dirmap[2 * h + 1] = -1;  /* mark as "multiple packages" */
+      cbdata->dirconflicts++;
+    }
+  MAPSET(&cbdata->idxmap, idx);
+}
+
+/* check if a dhx value is marked as "multiple" in the dirmap created by finddirs_cb */
+static inline int
+isindirmap(struct cbdata *cbdata, Id dhx)
+{
+  Hashval h, hh;
+  Id qx;
+
+  h = dhx & cbdata->dirmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->dirmap[2 * h];
+      if (!qx)
+       return 0;
+      if (qx == dhx)
+       return cbdata->dirmap[2 * h + 1] == -1 ? 1 : 0;
+      h = HASHCHAIN_NEXT(h, hh, cbdata->dirmapn);
+    }
+}
+
+/* collect all possible file conflicts candidates in cbdata->lookat */
+/* algorithm: hash file name into hx. Use cflmap the check if we have seen
+ * this value before. If yes, we have a file conflict candidate. */
+/* we also do extra work to ignore all-directory conflicts */
+static void
+findfileconflicts_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
+{
+  struct cbdata *cbdata = cbdatav;
+  int isdir = S_ISDIR(info->mode);
+  const char *dp;
+  Id idx, oidx;
+  Id hx, qx;
+  Hashval h, hh, dhx;
+
+  idx = cbdata->idx;
+
+  if (!info->dirlen)
+    return;
+  dp = fn + info->dirlen;
+  if (info->diridx != cbdata->lastdiridx)
+    {
+      cbdata->lastdiridx = info->diridx;
+      cbdata->lastdirhash = strnhash(fn, dp - fn);
+    }
+  dhx = cbdata->lastdirhash;
+
+  /* check if the directory is marked as "multiple" in the dirmap */
+  /* this mirrors the "if (!dhx) dhx = strlen(fn) + 1" used in  finddirs_cb */
+  if (!isindirmap(cbdata, dhx ? dhx : dp - fn + 1))
+    return;
+
+  hx = strhash_cont(dp, dhx);  /* extend hash to complete file name */
+  if (!hx)
+    hx = strlen(fn) + 1;       /* make sure hx is not zero */
+
+  h = hx & cbdata->cflmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->cflmap[2 * h];
+      if (!qx)
+       break;
+      if (qx == hx)
+       break;
+      h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
+    }
+  if (!qx)
+    {
+      /* a miss */
+      if (!cbdata->create)
+       return;
+      cbdata->cflmap[2 * h] = hx;
+      cbdata->cflmap[2 * h + 1] = (isdir ? ~idx : idx);
+      if (++cbdata->cflmapused * 2 > cbdata->cflmapn)
+       cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn);
+      return;
+    }
+  /* we have seen this hx before */
+  oidx = cbdata->cflmap[2 * h + 1];
+  if (oidx < 0)
+    {
+      int i;
+      if (isdir)
+       {
+         /* both are directories. delay the conflict, keep oidx in slot */
+          queue_push2(&cbdata->lookat_dir, hx, idx);
+         return;
+       }
+      oidx = ~oidx;
+      /* now have file, had directories before. */
+      cbdata->cflmap[2 * h + 1] = oidx;        /* make it a file */
+      /* dump all delayed directory hits for hx */
+      for (i = 0; i < cbdata->lookat_dir.count; i += 2)
+       if (cbdata->lookat_dir.elements[i] == hx)
+         {
+           queue_push2(&cbdata->lookat, hx, cbdata->lookat_dir.elements[i + 1]);
+           queue_push2(&cbdata->lookat, 0, 0);
+         }
+    }
+  else if (oidx == idx)
+    return;    /* no conflicts with ourself, please */
+  queue_push2(&cbdata->lookat, hx, oidx);
+  queue_push2(&cbdata->lookat, 0, 0);
+  queue_push2(&cbdata->lookat, hx, idx);
+  queue_push2(&cbdata->lookat, 0, 0);
+}
+
+/* same as findfileconflicts_cb, but
+ * - hashes with just the basename
+ * - sets idx in a map instead of pushing to lookat
+ * - sets the hash element to -1 ("multiple") if there may be a conflict
+ * we then use findfileconflicts_alias_cb as second step to generate the candidates.
+ * we do it this way because normailzing file names is expensive and thus we
+ * only want to do it for entries marked as "multiple"
+ */
+static void
+findfileconflicts_basename_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
+{
+  struct cbdata *cbdata = cbdatav;
+  int isdir = S_ISDIR(info->mode);
+  const char *dp;
+  Id idx, oidx;
+  Id hx, qx;
+  Hashval h, hh;
+
+  idx = cbdata->idx;
+
+  if (!info->dirlen)
+    return;
+  dp = fn + info->dirlen;
+  hx = strhash(dp);
+  if (!hx)
+    hx = strlen(fn) + 1;
+
+  h = hx & cbdata->cflmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->cflmap[2 * h];
+      if (!qx)
+       break;
+      if (qx == hx)
+       break;
+      h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
+    }
+  if (!qx)
+    {
+      /* a miss */
+      if (!cbdata->create)
+       return;
+      cbdata->cflmap[2 * h] = hx;
+      cbdata->cflmap[2 * h + 1] = (isdir ? -idx - 2 : idx);
+      if (++cbdata->cflmapused * 2 > cbdata->cflmapn)
+       cbdata->cflmap = growhash(cbdata->cflmap, &cbdata->cflmapn);
+      return;
+    }
+  oidx = cbdata->cflmap[2 * h + 1];
+  if (oidx < -1)
+    {
+      int i;
+      if (isdir)
+       {
+         /* both are directories. delay the conflict, keep oidx in slot */
+          queue_push2(&cbdata->lookat_dir, hx, idx);
+         return;
+       }
+      oidx = -idx - 2;
+      /* now have file, had directories before. */
+      cbdata->cflmap[2 * h + 1] = oidx;        /* make it a file */
+      /* dump all delayed directory hits for hx */
+      for (i = 0; i < cbdata->lookat_dir.count; i += 2)
+       if (cbdata->lookat_dir.elements[i] == hx)
+         MAPSET(&cbdata->idxmap, cbdata->lookat_dir.elements[i + 1]);
+    }
+  else if (oidx == idx)
+    return;    /* no conflicts with ourself, please */
+  if (oidx >= 0)
+    MAPSET(&cbdata->idxmap, oidx);
+  MAPSET(&cbdata->idxmap, idx);
+  if (oidx != -1)
+    cbdata->cflmap[2 * h + 1] = -1;
+}
+
+static inline Id
+addfilesspace(struct cbdata *cbdata, int len)
+{
+  unsigned int off = cbdata->filesspacen;
+  cbdata->filesspace = solv_extend(cbdata->filesspace, cbdata->filesspacen, len, 1, FILESSPACE_BLOCK);
+  cbdata->filesspacen += len;
+  return off;
+}
+
+static Id
+unifywithstat(struct cbdata *cbdata, Id diroff, int dirl)
+{
+  struct stat stb;
+  int i;
+  Hashval h, hh;
+  Id hx, qx;
+  Id nspaceoff;
+  unsigned char statdata[16 + sizeof(stb.st_dev) + sizeof(stb.st_ino)];
+
+  if (dirl > 1 && cbdata->filesspace[diroff + dirl - 1] == '/')
+    cbdata->filesspace[diroff + dirl - 1] = 0;
+  cbdata->statsmade++;
+  i = stat((char *)cbdata->filesspace + diroff, &stb);
+  if (dirl > 1 && cbdata->filesspace[diroff + dirl - 1] == 0)
+    cbdata->filesspace[diroff + dirl - 1] = '/';
+  if (i)
+    return diroff;
+  memset(statdata, 0, 16);
+  memcpy(statdata + 8, &stb.st_dev, sizeof(stb.st_dev));
+  memcpy(statdata, &stb.st_ino, sizeof(stb.st_ino));
+  hx = 0;
+  for (i = 15; i >= 0; i--)
+    hx = (unsigned int)hx * 13 + statdata[i];
+  h = hx & cbdata->statmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->statmap[2 * h];
+      if (!qx)
+       break;
+      if (qx == hx)
+       {
+         Id off = cbdata->statmap[2 * h + 1];
+         char *dp = (char *)cbdata->filesspace + cbdata->norq.elements[off];
+         if (!memcmp(dp, statdata, 16))
+           return cbdata->norq.elements[off + 1];
+       }
+      h = HASHCHAIN_NEXT(h, hh, cbdata->statmapn);
+    }
+  /* new stat result. work. */
+  nspaceoff = addfilesspace(cbdata, 16);
+  memcpy(cbdata->filesspace + nspaceoff, statdata, 16);
+  queue_push2(&cbdata->norq, nspaceoff, nspaceoff);
+  cbdata->statmap[2 * h] = hx;
+  cbdata->statmap[2 * h + 1] = cbdata->norq.count - 2;
+  if (++cbdata->statmapused * 2 > cbdata->statmapn)
+    cbdata->statmap = growhash(cbdata->statmap, &cbdata->statmapn);
+  return nspaceoff;
+}
+
+/* forward declaration */
+static Id normalizedir(struct cbdata *cbdata, const char *dir, int dirl, Id hx, int create);
+
+static Id
+unifywithcanon(struct cbdata *cbdata, Id diroff, int dirl)
+{
+  Id dirnameid;
+  int i, l, ll, lo;
+  struct stat stb;
+
+#if 0
+  printf("UNIFY %.*s\n", dirl, (char *)cbdata->filesspace + diroff);
+#endif
+  if (!dirl || cbdata->filesspace[diroff] != '/')
+    return diroff;
+  /* strip / at end*/
+  while (dirl && cbdata->filesspace[diroff + dirl - 1] == '/')
+    dirl--;
+  if (!dirl)
+    return diroff;
+
+  /* find dirname */
+  for (i = dirl - 1; i > 0; i--)
+    if (cbdata->filesspace[diroff + i] == '/')
+      break;
+  i++;                         /* include trailing / */
+
+  /* normalize dirname */
+  dirnameid = normalizedir(cbdata, (char *)cbdata->filesspace + diroff, i, strnhash((char *)cbdata->filesspace + diroff, i), 1);
+  if (dirnameid == -1)
+    return diroff;             /* hit "in progress" marker, some cyclic link */
+
+  /* sanity check result */
+  if (cbdata->filesspace[dirnameid] != '/')
+    return diroff;             /* hmm */
+  l = strlen((char *)cbdata->filesspace + dirnameid);
+  if (l && cbdata->filesspace[dirnameid + l - 1] != '/')
+    return diroff;             /* hmm */
+
+  /* special handling for "." and ".." basename */
+  if (cbdata->filesspace[diroff + i] == '.')
+    {
+      if (dirl - i == 1)
+       return dirnameid;
+      if (dirl - i == 2 && cbdata->filesspace[diroff + i + 1] == '.')
+       {
+         if (l <= 2)
+           return dirnameid;   /* we hit our root */
+         for (i = l - 2; i > 0; i--)
+           if (cbdata->filesspace[dirnameid + i] == '/')
+             break;
+         i++;  /* include trailing / */
+         dirnameid = normalizedir(cbdata, (char *)cbdata->filesspace + dirnameid, i, strnhash((char *)cbdata->filesspace + dirnameid, i), 1);
+         return dirnameid == -1 ? diroff : dirnameid;
+       }
+    }
+
+  /* append basename to normalized dirname */
+  if (cbdata->rootdirl + l + dirl - i + 1 > cbdata->canonspacen)
+    {
+      cbdata->canonspacen = cbdata->rootdirl + l + dirl - i + 20;
+      cbdata->canonspace = solv_realloc(cbdata->canonspace, cbdata->canonspacen);
+      strcpy(cbdata->canonspace, cbdata->rootdir);
+    }
+  strcpy(cbdata->canonspace + cbdata->rootdirl, (char *)cbdata->filesspace + dirnameid);
+  strncpy(cbdata->canonspace + cbdata->rootdirl + l, (char *)cbdata->filesspace + diroff + i, dirl - i);
+  cbdata->canonspace[cbdata->rootdirl + l + dirl - i] = 0;
+
+#if 0
+  printf("stat()ing %s\n", cbdata->canonspace);
+#endif
+  cbdata->statsmade++;
+  if (lstat(cbdata->canonspace, &stb) != 0 || !S_ISLNK(stb.st_mode))
+    {
+      /* not a symlink or stat failed, have new canon entry */
+      diroff = addfilesspace(cbdata, l + dirl - i + 2);
+      strcpy((char *)cbdata->filesspace + diroff, cbdata->canonspace + cbdata->rootdirl);
+      l += dirl - i;
+      /* add trailing / */
+      if (cbdata->filesspace[diroff + l - 1] != '/')
+       {
+         cbdata->filesspace[diroff + l++] = '/';
+         cbdata->filesspace[diroff + l] = 0;
+       }
+      /* call normalizedir on new entry for unification purposes */
+      dirnameid = normalizedir(cbdata, (char *)cbdata->filesspace + diroff, l, strnhash((char *)cbdata->filesspace + diroff, l), 1);
+      return dirnameid == -1 ? diroff : dirnameid;
+    }
+  /* oh no, a symlink! follow */
+  lo = cbdata->rootdirl + l + dirl - i + 1;
+  if (lo + stb.st_size + 2 > cbdata->canonspacen)
+    {
+      cbdata->canonspacen = lo + stb.st_size + 20;
+      cbdata->canonspace = solv_realloc(cbdata->canonspace, cbdata->canonspacen);
+    }
+  ll = readlink(cbdata->canonspace, cbdata->canonspace + lo, stb.st_size);
+  if (ll < 0 || ll > stb.st_size)
+    return diroff;             /* hmm */
+  if (ll == 0)
+    return dirnameid;          /* empty means current dir */
+  if (cbdata->canonspace[lo + ll - 1] != '/')
+    cbdata->canonspace[lo + ll++] = '/';       /* add trailing / */
+  cbdata->canonspace[lo + ll] = 0;             /* zero terminate */
+  if (cbdata->canonspace[lo] != '/')
+    {
+      /* relative link, concatenate to dirname */
+      memmove(cbdata->canonspace + cbdata->rootdirl + l, cbdata->canonspace + lo, ll + 1);
+      lo = cbdata->rootdirl;
+      ll += l;
+    }
+  dirnameid = normalizedir(cbdata, cbdata->canonspace + lo, ll, strnhash(cbdata->canonspace + lo, ll), 1);
+  return dirnameid == -1 ? diroff : dirnameid;
+}
+
+/*
+ * map a directory (containing a trailing /) into a number.
+ * for unifywithstat this is the offset to the 16 byte stat result.
+ * for unifywithcanon this is the offset to the normailzed dir.
+ */
+static Id
+normalizedir(struct cbdata *cbdata, const char *dir, int dirl, Id hx, int create)
+{
+  Hashval h, hh;
+  Id qx;
+  Id nspaceoff;
+  int mycnt;
+
+  if (!hx)
+    hx = dirl + 1;
+  h = hx & cbdata->normapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->normap[2 * h];
+      if (!qx)
+       break;
+      if (qx == hx)
+       {
+         Id off = cbdata->normap[2 * h + 1];
+         char *dp = (char *)cbdata->filesspace + cbdata->norq.elements[off];
+         if (!strncmp(dp, dir, dirl) && dp[dirl] == 0)
+           return cbdata->norq.elements[off + 1];
+       }
+      h = HASHCHAIN_NEXT(h, hh, cbdata->normapn);
+    }
+  if (!create)
+    return 0;
+  /* new dir. work. */
+  if (dir >= (const char *)cbdata->filesspace && dir < (const char *)cbdata->filesspace + cbdata->filesspacen)
+    {
+      /* can happen when called from unifywithcanon */
+      Id off = dir - (const char *)cbdata->filesspace;
+      nspaceoff = addfilesspace(cbdata, dirl + 1);
+      dir = (const char *)cbdata->filesspace + off;
+    }
+  else
+    nspaceoff = addfilesspace(cbdata, dirl + 1);
+  if (dirl)
+    memcpy(cbdata->filesspace + nspaceoff, dir, dirl);
+  cbdata->filesspace[nspaceoff + dirl] = 0;
+  mycnt = cbdata->norq.count;
+  queue_push2(&cbdata->norq, nspaceoff, -1);   /* -1: in progress */
+  cbdata->normap[2 * h] = hx;
+  cbdata->normap[2 * h + 1] = mycnt;
+  if (++cbdata->normapused * 2 > cbdata->normapn)
+    cbdata->normap = growhash(cbdata->normap, &cbdata->normapn);
+  /* unify */
+  if (cbdata->usestat)
+    nspaceoff = unifywithstat(cbdata, nspaceoff, dirl);
+  else
+    nspaceoff = unifywithcanon(cbdata, nspaceoff, dirl);
+  cbdata->norq.elements[mycnt + 1] = nspaceoff;        /* patch in result */
+#if 0
+  if (!cbdata->usestat)
+    printf("%s normalized to %d: %s\n", cbdata->filesspace + cbdata->norq.elements[mycnt], nspaceoff, cbdata->filesspace + nspaceoff);
+#endif
+  return nspaceoff;
+}
+
+/* collect all candidates for cflmap entries marked as "multiple" */
+static void
+findfileconflicts_alias_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
+{
+  int isdir = S_ISDIR(info->mode);
+  struct cbdata *cbdata = cbdatav;
+  const char *dp;
+  Id idx, dirid;
+  Id hx, qx;
+  Hashval h, hh;
+
+  idx = cbdata->idx;
+
+  if (!info->dirlen)
+    return;
+  dp = fn + info->dirlen;
+  if (info->diridx != cbdata->lastdiridx)
+    {
+      cbdata->lastdiridx = info->diridx;
+      cbdata->lastdirhash = 0;
+    }
+  dp = fn + info->dirlen;
+  hx = strhash(dp);
+  if (!hx)
+    hx = strlen(fn) + 1;
+
+  h = hx & cbdata->cflmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      qx = cbdata->cflmap[2 * h];
+      if (!qx)
+       break;
+      if (qx == hx)
+       break;
+      h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
+    }
+  if (!qx || cbdata->cflmap[2 * h + 1] != -1)
+    return;
+  /* found entry marked as "multiple", recored as conflict candidate */
+  if (!cbdata->lastdirhash)
+    cbdata->lastdirhash = strnhash(fn, dp - fn);
+  dirid = normalizedir(cbdata, fn, dp - fn, cbdata->lastdirhash, 1);
+  queue_push2(&cbdata->lookat, hx, idx);
+  queue_push2(&cbdata->lookat, cbdata->lastdirhash, isdir ? -dirid : dirid);
+}
+
+/* turn (hx, idx, dhx, dirid) entries into (hx, idx, off, dirid) entries,
+ * where off is an offset into the filespace block */
+static void
+findfileconflicts_expand_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
+{
+  struct cbdata *cbdata = cbdatav;
+  Id hx, dhx;
+  Hashval h, hh;
+  const char *dp;
+  char md5padded[34];
+  Id off, dirid;
+  int i;
+
+  if (!info->dirlen)
+    return;
+  dp = fn + info->dirlen;
+  if (info->diridx != cbdata->lastdiridx)
+    {
+      cbdata->lastdiridx = info->diridx;
+      cbdata->lastdirhash = strnhash(fn, dp - fn);
+      if (cbdata->aliases)
+        cbdata->lastdiridxbad = MAPTST(&cbdata->fetchdirmap, cbdata->lastdirhash & cbdata->fetchdirmapn) ? 0 : 1;
+    }
+  if (cbdata->lastdiridxbad)
+    return;
+  if (cbdata->aliases)
+    {
+      hx = strhash(dp);
+      dhx = cbdata->lastdirhash;
+      dirid =  normalizedir(cbdata, fn, dp - fn, dhx, 0);
+    }
+  else
+    {
+      hx = cbdata->lastdirhash;
+      hx = strhash_cont(dp, hx);
+      dhx = dirid = 0;
+    }
+  if (!hx)
+    hx = strlen(fn) + 1;
+
+  h = (hx ^ (dirid * 37)) & cbdata->fetchmapn;
+  hh = HASHCHAIN_START;
+  for (;;)
+    {
+      i = cbdata->fetchmap[h];
+      if (!i)
+       break;
+      if (cbdata->lookat.elements[i - 1] == hx && cbdata->lookat.elements[i + 2] == dirid && cbdata->lookat.elements[i + 1] == dhx)
+       {
+          /* printf("%d, hx %x dhx %x dirid %d -> %s   %d %s %d\n", cbdata->idx, hx, dhx, dirid, fn, info->mode, info->digest, info->color); */
+         strncpy(md5padded, info->digest, 32);
+         md5padded[32] = 0;
+         md5padded[33] = info->color;
+         off = addfilesspace(cbdata, strlen(fn) + (34 + 1));
+         memcpy(cbdata->filesspace + off, (unsigned char *)md5padded, 34);
+          strcpy((char *)cbdata->filesspace + off + 34, fn);
+         queue_push2(&cbdata->lookat, hx, cbdata->idx);
+         queue_push2(&cbdata->lookat, off, dirid);
+       }
+      h = HASHCHAIN_NEXT(h, hh, cbdata->fetchmapn);
+    }
+}
+
+static int
+lookat_idx_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap, *b = bp;
+  unsigned int ahx, bhx;
+  if (a[1] - b[1] != 0)                /* idx */
+    return a[1] - b[1];
+  if (a[3] - b[3] != 0)                /* dirid */
+    return a[3] - b[3];
+  ahx = (unsigned int)a[0];    /* can be < 0 */
+  bhx = (unsigned int)b[0];
+  if (ahx != bhx)
+    return ahx < bhx ? -1 : 1;
+  ahx = (unsigned int)a[2];    /* dhx */
+  bhx = (unsigned int)b[2];
+  if (ahx != bhx)
+    return ahx < bhx ? -1 : 1;
+  return 0;
+}
+
+static int
+lookat_hx_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap, *b = bp;
+  unsigned int ahx, bhx;
+  Id adirid, bdirid;
+  ahx = (unsigned int)a[0];    /* can be < 0 */
+  bhx = (unsigned int)b[0];
+  if (ahx != bhx)
+    return ahx < bhx ? -1 : 1;
+  adirid = a[3] < 0 ? -a[3] : a[3];
+  bdirid = b[3] < 0 ? -b[3] : b[3];
+  if (adirid - bdirid != 0)    /* dirid */
+    return adirid - bdirid;
+  if (a[3] != b[3])
+    return a[3] > 0 ? -1 : 1;  /* bring positive dirids to front */
+  if (a[1] - b[1] != 0)                /* idx */
+    return a[1] - b[1];
+  ahx = (unsigned int)a[2];    /* dhx */
+  bhx = (unsigned int)b[2];
+  if (ahx != bhx)
+    return ahx < bhx ? -1 : 1;
+  return 0;
+}
+
+static int
+conflicts_cmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  const Id *a = ap;
+  const Id *b = bp;
+  if (a[0] != b[0])    /* filename1 */
+    return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
+  if (a[3] != b[3])    /* filename2 */
+    return strcmp(pool_id2str(pool, a[3]), pool_id2str(pool, b[3]));
+  if (a[1] != b[1])    /* pkgid1 */
+    return a[1] - b[1];
+  if (a[4] != b[4])    /* pkgid2 */
+    return a[4] - b[4];
+  return 0;
+}
+
+static void
+iterate_solvable_dirs(Pool *pool, Id p, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata)
+{
+  Repodata *lastdata = 0;
+  Id lastdirid = -1;
+  Dataiterator di;
+
+  dataiterator_init(&di, pool, 0, p, SOLVABLE_FILELIST, 0, SEARCH_COMPLETE_FILELIST);
+  while (dataiterator_step(&di))
+    {
+      if (di.data == lastdata && di.kv.id == lastdirid)
+       continue;
+      lastdata = di.data;
+      lastdirid = di.kv.id;
+      cb(cbdata, repodata_dir2str(di.data, di.kv.id, ""), 0);
+    }
+  dataiterator_free(&di);
+}
+
+/* before calling the expensive findfileconflicts_cb we check if any of
+ * the files match. This only makes sense when cbdata->create is off.
+ */
+static int
+precheck_solvable_files(struct cbdata *cbdata, Pool *pool, Id p)
+{
+  Dataiterator di;
+  Id hx, qx;
+  Hashval h, hh;
+  int found = 0;
+  int aliases = cbdata->aliases;
+  unsigned int lastdirid = -1;
+  Hashval lastdirhash = 0;
+  int lastdirlen = 0;
+  int checkthisdir = 0;
+  Repodata *lastrepodata = 0;
+
+  dataiterator_init(&di, pool, 0, p, SOLVABLE_FILELIST, 0, SEARCH_COMPLETE_FILELIST);
+  while (dataiterator_step(&di))
+    {
+      if (aliases)
+       {
+         /* hash just the basename */
+         hx = strhash(di.kv.str);
+         if (!hx)
+           hx = strlen(di.kv.str) + 1;
+       }
+      else
+       {
+         /* hash the full path */
+         if (di.data != lastrepodata || di.kv.id != lastdirid)
+           {
+             const char *dir;
+             lastrepodata = di.data;
+             lastdirid = di.kv.id;
+             dir = repodata_dir2str(lastrepodata, lastdirid, "");
+             lastdirlen = strlen(dir);
+             lastdirhash = strhash(dir);
+             checkthisdir =  isindirmap(cbdata, lastdirhash ? lastdirhash : lastdirlen + 1);
+           }
+         if (!checkthisdir)
+           continue;
+         hx = strhash_cont(di.kv.str, lastdirhash);
+         if (!hx)
+           hx = lastdirlen + strlen(di.kv.str) + 1;
+       }
+      h = hx & cbdata->cflmapn;
+      hh = HASHCHAIN_START;
+      for (;;)
+       {
+         qx = cbdata->cflmap[2 * h];
+         if (!qx)
+           break;
+         if (qx == hx)
+           {
+             found = 1;
+             break;
+           }
+         h = HASHCHAIN_NEXT(h, hh, cbdata->cflmapn);
+       }
+      if (found)
+       break;
+    }
+  dataiterator_free(&di);
+  return found;
+}
+
+
+/* pool_findfileconflicts: find file conflicts in a set of packages
+ * input:
+ *   - pkgs: list of packages to check
+ *   - cutoff: packages after this are not checked against each other
+ *             this is useful to ignore file conflicts in already installed packages
+ *   - flags: see pool_fileconflicts.h
+ *   - handle_cb, handle_cbdata: callback for rpm header fetches
+ * output:
+ *   - conflicts: list of conflicts
+ *
+ * This is designed for needing only little memory while still being reasonable fast.
+ * We do this by hashing the file names and working with the 32bit hash values in the
+ * first steps of the algorithm. A hash conflict is not a problem as it will just
+ * lead to some unneeded extra work later on.
+ */
+
+int
+pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, int flags, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata)
+{
+  int i, j, idxmapset;
+  struct cbdata cbdata;
+  unsigned int now, start;
+  void *handle;
+  Repo *installed = pool->installed;
+  Id p;
+  int usefilecolors;
+  int hdrfetches;
+  int lookat_cnt;
+
+  queue_empty(conflicts);
+  if (!pkgs->count)
+    return 0;
+
+  now = start = solv_timems(0);
+  /* Hmm, should we have a different flag for this? */
+  usefilecolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "searching for file conflicts\n");
+  POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d, usefilecolors %d\n", pkgs->count, cutoff, usefilecolors);
+
+  memset(&cbdata, 0, sizeof(cbdata));
+  cbdata.aliases = flags & FINDFILECONFLICTS_CHECK_DIRALIASING;
+  cbdata.pool = pool;
+  if (cbdata.aliases && (flags & FINDFILECONFLICTS_USE_ROOTDIR) != 0)
+    {
+      cbdata.rootdir = pool_get_rootdir(pool);
+      if (cbdata.rootdir && !strcmp(cbdata.rootdir, "/"))
+       cbdata.rootdir = 0;
+      if (cbdata.rootdir)
+       cbdata.rootdirl = strlen(cbdata.rootdir);
+      if (!cbdata.rootdir)
+       cbdata.usestat = 1;
+    }
+  queue_init(&cbdata.lookat);
+  queue_init(&cbdata.lookat_dir);
+  map_init(&cbdata.idxmap, pkgs->count);
+
+  if (cutoff <= 0)
+    cutoff = pkgs->count;
+
+  /* avarage file list size: 200 files per package */
+  /* avarage dir count: 20 dirs per package */
+
+  /* first pass: find dirs belonging to multiple packages */
+  if (!cbdata.aliases)
+    {
+      hdrfetches = 0;
+      cbdata.dirmapn = mkmask((cutoff + 3) * 16);
+      cbdata.dirmap = solv_calloc(cbdata.dirmapn + 1, 2 * sizeof(Id));
+      cbdata.create = 1;
+      idxmapset = 0;
+      for (i = 0; i < pkgs->count; i++)
+       {
+         if (i == cutoff)
+           cbdata.create = 0;
+         cbdata.idx = i;
+         p = pkgs->elements[i];
+         if ((flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed)
+           {
+             if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed)
+               {
+                 iterate_solvable_dirs(pool, p, finddirs_cb, &cbdata);
+                 if (MAPTST(&cbdata.idxmap, i))
+                   idxmapset++;
+                 continue;
+               }
+           }
+         handle = (*handle_cb)(pool, p, handle_cbdata);
+         if (!handle)
+           continue;
+         hdrfetches++;
+         rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_ONLYDIRS, finddirs_cb, &cbdata);
+         if (MAPTST(&cbdata.idxmap, i))
+           idxmapset++;
+       }
+      POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap size: %d, used %d\n", cbdata.dirmapn + 1, cbdata.dirmapused);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap memory usage: %d K\n", (cbdata.dirmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap creation took %d ms\n", solv_timems(now));
+      POOL_DEBUG(SOLV_DEBUG_STATS, "dir conflicts found: %d, idxmap %d of %d\n", cbdata.dirconflicts, idxmapset, pkgs->count);
+    }
+
+  /* second pass: scan files in the directories found above */
+  now = solv_timems(0);
+  cbdata.cflmapn = mkmask((cutoff + 3) * 32);
+  cbdata.cflmap = solv_calloc(cbdata.cflmapn + 1, 2 * sizeof(Id));
+  cbdata.create = 1;
+  hdrfetches = 0;
+  for (i = 0; i < pkgs->count; i++)
+    {
+      if (i == cutoff)
+       cbdata.create = 0;
+      if (!cbdata.aliases && !MAPTST(&cbdata.idxmap, i))
+       continue;
+      cbdata.idx = i;
+      p = pkgs->elements[i];
+      if (!cbdata.create && (flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed)
+       {
+         if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed)
+           if (!precheck_solvable_files(&cbdata, pool, p))
+             continue;
+       }
+      /* can't use FINDFILECONFLICTS_USE_SOLVABLEFILELIST because we have to know if
+       * the file is a directory or not */
+      handle = (*handle_cb)(pool, p, handle_cbdata);
+      if (!handle)
+       continue;
+      hdrfetches++;
+      cbdata.lastdiridx = -1;
+      rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, cbdata.aliases ? findfileconflicts_basename_cb : findfileconflicts_cb, &cbdata);
+    }
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "filemap size: %d, used %d\n", cbdata.cflmapn + 1, cbdata.cflmapused);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "filemap memory usage: %d K\n", (cbdata.cflmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "filemap creation took %d ms\n", solv_timems(now));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "lookat_dir size: %d\n", cbdata.lookat_dir.count);
+  queue_free(&cbdata.lookat_dir);
+
+  /* we need another pass for aliases to generate the normalized directory ids */
+  queue_init(&cbdata.norq);
+  if (cbdata.aliases)
+    {
+      now = solv_timems(0);
+      addfilesspace(&cbdata, 1);       /* make sure the first offset is not zero */
+      cbdata.normapn = mkmask((cutoff + 3) * 4);
+      cbdata.normap = solv_calloc(cbdata.normapn + 1, 2 * sizeof(Id));
+      if (cbdata.usestat)
+       {
+         cbdata.statmapn = cbdata.normapn;
+         cbdata.statmap = solv_calloc(cbdata.statmapn + 1, 2 * sizeof(Id));
+       }
+      cbdata.create = 0;
+      hdrfetches = 0;
+      for (i = 0; i < pkgs->count; i++)
+       {
+         if (!MAPTST(&cbdata.idxmap, i))
+           continue;
+         p = pkgs->elements[i];
+         cbdata.idx = i;
+         /* can't use FINDFILECONFLICTS_USE_SOLVABLEFILELIST because we have to know if
+          * the file is a directory or not */
+         handle = (*handle_cb)(pool, p, handle_cbdata);
+         if (!handle)
+           continue;
+         hdrfetches++;
+         cbdata.lastdiridx = -1;
+         rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, findfileconflicts_alias_cb, &cbdata);
+       }
+      POOL_DEBUG(SOLV_DEBUG_STATS, "normap size: %d, used %d\n", cbdata.normapn + 1, cbdata.normapused);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "normap memory usage: %d K\n", (cbdata.normapn + 1) * 2 * (int)sizeof(Id) / 1024);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "stats made: %d\n", cbdata.statsmade);
+      if (cbdata.usestat)
+       {
+         POOL_DEBUG(SOLV_DEBUG_STATS, "statmap size: %d, used %d\n", cbdata.statmapn + 1, cbdata.statmapused);
+         POOL_DEBUG(SOLV_DEBUG_STATS, "statmap memory usage: %d K\n", (cbdata.statmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+       }
+      cbdata.statmap = solv_free(cbdata.statmap);
+      cbdata.statmapn = 0;
+      cbdata.canonspace = solv_free(cbdata.canonspace);
+      cbdata.canonspacen = 0;
+      POOL_DEBUG(SOLV_DEBUG_STATS, "alias processing took %d ms\n", solv_timems(now));
+    }
+
+  /* free no longer used stuff */
+  cbdata.dirmap = solv_free(cbdata.dirmap);
+  cbdata.dirmapn = 0;
+  cbdata.dirmapused = 0;
+  cbdata.cflmap = solv_free(cbdata.cflmap);
+  cbdata.cflmapn = 0;
+  cbdata.cflmapused = 0;
+  map_free(&cbdata.idxmap);
+
+  /* sort and unify/prune */
+  /* this also makes all dirids positive as side effect */
+  now = solv_timems(0);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "raw candidates: %d\n", cbdata.lookat.count / 4);
+  solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool);
+  for (i = j = 0; i < cbdata.lookat.count; )
+    {
+      int first = 1, jstart = j;
+      Id hx = cbdata.lookat.elements[i];
+      Id idx = cbdata.lookat.elements[i + 1];
+      Id dhx = cbdata.lookat.elements[i + 2];
+      Id dirid = cbdata.lookat.elements[i + 3];
+      i += 4;
+      for (; i < cbdata.lookat.count && hx == cbdata.lookat.elements[i] && (dirid == cbdata.lookat.elements[i + 3] || dirid == -cbdata.lookat.elements[i + 3]); i += 4)
+       {
+         if (idx == cbdata.lookat.elements[i + 1] && dhx == cbdata.lookat.elements[i + 2])
+           {
+             if (first && idx < cutoff && cbdata.aliases && dirid >= 0)
+               first = 0;      /* special self-conflict case with dhx hash collision, e.g. /foo/xx and /fpf/xx */
+             else
+               continue;       /* ignore duplicates */
+           }
+         if (first)
+           {
+             if (dirid < 0)
+               continue;       /* all have a neg dirid */
+             cbdata.lookat.elements[j++] = hx;
+             cbdata.lookat.elements[j++] = idx;
+             cbdata.lookat.elements[j++] = dhx;
+             cbdata.lookat.elements[j++] = dirid;
+             first = 0;
+             if (jstart >= 0 && idx < cutoff)
+               jstart = -1;
+           }
+         idx = cbdata.lookat.elements[i + 1];
+         dhx = cbdata.lookat.elements[i + 2];
+         cbdata.lookat.elements[j++] = hx;
+         cbdata.lookat.elements[j++] = idx;
+         cbdata.lookat.elements[j++] = dhx;
+         cbdata.lookat.elements[j++] = dirid;
+         if (jstart >= 0 && idx < cutoff)
+           jstart = -1;
+       }
+      if (jstart >= 0) /* we need at least one new candidate */
+       j = jstart;
+    }
+  queue_truncate(&cbdata.lookat, j);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "pruned candidates: %d\n", cbdata.lookat.count / 4);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "pruning took %d ms\n", solv_timems(now));
+
+  /* third pass: expand to real file names */
+  now = solv_timems(0);
+  /* sort by idx so we can do all files of a package in one go */
+  solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_idx_cmp, pool);
+  hdrfetches = 0;
+  queue_init(&cbdata.newlookat);
+  if (cbdata.lookat.count)
+    {
+      /* setup fetch map space */
+      cbdata.fetchmapn = mkmask(cbdata.lookat.count + 3);
+      if (cbdata.fetchmapn < 4095)
+        cbdata.fetchmapn = 4095;
+      cbdata.fetchmap = solv_calloc(cbdata.fetchmapn + 1, sizeof(Id));
+      if (cbdata.aliases)
+       {
+         cbdata.fetchdirmapn = ((cbdata.fetchmapn + 1) / 16) - 1;
+         map_init(&cbdata.fetchdirmap, cbdata.fetchdirmapn + 1);
+       }
+    }
+  lookat_cnt = cbdata.lookat.count;
+  while (lookat_cnt)
+    {
+      Id idx = cbdata.lookat.elements[1];
+      int iterflags = RPM_ITERATE_FILELIST_WITHMD5 | RPM_ITERATE_FILELIST_NOGHOSTS;
+      if (usefilecolors)
+       iterflags |= RPM_ITERATE_FILELIST_WITHCOL;
+      /* find end of idx block */
+      for (j = 4; j < lookat_cnt; j += 4)
+       if (cbdata.lookat.elements[j + 1] != idx)
+         break;
+      p = pkgs->elements[idx];
+      handle = (*handle_cb)(pool, p, handle_cbdata);
+      if (!handle)
+       {
+         queue_deleten(&cbdata.lookat, 0, j);
+         lookat_cnt -= j;
+         continue;
+       }
+      hdrfetches++;
+      /* create hash which maps (hx, dirid) to lookat elements */
+      /* also create map from dhx values for fast reject */
+      for (i = 0; i < j; i += 4)
+       {
+         Hashval h, hh;
+         h = (cbdata.lookat.elements[i] ^ (cbdata.lookat.elements[i + 3] * 37)) & cbdata.fetchmapn;
+         hh = HASHCHAIN_START;
+         while (cbdata.fetchmap[h])
+           h = HASHCHAIN_NEXT(h, hh, cbdata.fetchmapn);
+         cbdata.fetchmap[h] = i + 1;
+         cbdata.lookat.elements[i + 1] = (Id)h;        /* hack: misuse idx for easy hash cleanup */
+         if (cbdata.fetchdirmapn)
+           MAPSET(&cbdata.fetchdirmap, cbdata.lookat.elements[i + 2] & cbdata.fetchdirmapn);
+       }
+      cbdata.idx = idx;
+      cbdata.lastdiridx = -1;
+      cbdata.lastdiridxbad = 0;
+      queue_prealloc(&cbdata.newlookat, j + 256);
+      rpm_iterate_filelist(handle, iterflags, findfileconflicts_expand_cb, &cbdata);
+      /* clear hash and map again */
+      for (i = 0; i < j; i += 4)
+       {
+         Hashval h = (Hashval)cbdata.lookat.elements[i + 1];
+         cbdata.fetchmap[h] = 0;
+         if (cbdata.fetchdirmapn)
+           MAPCLR_AT(&cbdata.fetchdirmap, cbdata.lookat.elements[i + 2] & cbdata.fetchdirmapn);
+       }
+      /* now delete old block and add new block to the end */
+      queue_deleten(&cbdata.lookat, 0, j);
+      queue_insertn(&cbdata.lookat, cbdata.lookat.count, cbdata.newlookat.count, cbdata.newlookat.elements);
+      queue_empty(&cbdata.newlookat);
+      lookat_cnt -= j;
+    }
+  queue_free(&cbdata.newlookat);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "candidates now: %d\n", cbdata.lookat.count / 4);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "file expansion took %d ms\n", solv_timems(now));
+  /* free memory */
+  cbdata.fetchmap = solv_free(cbdata.fetchmap);
+  cbdata.fetchmapn = 0;
+  if (cbdata.fetchdirmapn)
+    map_free(&cbdata.fetchdirmap);
+  cbdata.fetchdirmapn = 0;
+  cbdata.normap = solv_free(cbdata.normap);
+  cbdata.normapn = 0;
+  queue_free(&cbdata.norq);
+
+  /* forth pass: for each (hx,dirid) we have, compare all matching files against all other matching files */
+  now = solv_timems(0);
+  solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool);
+  for (i = 0; i < cbdata.lookat.count - 4; i += 4)
+    {
+      Id hx = cbdata.lookat.elements[i];
+      Id dirid = cbdata.lookat.elements[i + 3];
+      Id idxi = cbdata.lookat.elements[i + 1];
+      Id offi = cbdata.lookat.elements[i + 2];
+      if (idxi >= cutoff)
+       continue;       /* no conflicts between packages with idx >= cutoff */
+      for (j = i + 4; j < cbdata.lookat.count && cbdata.lookat.elements[j] == hx && cbdata.lookat.elements[j + 3] == dirid; j += 4)
+       {
+         Id idxj = cbdata.lookat.elements[j + 1];
+         Id offj = cbdata.lookat.elements[j + 2];
+         char *fsi = (char *)cbdata.filesspace + offi;
+         char *fsj = (char *)cbdata.filesspace + offj;
+         if (cbdata.aliases)
+           {
+             /* compare just the basenames, the dirs match because of the dirid */
+             char *bsi = strrchr(fsi + 34, '/');
+             char *bsj = strrchr(fsj + 34, '/');
+             if (!bsi || !bsj)
+               continue;
+             if (strcmp(bsi, bsj))
+               continue;       /* different base names */
+           }
+         else
+           {
+             if (strcmp(fsi + 34, fsj + 34))
+               continue;       /* different file names */
+           }
+         if (!strcmp(fsi, fsj))
+           continue;   /* file digests match, no conflict */
+         if (usefilecolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0)
+           continue;   /* colors do not conflict */
+         queue_push(conflicts, pool_str2id(pool, fsi + 34, 1));
+         queue_push(conflicts, pkgs->elements[idxi]);
+         queue_push(conflicts, pool_str2id(pool, fsi, 1));
+         queue_push(conflicts, pool_str2id(pool, fsj + 34, 1));
+         queue_push(conflicts, pkgs->elements[idxj]);
+         queue_push(conflicts, pool_str2id(pool, fsj, 1));
+       }
+    }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "filespace size: %d K\n", cbdata.filesspacen / 1024);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "candidate check took %d ms\n", solv_timems(now));
+  cbdata.filesspace = solv_free(cbdata.filesspace);
+  cbdata.filesspacen = 0;
+  queue_free(&cbdata.lookat);
+  if (conflicts->count > 6)
+    solv_sort(conflicts->elements, conflicts->count / 6, 6 * sizeof(Id), conflicts_cmp, pool);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file conflicts\n", conflicts->count / 6);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "file conflict detection took %d ms\n", solv_timems(start));
+
+  return conflicts->count / 6;
+}
+
diff --git a/libsolv-0.7.2/ext/pool_fileconflicts.h b/libsolv-0.7.2/ext/pool_fileconflicts.h
new file mode 100644 (file)
index 0000000..13abdc7
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2009-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef POOL_FILECONFLICTS_H
+#define POOL_FILECONFLICTS_H
+
+#include "pool.h"
+
+extern int pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, int flags, void *(*handle_cb)(Pool *, Id, void *) , void *handle_cbdata);
+
+#define FINDFILECONFLICTS_USE_SOLVABLEFILELIST (1 << 0)
+#define FINDFILECONFLICTS_CHECK_DIRALIASING    (1 << 1)
+#define FINDFILECONFLICTS_USE_ROOTDIR          (1 << 2)
+
+#endif
diff --git a/libsolv-0.7.2/ext/pool_parserpmrichdep.c b/libsolv-0.7.2/ext/pool_parserpmrichdep.c
new file mode 100644 (file)
index 0000000..93d77f8
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* this is used by repo_rpmmd, repo_rpmdb, and repo_susetags */
+
+#include <stdio.h>
+
+#include "pool.h"
+#include "pool_parserpmrichdep.h"
+
+static struct RichOpComp {
+  const char *n;
+  int l;
+  Id fl;
+} RichOps[] = {
+  { "and",     3, REL_AND },
+  { "or",      2, REL_OR },
+  { "if",      2, REL_COND },
+  { "unless",  6, REL_UNLESS },
+  { "else",    4, REL_ELSE },
+  { "with",    4, REL_WITH },
+  { "without", 7, REL_WITHOUT },
+  { NULL, 0, 0},
+};
+
+static Id
+parseRichDep(Pool *pool, const char **depp, Id chainfl)
+{
+  const char *p = *depp;
+  const char *n;
+  Id id, evr;
+  int fl, bl;
+  struct RichOpComp *op;
+
+  if (!chainfl && *p++ != '(')
+    return 0;
+  while (*p == ' ')
+    p++;
+  if (*p == ')')
+    return 0;
+  if (*p == '(')
+    {
+      id = parseRichDep(pool, &p, 0);
+      if (!id)
+       return 0;
+    }
+  else
+    {
+      n = p;
+      bl = 0;
+      while (*p && !(*p == ' ' || *p == ',' || (*p == ')' && bl-- <= 0)))
+       if (*p++ == '(')
+         bl++;
+      if (n == p)
+       return 0;
+      id = pool_strn2id(pool, n, p - n, 1);
+      while (*p == ' ')
+       p++;
+      if (*p)
+       {
+         fl = 0;
+         for (;; p++)
+           {
+             if (*p == '<')
+               fl |= REL_LT;
+             else if (*p == '=')
+               fl |= REL_EQ;
+             else if (*p == '>')
+               fl |= REL_GT;
+             else
+               break;
+           }
+         if (fl)
+           {
+             while (*p == ' ')
+               p++;
+             n = p;
+             bl = 0;
+             while (*p && !(*p == ' ' || *p == ',' || (*p == ')' && bl-- <= 0)))
+               if (*p++ == '(')
+                 bl++;
+             if (p - n > 2 && n[0] == '0' && n[1] == ':')
+               n += 2;         /* strip zero epoch */
+             if (n == p)
+               return 0;
+             id = pool_rel2id(pool, id, pool_strn2id(pool, n, p - n, 1), fl, 1);
+           }
+       }
+    }
+  while (*p == ' ')
+    p++;
+  if (!*p)
+    return 0;
+  if (*p == ')')
+    {
+      *depp = p + 1;
+      return id;
+    }
+  n = p;
+  while (*p && *p != ' ')
+    p++;
+  for (op = RichOps; op->n; op++)
+    if (p - n == op->l && !strncmp(n, op->n, op->l))
+      break;
+  fl = op->fl;
+  if (!fl)
+    return 0;
+  if ((chainfl == REL_COND || chainfl == REL_UNLESS) && fl == REL_ELSE)
+    chainfl = 0;
+  if (chainfl && fl != chainfl)
+    return 0;
+  evr = parseRichDep(pool, &p, fl);
+  if (!evr)
+    return 0;
+  *depp = p;
+  return pool_rel2id(pool, id, evr, fl, 1);
+}
+
+Id
+pool_parserpmrichdep(Pool *pool, const char *dep)
+{
+  Id id = parseRichDep(pool, &dep, 0);
+  if (id && *dep)
+    id = 0;
+  return id;
+}
+
diff --git a/libsolv-0.7.2/ext/pool_parserpmrichdep.h b/libsolv-0.7.2/ext/pool_parserpmrichdep.h
new file mode 100644 (file)
index 0000000..09dce2c
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef POOL_PARSERPMRICHDEP_H
+#define POOL_PARSERPMRICHDEP_H
+
+#include "pool.h"
+
+extern Id pool_parserpmrichdep(Pool *pool, const char *dep);
+
+#endif
diff --git a/libsolv-0.7.2/ext/repo_appdata.c b/libsolv-0.7.2/ext/repo_appdata.c
new file mode 100644 (file)
index 0000000..3174968
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * repo_appdatadb.c
+ *
+ * Parses AppSteam Data files.
+ * See http://people.freedesktop.org/~hughsient/appdata/
+ *
+ *
+ * Copyright (c) 2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "solv_xmlparser.h"
+#include "repo_appdata.h"
+
+
+enum state {
+  STATE_START,
+  STATE_APPLICATION,
+  STATE_ID,
+  STATE_PKGNAME,
+  STATE_LICENCE,
+  STATE_NAME,
+  STATE_SUMMARY,
+  STATE_DESCRIPTION,
+  STATE_P,
+  STATE_UL,
+  STATE_UL_LI,
+  STATE_OL,
+  STATE_OL_LI,
+  STATE_URL,
+  STATE_GROUP,
+  STATE_KEYWORDS,
+  STATE_KEYWORD,
+  STATE_EXTENDS,
+  NUMSTATES
+};
+
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START,       "applications",  STATE_START,         0 },
+  { STATE_START,       "components",    STATE_START,         0 },
+  { STATE_START,       "application",   STATE_APPLICATION,   0 },
+  { STATE_START,       "component",     STATE_APPLICATION,   0 },
+  { STATE_APPLICATION, "id",            STATE_ID,            1 },
+  { STATE_APPLICATION, "pkgname",       STATE_PKGNAME,       1 },
+  { STATE_APPLICATION, "product_license", STATE_LICENCE,     1 },
+  { STATE_APPLICATION, "name",          STATE_NAME,          1 },
+  { STATE_APPLICATION, "summary",       STATE_SUMMARY,       1 },
+  { STATE_APPLICATION, "description",   STATE_DESCRIPTION,   0 },
+  { STATE_APPLICATION, "url",           STATE_URL,           1 },
+  { STATE_APPLICATION, "project_group", STATE_GROUP,         1 },
+  { STATE_APPLICATION, "keywords",      STATE_KEYWORDS,      0 },
+  { STATE_APPLICATION, "extends",       STATE_EXTENDS,       1 },
+  { STATE_DESCRIPTION, "p",             STATE_P,             1 },
+  { STATE_DESCRIPTION, "ul",            STATE_UL,            0 },
+  { STATE_DESCRIPTION, "ol",            STATE_OL,            0 },
+  { STATE_UL,          "li",            STATE_UL_LI,         1 },
+  { STATE_OL,          "li",            STATE_OL_LI,         1 },
+  { STATE_KEYWORDS,    "keyword",       STATE_KEYWORD,       1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  int ret;
+
+  Solvable *solvable;
+  Id handle;
+
+  int skiplang;
+  char *description;
+  int licnt;
+  int skip_depth;
+  int flags;
+  char *desktop_file;
+  int havesummary;
+  const char *filename;
+  Queue *owners;
+
+  struct solv_xmlparser xmlp;
+};
+
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+  const char *type;
+
+  /* ignore all language tags */
+  if (pd->skiplang || solv_xmlparser_find_attr("xml:lang", atts))
+    {
+      pd->skiplang++;
+      return;
+    }
+
+  switch(state)
+    {
+    case STATE_APPLICATION:
+      type = solv_xmlparser_find_attr("type", atts);
+      if (!type || !*type)
+        type = "desktop";
+      if (strcmp(type, "desktop") != 0)
+       {
+         /* ignore for now */
+         pd->solvable = 0;
+         break;
+       }
+      s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+      pd->handle = s - pool->solvables;
+      pd->havesummary = 0;
+      repodata_set_poolstr(pd->data, pd->handle, SOLVABLE_CATEGORY, type);
+      break;
+    case STATE_DESCRIPTION:
+      pd->description = solv_free(pd->description);
+      break;
+    case STATE_OL:
+    case STATE_UL:
+      pd->licnt = 0;
+      break;
+    default:
+      break;
+    }
+}
+
+/* replace whitespace with one space/newline */
+/* also strip starting/ending whitespace */
+static char *
+wsstrip(struct parsedata *pd)
+{
+  struct solv_xmlparser *xmlp = &pd->xmlp;
+  int i, j;
+  int ws = 0;
+  for (i = j = 0; xmlp->content[i]; i++)
+    {
+      if (xmlp->content[i] == ' ' || xmlp->content[i] == '\t' || xmlp->content[i] == '\n')
+       {
+         ws |= xmlp->content[i] == '\n' ? 2 : 1;
+         continue;
+       }
+      if (ws && j)
+       xmlp->content[j++] = (ws & 2) ? '\n' : ' ';
+      ws = 0;
+      xmlp->content[j++] = xmlp->content[i];
+    }
+  xmlp->content[j] = 0;
+  xmlp->lcontent = j;
+  return xmlp->content;
+}
+
+/* indent all lines */
+static char *
+indent(struct parsedata *pd, int il)
+{
+  struct solv_xmlparser *xmlp = &pd->xmlp;
+  int i, l;
+  for (l = 0; xmlp->content[l]; )
+    {
+      if (xmlp->content[l] == '\n')
+       {
+         l++;
+         continue;
+       }
+      if (xmlp->lcontent + il + 1 > xmlp->acontent)
+       {
+         xmlp->acontent = xmlp->lcontent + il + 256;
+         xmlp->content = realloc(xmlp->content, xmlp->acontent);
+       }
+      memmove(xmlp->content + l + il, xmlp->content + l, xmlp->lcontent - l + 1);
+      for (i = 0; i < il; i++)
+       xmlp->content[l + i] = ' ';
+      xmlp->lcontent += il;
+      while (xmlp->content[l] && xmlp->content[l] != '\n')
+       l++;
+    }
+  return xmlp->content;
+}
+
+static void
+add_missing_tags_from_desktop_file(struct parsedata *pd, Solvable *s, const char *desktop_file)
+{
+  Pool *pool = pd->pool;
+  FILE *fp;
+  const char *filepath;
+  char buf[1024];
+  char *p, *p2, *p3;
+  int inde = 0;
+
+  filepath = pool_tmpjoin(pool, "/usr/share/applications/", desktop_file, 0);
+  if (pd->flags & REPO_USE_ROOTDIR)
+    filepath = pool_prepend_rootdir_tmp(pool, filepath);
+  if (!(fp = fopen(filepath, "r")))
+    return;
+  while (fgets(buf, sizeof(buf), fp) > 0)
+    {
+      int c, l = strlen(buf);
+      if (!l)
+       continue;
+      if (buf[l - 1] != '\n')
+       {
+         /* ignore overlong lines */
+         while ((c = getc(fp)) != EOF)
+           if (c == '\n')
+             break;
+         if (c == EOF)
+           break;
+         continue;
+       }
+      buf[--l] = 0;
+      while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+        buf[--l] = 0;
+      p = buf;
+      while (*p == ' ' || *p == '\t')
+       p++;
+      if (!*p || *p == '#')
+       continue;
+      if (*p == '[')
+       inde = 0;
+      if (!strcmp(p, "[Desktop Entry]"))
+       {
+         inde = 1;
+         continue;
+       }
+      if (!inde)
+       continue;
+      p2 = strchr(p, '=');
+      if (!p2 || p2 == p)
+       continue;
+      *p2 = 0;
+      for (p3 = p2 - 1; *p3 == ' ' || *p3 == '\t'; p3--)
+       *p3 = 0;
+      p2++;
+      while (*p2 == ' ' || *p2 == '\t')
+       p2++;
+      if (!*p2)
+       continue;
+      if (!s->name && !strcmp(p, "Name"))
+       s->name = pool_str2id(pool, pool_tmpjoin(pool, "application:", p2, 0), 1);
+      else if (!pd->havesummary && !strcmp(p, "Comment"))
+       {
+         pd->havesummary = 1;
+         repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, p2);
+       }
+      else
+       continue;
+      if (s->name && pd->havesummary)
+       break;  /* our work is done */
+    }
+  fclose(fp);
+}
+
+static char *
+guess_filename_from_id(Pool *pool, const char *id)
+{
+  int l = strlen(id);
+  char *r = pool_tmpjoin(pool, id, ".metainfo.xml", 0);
+  if (l > 8 && !strcmp(".desktop", id + l - 8))
+    strcpy(r + l - 8, ".appdata.xml");
+  else if (l > 4 && !strcmp(".ttf", id + l - 4))
+    strcpy(r + l - 4, ".metainfo.xml");
+  else if (l > 4 && !strcmp(".otf", id + l - 4))
+    strcpy(r + l - 4, ".metainfo.xml");
+  else if (l > 4 && !strcmp(".xml", id + l - 4))
+    strcpy(r + l - 4, ".metainfo.xml");
+  else if (l > 3 && !strcmp(".db", id + l - 3))
+    strcpy(r + l - 3, ".metainfo.xml");
+  else
+    return 0;
+  return r;
+}
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+  Id id;
+
+  if (pd->skiplang)
+    {
+      pd->skiplang--;
+      return;
+    }
+  if (!s)
+    return;
+
+  switch (state)
+    {
+    case STATE_APPLICATION:
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      if ((!s->name || !pd->havesummary) && (pd->flags & APPDATA_CHECK_DESKTOP_FILE) != 0 && pd->desktop_file)
+       add_missing_tags_from_desktop_file(pd, s, pd->desktop_file);
+      if (!s->name && pd->desktop_file)
+       {
+          char *name = pool_tmpjoin(pool, "application:", pd->desktop_file, 0);
+         int l = strlen(name);
+         if (l > 8 && !strcmp(".desktop", name + l - 8))
+           l -= 8;
+         s->name = pool_strn2id(pool, name, l, 1);
+       }
+      if (!s->requires && pd->owners)
+       {
+         int i;
+         Id id;
+         for (i = 0; i < pd->owners->count; i++)
+           {
+             Solvable *os = pd->pool->solvables + pd->owners->elements[i];
+             s->requires = repo_addid_dep(pd->repo, s->requires, os->name, 0);
+             id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", pool_id2str(pd->pool, os->name), ")"), 1);
+             s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
+           }
+       }
+      if (!s->requires && (pd->desktop_file || pd->filename))
+       {
+         /* add appdata() link requires/provides */
+         const char *filename = pd->filename;
+         if (!filename)
+           filename = guess_filename_from_id(pool, pd->desktop_file);
+         if (filename)
+           {
+             filename = pool_tmpjoin(pool, "application-appdata(", filename, ")");
+             s->requires = repo_addid_dep(pd->repo, s->requires, pool_str2id(pd->pool, filename + 12, 1), 0);
+             s->provides = repo_addid_dep(pd->repo, s->provides, pool_str2id(pd->pool, filename, 1), 0);
+           }
+       }
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
+      pd->solvable = 0;
+      pd->desktop_file = solv_free(pd->desktop_file);
+      break;
+    case STATE_ID:
+      pd->desktop_file = solv_strdup(content);
+      break;
+    case STATE_NAME:
+      s->name = pool_str2id(pd->pool, pool_tmpjoin(pool, "application:", content, 0), 1);
+      break;
+    case STATE_LICENCE:
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_LICENSE, content);
+      break;
+    case STATE_SUMMARY:
+      pd->havesummary = 1;
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content);
+      break;
+    case STATE_URL:
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_URL, content);
+      break;
+    case STATE_GROUP:
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_GROUP, content);
+      break;
+    case STATE_EXTENDS:
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_EXTENDS, content);
+      break;
+    case STATE_DESCRIPTION:
+      if (pd->description)
+       {
+         /* strip trailing newlines */
+         int l = strlen(pd->description);
+         while (l && pd->description[l - 1] == '\n')
+           pd->description[--l] = 0;
+          repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, pd->description);
+       }
+      break;
+    case STATE_P:
+      content = wsstrip(pd);
+      pd->description = solv_dupappend(pd->description, content, "\n\n");
+      break;
+    case STATE_UL_LI:
+      wsstrip(pd);
+      content = indent(pd, 4);
+      content[2] = '-';
+      pd->description = solv_dupappend(pd->description, content, "\n");
+      break;
+    case STATE_OL_LI:
+      wsstrip(pd);
+      content = indent(pd, 4);
+      if (++pd->licnt >= 10)
+       content[0] = '0' + (pd->licnt / 10) % 10;
+      content[1] = '0' + pd->licnt  % 10;
+      content[2] = '.';
+      pd->description = solv_dupappend(pd->description, content, "\n");
+      break;
+    case STATE_UL:
+    case STATE_OL:
+      pd->description = solv_dupappend(pd->description, "\n", 0);
+      break;
+    case STATE_PKGNAME:
+      id = pool_str2id(pd->pool, content, 1);
+      s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
+      id = pool_str2id(pd->pool, pool_tmpjoin(pd->pool, "application-appdata(", content, ")"), 1);
+      s->provides = repo_addid_dep(pd->repo, s->provides, id, 0);
+      break;
+    case STATE_KEYWORD:
+      repodata_add_poolstr_array(pd->data, pd->handle, SOLVABLE_KEYWORDS, content);
+      break;
+    default:
+      break;
+    }
+}
+
+static int
+repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue *owners)
+{
+  Repodata *data;
+  struct parsedata pd;
+
+  data = repo_add_repodata(repo, flags);
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+  pd.flags = flags;
+  pd.filename = filename;
+  pd.owners = owners;
+
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    {
+      pool_debug(pd.pool, SOLV_ERROR, "repo_appdata: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+      pd.ret = -1;
+      pd.solvable = solvable_free(pd.solvable, 1);
+    }
+  solv_xmlparser_free(&pd.xmlp);
+
+  solv_free(pd.desktop_file);
+  solv_free(pd.description);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+
+  return pd.ret;
+}
+
+int
+repo_add_appdata(Repo *repo, FILE *fp, int flags)
+{
+  return repo_add_appdata_fn(repo, fp, flags, 0, 0);
+}
+
+struct uninternalized_filelist_data {
+  Id did;
+  Queue *res;
+};
+
+static int
+search_uninternalized_filelist_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  struct uninternalized_filelist_data *uf = cbdata;
+  const char *str;
+  Id id;
+  size_t l;
+  if (key->type != REPOKEY_TYPE_DIRSTRARRAY || kv->id != uf->did)
+    return 0;
+  str = kv->str;
+  l = strlen(str);
+  if (l > 12 && strncmp(str + l - 12, ".appdata.xml", 12))
+    id = pool_str2id(data->repo->pool, str, 1);
+  else if (l > 13 && strncmp(str + l - 13, ".metainfo.xml", 13))
+    id = pool_str2id(data->repo->pool, str, 1);
+  else
+    return 0;
+  queue_push2(uf->res, s - data->repo->pool->solvables, id);
+  return 0;
+}
+
+static void
+search_uninternalized_filelist(Repo *repo, const char *dir, Queue *res)
+{
+  Pool *pool = repo->pool;
+  Id did, rdid, p;
+  struct uninternalized_filelist_data uf;
+
+  uf.res = res;
+  for (rdid = 1; rdid < repo->nrepodata; rdid++)
+    {
+      Repodata *data = repo_id2repodata(repo, rdid);
+      if (!data)
+       continue;
+      if (data->state == REPODATA_STUB)
+       continue;
+      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+       continue;
+      did = repodata_str2dir(data, dir, 0);
+      if (!did)
+       continue;
+      uf.did = did;
+      for (p = data->start; p < data->end; p++)
+       {
+         if (p >= pool->nsolvables || pool->solvables[p].repo != repo)
+           continue;
+         repodata_search_uninternalized(data, p, SOLVABLE_FILELIST, 0, search_uninternalized_filelist_cb, &uf);
+       }
+    }
+}
+
+/* add all files ending in .appdata.xml */
+int
+repo_add_appdata_dir(Repo *repo, const char *appdatadir, int flags)
+{
+  DIR *dir;
+  char *dirpath;
+  Repodata *data;
+  Queue flq;
+  Queue oq;
+
+  queue_init(&flq);
+  queue_init(&oq);
+  if (flags & APPDATA_SEARCH_UNINTERNALIZED_FILELIST)
+    search_uninternalized_filelist(repo, appdatadir, &flq);
+  data = repo_add_repodata(repo, flags);
+  if (flags & REPO_USE_ROOTDIR)
+    dirpath = pool_prepend_rootdir(repo->pool, appdatadir);
+  else
+    dirpath = solv_strdup(appdatadir);
+  if ((dir = opendir(dirpath)) != 0)
+    {
+      struct dirent *entry;
+      while ((entry = readdir(dir)))
+       {
+         const char *n;
+         FILE *fp;
+         int len = strlen(entry->d_name);
+         if (entry->d_name[0] == '.')
+           continue;
+         if (!(len > 12 && !strcmp(entry->d_name + len - 12, ".appdata.xml")) &&
+             !(len > 13 && !strcmp(entry->d_name + len - 13, ".metainfo.xml")))
+           continue;
+          n = pool_tmpjoin(repo->pool, dirpath, "/", entry->d_name);
+         fp = fopen(n, "r");
+         if (!fp)
+           {
+             pool_error(repo->pool, 0, "%s: %s", n, strerror(errno));
+             continue;
+           }
+         if (flags & APPDATA_SEARCH_UNINTERNALIZED_FILELIST)
+           {
+             Id id = pool_str2id(repo->pool, entry->d_name, 0);
+             queue_empty(&oq);
+             if (id)
+               {
+                 int i;
+                 for (i = 0; i < flq.count; i += 2)
+                   if (flq.elements[i + 1] == id)
+                     queue_push(&oq, flq.elements[i]);
+               }
+           }
+         repo_add_appdata_fn(repo, fp, flags | REPO_NO_INTERNALIZE | REPO_REUSE_REPODATA | APPDATA_CHECK_DESKTOP_FILE, entry->d_name, oq.count ? &oq : 0);
+         fclose(fp);
+       }
+      closedir(dir);
+    }
+  solv_free(dirpath);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  queue_free(&oq);
+  queue_free(&flq);
+  return 0;
+}
diff --git a/libsolv-0.7.2/ext/repo_appdata.h b/libsolv-0.7.2/ext/repo_appdata.h
new file mode 100644 (file)
index 0000000..db5f2cf
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+int repo_add_appdata(Repo *repo, FILE *fp, int flags);
+int repo_add_appdata_dir(Repo *repo, const char *appdatadir, int flags);
+
+#define APPDATA_SEARCH_UNINTERNALIZED_FILELIST         (1 << 8)
+#define APPDATA_CHECK_DESKTOP_FILE     (1 << 30)       /* internal */
diff --git a/libsolv-0.7.2/ext/repo_arch.c b/libsolv-0.7.2/ext/repo_arch.c
new file mode 100644 (file)
index 0000000..698d506
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "chksum.h"
+#include "solv_xfopen.h"
+#include "repo_arch.h"
+
+static long long parsenum(unsigned char *p, int cnt)
+{
+  long long x = 0;
+  if (!cnt)
+    return -1;
+  if (*p & 0x80)
+    {
+      /* binary format */
+      x = *p & 0x40 ? (-1 << 8 | *p)  : (*p ^ 0x80);
+      while (--cnt > 0)
+       x = (x << 8) | *p++;
+      return x;
+    }
+  while (cnt > 0 && (*p == ' ' || *p == '\t'))
+    cnt--, p++;
+  if (*p == '-')
+    return -1;
+  for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
+    x = (x << 3) | (*p - '0');
+  return x;
+}
+
+static int readblock(FILE *fp, unsigned char *blk)
+{
+  int r, l = 0;
+  while (l < 512)
+    {
+      r = fread(blk + l, 1, 512 - l, fp);
+      if (r <= 0)
+       return -1;
+      l += r;
+    }
+  return 0;
+}
+
+struct tarhead {
+  FILE *fp;
+  unsigned char blk[512];
+  int type;
+  long long length;
+  char *path;
+  int eof;
+  int ispax;
+  int off;
+  int end;
+};
+
+static char *getsentry(struct tarhead *th, char *s, int size)
+{
+  char *os = s;
+  if (th->eof || size <= 1)
+    return 0;
+  size--;      /* terminating 0 */
+  for (;;)
+    {
+      int i;
+      for (i = th->off; i < th->end; i++)
+       {
+         *s++ = th->blk[i];
+         size--;
+         if (!size || th->blk[i] == '\n')
+           {
+             th->off = i + 1;
+             *s = 0;
+             return os;
+           }
+       }
+      th->off = i;
+      if (!th->path)
+       {
+         /* fake entry */
+         th->end = fread(th->blk, 1, 512, th->fp);
+         if (th->end <= 0)
+           {
+             th->eof = 1;
+             return 0;
+           }
+         th->off = 0;
+         continue;
+       }
+      if (th->length <= 0)
+       return 0;
+      if (readblock(th->fp, th->blk))
+       {
+         th->eof = 1;
+         return 0;
+       }
+      th->off = 0;
+      th->end = th->length > 512 ? 512 : th->length;
+      th->length -= th->end;
+    }
+}
+
+static void skipentry(struct tarhead *th)
+{
+  for (; th->length > 0; th->length -= 512)
+    {
+      if (readblock(th->fp, th->blk))
+       {
+         th->eof = 1;
+         th->length = 0;
+         return;
+       }
+    }
+  th->length = 0;
+  th->off = th->end = 0;
+}
+
+static void inittarhead(struct tarhead *th, FILE *fp)
+{
+  memset(th, 0, sizeof(*th));
+  th->fp = fp;
+}
+
+static void freetarhead(struct tarhead *th)
+{
+  solv_free(th->path);
+}
+
+static int gettarhead(struct tarhead *th)
+{
+  int l, type;
+  long long length;
+
+  th->path = solv_free(th->path);
+  th->ispax = 0;
+  th->type = 0;
+  th->length = 0;
+  th->off = 0;
+  th->end = 0;
+  if (th->eof)
+    return 0;
+  for (;;)
+    {
+      int r = readblock(th->fp, th->blk);
+      if (r)
+       {
+         if (feof(th->fp))
+           {
+             th->eof = 1;
+             return 0;
+           }
+         return -1;
+       }
+      if (th->blk[0] == 0)
+       {
+          th->eof = 1;
+         return 0;
+       }
+      length = parsenum(th->blk + 124, 12);
+      if (length < 0)
+       return -1;
+      type = 0;
+      switch (th->blk[156])
+       {
+       case 'S': case '0':
+         type = 1;     /* file */
+         break;
+       case '1':
+         /* hard link, special length magic... */
+         if (!th->ispax)
+           length = 0;
+         break;
+       case '5':
+         type = 2;     /* dir */
+         break;
+       case '2': case '3': case '4': case '6':
+         length = 0;
+         break;
+       case 'X': case 'x': case 'L':
+         {
+           char *data, *pp;
+           if (length < 1 || length >= 1024 * 1024)
+             return -1;
+           data = pp = solv_malloc(length + 512);
+           for (l = length; l > 0; l -= 512, pp += 512)
+             if (readblock(th->fp, (unsigned char *)pp))
+               {
+                 solv_free(data);
+                 return -1;
+               }
+           data[length] = 0;
+           type = 3;           /* extension */
+           if (th->blk[156] == 'L')
+             {
+               solv_free(th->path);
+               th->path = data;
+               length = 0;
+               break;
+             }
+           pp = data;
+           while (length > 0)
+             {
+               int ll = 0;
+               for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
+                 ll = ll * 10 + (pp[l] - '0');
+               if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
+                 {
+                   solv_free(data);
+                   return -1;
+                 }
+               length -= ll;
+               pp += l + 1;
+               ll -= l + 1;
+               pp[ll - 1] = 0;
+               if (!strncmp(pp, "path=", 5))
+                 {
+                   solv_free(th->path);
+                   th->path = solv_strdup(pp + 5);
+                 }
+               pp += ll;
+             }
+           solv_free(data);
+           th->ispax = 1;
+           length = 0;
+           break;
+         }
+       default:
+         type = 3;     /* extension */
+         break;
+       }
+      if ((type == 1 || type == 2) && !th->path)
+       {
+         char path[157];
+         memcpy(path, th->blk, 156);
+         path[156] = 0;
+         if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
+           {
+             /* POSIX ustar with prefix */
+             char prefix[156];
+             memcpy(prefix, th->blk + 345, 155);
+             prefix[155] = 0;
+             l = strlen(prefix);
+             if (l && prefix[l - 1] == '/')
+               prefix[l - 1] = 0;
+             th->path = solv_dupjoin(prefix, "/", path);
+           }
+         else
+           th->path = solv_dupjoin(path, 0, 0);
+       }
+      if (type == 1 || type == 2)
+       {
+         l = strlen(th->path);
+         if (l && th->path[l - 1] == '/')
+           {
+             if (l > 1)
+               th->path[l - 1] = 0;
+             type = 2;
+           }
+       }
+      if (type != 3)
+       break;
+      while (length > 0)
+       {
+         r = readblock(th->fp, th->blk);
+         if (r)
+           return r;
+         length -= 512;
+       }
+    }
+  th->type = type;
+  th->length = length;
+  return 1;
+}
+
+static Offset
+adddep(Repo *repo, Offset olddeps, char *line)
+{
+  Pool *pool = repo->pool;
+  char *p;
+  Id id;
+
+  while (*line == ' ' || *line == '\t')
+    line++;
+  p = line;
+  while (*p && *p != ' ' && *p != '\t' && *p != '<' && *p != '=' && *p != '>')
+    p++;
+  id = pool_strn2id(pool, line, p - line, 1);
+  while (*p == ' ' || *p == '\t')
+    p++;
+  if (*p == '<' || *p == '=' || *p == '>')
+    {
+      int flags = 0;
+      for (;; p++)
+       {
+         if (*p == '<')
+           flags |= REL_LT;
+         else if (*p == '=')
+           flags |= REL_EQ;
+         else if (*p == '>')
+           flags |= REL_GT;
+         else
+           break;
+       }
+      while (*p == ' ' || *p == '\t')
+        p++;
+      line = p;
+      while (*p && *p != ' ' && *p != '\t')
+       p++;
+      id = pool_rel2id(pool, id, pool_strn2id(pool, line, p - line, 1), flags, 1);
+    }
+  return repo_addid_dep(repo, olddeps, id, 0);
+}
+
+Id
+repo_add_arch_pkg(Repo *repo, const char *fn, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  FILE *fp;
+  struct tarhead th;
+  char line[4096];
+  int ignoreline;
+  Solvable *s;
+  int l, fd;
+  struct stat stb;
+  Chksum *pkgidchk = 0;
+
+  data = repo_add_repodata(repo, flags);
+  if ((fd = open(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, fn) : fn, O_RDONLY, 0)) < 0)
+    {
+      pool_error(pool, -1, "%s: %s", fn, strerror(errno));
+      return 0;
+    }
+  if (fstat(fd, &stb))
+    {
+      pool_error(pool, -1, "%s: fstat: %s", fn, strerror(errno));
+      close(fd);
+      return 0;
+    }
+  if (!(fp = solv_xfopen_fd(fn, fd, "r")))
+    {
+      pool_error(pool, -1, "%s: fdopen failed", fn);
+      close(fd);
+      return 0;
+    }
+  s = 0;
+  inittarhead(&th, fp);
+  while (gettarhead(&th) > 0)
+    {
+      if (th.type != 1 || strcmp(th.path, ".PKGINFO") != 0)
+       {
+          skipentry(&th);
+         continue;
+       }
+      ignoreline = 0;
+      s = pool_id2solvable(pool, repo_add_solvable(repo));
+      if (flags & ARCH_ADD_WITH_PKGID)
+       pkgidchk = solv_chksum_create(REPOKEY_TYPE_MD5);
+      while (getsentry(&th, line, sizeof(line)))
+       {
+         l = strlen(line);
+         if (l == 0)
+           continue;
+         if (pkgidchk)
+           solv_chksum_add(pkgidchk, line, l);
+         if (line[l - 1] != '\n')
+           {
+             ignoreline = 1;
+             continue;
+           }
+         if (ignoreline)
+           {
+             ignoreline = 0;
+             continue;
+           }
+         line[--l] = 0;
+         if (l == 0 || line[0] == '#')
+           continue;
+         if (!strncmp(line, "pkgname = ", 10))
+           s->name = pool_str2id(pool, line + 10, 1);
+         else if (!strncmp(line, "pkgver = ", 9))
+           s->evr = pool_str2id(pool, line + 9, 1);
+         else if (!strncmp(line, "pkgdesc = ", 10))
+           {
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 10);
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line + 10);
+           }
+         else if (!strncmp(line, "url = ", 6))
+           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line + 6);
+         else if (!strncmp(line, "builddate = ", 12))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line + 12, 0, 10));
+         else if (!strncmp(line, "packager = ", 11))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line + 11);
+         else if (!strncmp(line, "size = ", 7))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line + 7, 0, 10));
+         else if (!strncmp(line, "arch = ", 7))
+           s->arch = pool_str2id(pool, line + 7, 1);
+         else if (!strncmp(line, "license = ", 10))
+           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
+         else if (!strncmp(line, "replaces = ", 11))
+           s->obsoletes = adddep(repo, s->obsoletes, line + 11);
+         else if (!strncmp(line, "group = ", 8))
+           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line + 8);
+         else if (!strncmp(line, "depend = ", 9))
+           s->requires = adddep(repo, s->requires, line + 9);
+         else if (!strncmp(line, "optdepend = ", 12))
+           {
+             char *p = strchr(line, ':');
+             if (p)
+               *p = 0;
+             s->suggests = adddep(repo, s->suggests, line + 12);
+           }
+         else if (!strncmp(line, "conflict = ", 11))
+           s->conflicts = adddep(repo, s->conflicts, line + 11);
+         else if (!strncmp(line, "provides = ", 11))
+           s->provides = adddep(repo, s->provides, line + 11);
+       }
+      break;
+    }
+  freetarhead(&th);
+  fclose(fp);
+  if (!s)
+    {
+      pool_error(pool, -1, "%s: not an arch package", fn);
+      if (pkgidchk)
+       solv_chksum_free(pkgidchk, 0);
+      return 0;
+    }
+  if (s && !s->name)
+    {
+      pool_error(pool, -1, "%s: package has no name", fn);
+      s = solvable_free(s, 1);
+    }
+  if (s)
+    {
+      if (!s->arch)
+       s->arch = ARCH_ANY;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      if (!(flags & REPO_NO_LOCATION))
+       repodata_set_location(data, s - pool->solvables, 0, 0, fn);
+      if (S_ISREG(stb.st_mode))
+        repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
+      if (pkgidchk)
+       {
+         unsigned char pkgid[16];
+         solv_chksum_free(pkgidchk, pkgid);
+         repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
+         pkgidchk = 0;
+       }
+    }
+  if (pkgidchk)
+    solv_chksum_free(pkgidchk, 0);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return s ? s - pool->solvables : 0;
+}
+
+static char *getsentrynl(struct tarhead *th, char *s, int size)
+{
+  int l;
+  if (!getsentry(th, s, size))
+    {
+      *s = 0;  /* eof */
+      return 0;
+    }
+  l = strlen(s);
+  if (!l)
+    return 0;
+  if (l && s[l - 1] == '\n')
+    {
+      s[l - 1] = 0;
+      return s;
+    }
+  while (getsentry(th, s, size))
+    {
+      l = strlen(s);
+      if (!l || s[l - 1] == '\n')
+       return 0;
+    }
+  *s = 0;      /* eof */
+  return 0;
+}
+
+static Hashtable
+joinhash_init(Repo *repo, Hashval *hmp)
+{
+  Hashval hm = mkmask(repo->nsolvables);
+  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
+  Hashval h, hh;
+  Solvable *s;
+  int i;
+
+  FOR_REPO_SOLVABLES(repo, i, s)
+    {
+      hh = HASHCHAIN_START;
+      h = s->name & hm;
+      while (ht[h])
+        h = HASHCHAIN_NEXT(h, hh, hm);
+      ht[h] = i;
+    }
+  *hmp = hm;
+  return ht;
+}
+
+static Solvable *
+joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn)
+{
+  const char *p;
+  Id name, evr;
+  Hashval h, hh;
+
+  if ((p = strrchr(fn, '/')) != 0)
+    fn = p + 1;
+  /* here we assume that the dirname is name-evr */
+  if (!*fn)
+    return 0;
+  for (p = fn + strlen(fn) - 1; p > fn; p--)
+    {
+      while (p > fn && *p != '-')
+       p--;
+      if (p == fn)
+       return 0;
+      name = pool_strn2id(repo->pool, fn, p - fn, 0);
+      if (!name)
+       continue;
+      evr = pool_str2id(repo->pool, p + 1, 0);
+      if (!evr)
+       continue;
+      /* found valid name/evr combination, check hash */
+      hh = HASHCHAIN_START;
+      h = name & hm;
+      while (ht[h])
+       {
+         Solvable *s = repo->pool->solvables + ht[h];
+         if (s->name == name && s->evr == evr)
+           return s;
+         h = HASHCHAIN_NEXT(h, hh, hm);
+       }
+    }
+  return 0;
+}
+
+static void
+adddata(Repodata *data, Solvable *s, struct tarhead *th)
+{
+  Repo *repo = data->repo;
+  Pool *pool = repo->pool;
+  char line[4096];
+  int l;
+  int havesha256 = 0;
+
+  while (getsentry(th, line, sizeof(line)))
+    {
+      l = strlen(line);
+      if (l == 0 || line[l - 1] != '\n')
+       continue;
+      line[--l] = 0;
+      if (l <= 2 || line[0] != '%' || line[l - 1] != '%')
+       continue;
+      if (!strcmp(line, "%FILENAME%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_set_location(data, s - pool->solvables, 0, 0, line);
+       }
+      else if (!strcmp(line, "%NAME%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           s->name = pool_str2id(pool, line, 1);
+       }
+      else if (!strcmp(line, "%VERSION%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           s->evr = pool_str2id(pool, line, 1);
+       }
+      else if (!strcmp(line, "%DESC%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           {
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line);
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line);
+           }
+       }
+      else if (!strcmp(line, "%GROUPS%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line);
+       }
+      else if (!strcmp(line, "%CSIZE%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(line, 0, 10));
+       }
+      else if (!strcmp(line, "%ISIZE%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line, 0, 10));
+       }
+      else if (!strcmp(line, "%MD5SUM%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)) && !havesha256)
+           repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_MD5, line);
+       }
+      else if (!strcmp(line, "%SHA256SUM%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           {
+             repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, line);
+             havesha256 = 1;
+           }
+       }
+      else if (!strcmp(line, "%URL%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line);
+       }
+      else if (!strcmp(line, "%LICENSE%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line);
+       }
+      else if (!strcmp(line, "%ARCH%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           s->arch = pool_str2id(pool, line, 1);
+       }
+      else if (!strcmp(line, "%BUILDDATE%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line, 0, 10));
+       }
+      else if (!strcmp(line, "%PACKAGER%"))
+       {
+         if (getsentrynl(th, line, sizeof(line)))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line);
+       }
+      else if (!strcmp(line, "%REPLACES%"))
+       {
+         while (getsentrynl(th, line, sizeof(line)) && *line)
+           s->obsoletes = adddep(repo, s->obsoletes, line);
+       }
+      else if (!strcmp(line, "%DEPENDS%"))
+       {
+         while (getsentrynl(th, line, sizeof(line)) && *line)
+           s->requires = adddep(repo, s->requires, line);
+       }
+      else if (!strcmp(line, "%CONFLICTS%"))
+       {
+         while (getsentrynl(th, line, sizeof(line)) && *line)
+           s->conflicts = adddep(repo, s->conflicts, line);
+       }
+      else if (!strcmp(line, "%PROVIDES%"))
+       {
+         while (getsentrynl(th, line, sizeof(line)) && *line)
+           s->provides = adddep(repo, s->provides, line);
+       }
+      else if (!strcmp(line, "%OPTDEPENDS%"))
+       {
+         while (getsentrynl(th, line, sizeof(line)) && *line)
+           {
+             char *p = strchr(line, ':');
+             if (p && p > line)
+               *p = 0;
+             s->suggests = adddep(repo, s->suggests, line);
+           }
+       }
+      else if (!strcmp(line, "%FILES%"))
+       {
+         while (getsentrynl(th, line, sizeof(line)) && *line)
+           {
+             char *p;
+             Id id;
+             l = strlen(line);
+             if (l > 1 && line[l - 1] == '/')
+               line[--l] = 0;  /* remove trailing slashes */
+             if ((p = strrchr(line , '/')) != 0)
+               {
+                 *p++ = 0;
+                 if (line[0] != '/')   /* anchor */
+                   {
+                     char tmp = *p;
+                     memmove(line + 1, line, p - 1 - line);
+                     *line = '/';
+                     *p = 0;
+                     id = repodata_str2dir(data, line, 1);
+                     *p = tmp;
+                   }
+                 else
+                   id = repodata_str2dir(data, line, 1);
+               }
+             else
+               {
+                 p = line;
+                 id = 0;
+               }
+             if (!id)
+               id = repodata_str2dir(data, "/", 1);
+             repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, id, p);
+           }
+       }
+      while (*line)
+       getsentrynl(th, line, sizeof(line));
+    }
+}
+
+static void
+finishsolvable(Repo *repo, Solvable *s)
+{
+  Pool *pool = repo->pool;
+  if (!s)
+    return;
+  if (!s->name)
+    {
+      solvable_free(s, 1);
+      return;
+    }
+  if (!s->arch)
+    s->arch = ARCH_ANY;
+  if (!s->evr)
+    s->evr = ID_EMPTY;
+  s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+}
+
+int
+repo_add_arch_repo(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  struct tarhead th;
+  char *lastdn = 0;
+  int lastdnlen = 0;
+  Solvable *s = 0;
+  Hashtable joinhash = 0;
+  Hashval joinhashmask = 0;
+
+  data = repo_add_repodata(repo, flags);
+
+  if (flags & REPO_EXTEND_SOLVABLES)
+    joinhash = joinhash_init(repo, &joinhashmask);
+
+  inittarhead(&th, fp);
+  while (gettarhead(&th) > 0)
+    {
+      char *bn;
+      if (th.type != 1)
+       {
+          skipentry(&th);
+         continue;
+       }
+      bn = strrchr(th.path, '/');
+      if (!bn || (strcmp(bn + 1, "desc") != 0 && strcmp(bn + 1, "depends") != 0 && strcmp(bn + 1, "files") != 0))
+       {
+          skipentry(&th);
+         continue;
+       }
+      if ((flags & REPO_EXTEND_SOLVABLES) != 0 && (!strcmp(bn + 1, "desc") || !strcmp(bn + 1, "depends")))
+       {
+          skipentry(&th);
+         continue;     /* skip those when we're extending */
+       }
+      if (!lastdn || (bn - th.path) != lastdnlen || strncmp(lastdn, th.path, lastdnlen) != 0)
+       {
+         finishsolvable(repo, s);
+         solv_free(lastdn);
+         lastdn = solv_strdup(th.path);
+         lastdnlen = bn - th.path;
+         lastdn[lastdnlen] = 0;
+         if (flags & REPO_EXTEND_SOLVABLES)
+           {
+             s = joinhash_lookup(repo, joinhash, joinhashmask, lastdn);
+             if (!s)
+               {
+                 skipentry(&th);
+                 continue;
+               }
+           }
+         else
+           s = pool_id2solvable(pool, repo_add_solvable(repo));
+       }
+      adddata(data, s, &th);
+    }
+  finishsolvable(repo, s);
+  solv_free(joinhash);
+  solv_free(lastdn);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+int
+repo_add_arch_local(Repo *repo, const char *dir, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  DIR *dp;
+  struct dirent *de;
+  char *entrydir, *file;
+  FILE *fp;
+  Solvable *s;
+
+  data = repo_add_repodata(repo, flags);
+
+  if (flags & REPO_USE_ROOTDIR)
+    dir = pool_prepend_rootdir(pool, dir);
+  dp = opendir(dir);
+  if (dp)
+    {
+      while ((de = readdir(dp)) != 0)
+       {
+         if (!de->d_name[0] || de->d_name[0] == '.')
+           continue;
+         entrydir = solv_dupjoin(dir, "/", de->d_name);
+         file = pool_tmpjoin(repo->pool, entrydir, "/desc", 0);
+         s = 0;
+         if ((fp = fopen(file, "r")) != 0)
+           {
+             struct tarhead th;
+             inittarhead(&th, fp);
+             s = pool_id2solvable(pool, repo_add_solvable(repo));
+             adddata(data, s, &th);
+             freetarhead(&th);
+             fclose(fp);
+             file = pool_tmpjoin(repo->pool, entrydir, "/files", 0);
+             if ((fp = fopen(file, "r")) != 0)
+               {
+                 inittarhead(&th, fp);
+                 adddata(data, s, &th);
+                 freetarhead(&th);
+                 fclose(fp);
+               }
+           }
+         solv_free(entrydir);
+       }
+      closedir(dp);
+    }
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  if (flags & REPO_USE_ROOTDIR)
+    solv_free((char *)dir);
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/ext/repo_arch.h b/libsolv-0.7.2/ext/repo_arch.h
new file mode 100644 (file)
index 0000000..78a2f32
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define ARCH_ADD_WITH_PKGID  (1 << 8)
+
+extern Id repo_add_arch_pkg(Repo *repo, const char *fn, int flags);
+extern Id repo_add_arch_repo(Repo *repo, FILE *fp, int flags);
+extern Id repo_add_arch_local(Repo *repo, const char *dir, int flags);
+
diff --git a/libsolv-0.7.2/ext/repo_autopattern.c b/libsolv-0.7.2/ext/repo_autopattern.c
new file mode 100644 (file)
index 0000000..4c09e79
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "repo_autopattern.h"
+
+static void
+unescape(char *p)
+{
+  char *q = p;
+  while (*p)
+    {
+      if (*p == '%' && p[1] && p[2])
+       {
+         int d1 = p[1], d2 = p[2];
+         if (d1 >= '0' && d1 <= '9')
+           d1 -= '0';
+         else if (d1 >= 'a' && d1 <= 'f')
+           d1 -= 'a' - 10;
+         else if (d1 >= 'A' && d1 <= 'F')
+           d1 -= 'A' - 10;
+         else
+           d1 = -1;
+         if (d2 >= '0' && d2 <= '9')
+           d2 -= '0';
+         else if (d2 >= 'a' && d2 <= 'f')
+           d2 -= 'a' - 10;
+         else if (d2 >= 'A' && d2 <= 'F')
+           d2 -= 'A' - 10;
+         else
+           d2 = -1;
+         if (d1 != -1 && d2 != -1)
+           {
+             *q++ = d1 << 4 | d2;
+             p += 3;
+             continue;
+           }
+       }
+      *q++ = *p++;
+    }
+  *q = 0;
+}
+
+static time_t
+datestr2timestamp(const char *date)
+{
+  const char *p; 
+  struct tm tm; 
+
+  if (!date || !*date)
+    return 0;
+  for (p = date; *p >= '0' && *p <= '9'; p++)
+    ;   
+  if (!*p)
+    return atoi(date);
+  memset(&tm, 0, sizeof(tm));
+  p = strptime(date, "%F%T", &tm);
+  if (!p)
+    {   
+      memset(&tm, 0, sizeof(tm));
+      p = strptime(date, "%F", &tm);
+      if (!p || *p) 
+        return 0;
+    }   
+  return timegm(&tm);
+}
+
+/* we just look at the repodata keys and do not iterate
+ * over the solvables, because iterating would mean a
+ * load of stub repodata areas */
+static void
+find_langkeys(Repo *repo, Id keyname, Queue *q)
+{
+  Pool *pool = repo->pool;
+  int rid;
+  int i;
+  const char *keyname_str;
+  size_t keyname_len;
+
+  keyname_str = pool_id2str(pool, keyname);
+  keyname_len = strlen(keyname_str);
+  queue_empty(q);
+  for (rid = 1; rid < repo->nrepodata; rid++)
+    {
+      Repodata *data = repo_id2repodata(repo, rid);
+      for (i = 1; i < data->nkeys; i++)
+       {
+         const char *s = pool_id2str(pool, data->keys[i].name);
+         if (!strncmp(s, keyname_str, keyname_len) && s[keyname_len] == ':')
+           queue_pushunique(q, data->keys[i].name);
+       }
+    }
+}
+
+int
+repo_add_autopattern(Repo *repo, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data = 0;
+  Solvable *s, *s2;
+  Queue patq, patq2;
+  Queue prdq, prdq2;
+  Id p;
+  Id pattern_id, product_id;
+  Id autopattern_id = 0, autoproduct_id = 0;
+  int i, j;
+  Queue categorykeys;
+
+  queue_init(&patq);
+  queue_init(&patq2);
+  queue_init(&prdq);
+  queue_init(&prdq2);
+
+  if (repo == pool->installed)
+    flags |= ADD_NO_AUTOPRODUCTS;      /* no auto products for installed repos */
+
+  pattern_id = pool_str2id(pool, "pattern()", 9);
+  product_id = pool_str2id(pool, "product()", 9);
+
+  queue_init(&categorykeys);
+  FOR_REPO_SOLVABLES(repo, p, s)
+    {
+      const char *n = pool_id2str(pool, s->name);
+      if (*n == 'p')
+       {
+         if (!strncmp("pattern:", n, 8))
+           {
+             queue_push(&patq, p);
+             continue;
+           }
+         else if (!strncmp("product:", n, 8))
+           {
+             queue_push(&prdq, p);
+             continue;
+           }
+       }
+      if (s->provides)
+       {
+         Id prv, *prvp = repo->idarraydata + s->provides;
+         while ((prv = *prvp++) != 0)            /* go through all provides */
+           if (ISRELDEP(prv))
+             {
+               Reldep *rd = GETRELDEP(pool, prv);
+               if (rd->flags != REL_EQ)
+                 continue;
+               if (rd->name == pattern_id)
+                 {
+                   const char *evrstr = pool_id2str(pool, rd->evr);
+                   if (evrstr[0] == '.')       /* hack to allow provides that do not create a pattern */
+                     continue;
+                   if (patq2.count && patq2.elements[patq2.count - 2] == p)
+                     {
+                       /* hmm, two provides. choose by evrstr */
+                       if (strcmp(evrstr, pool_id2str(pool, patq2.elements[patq2.count - 1])) >= 0)
+                         continue;
+                       patq2.count -= 2;
+                     }
+                   queue_push2(&patq2, p, rd->evr);
+                 }
+               if (rd->name == product_id)
+                 {
+                   const char *evrstr = pool_id2str(pool, rd->evr);
+                   if (prdq2.count && prdq2.elements[prdq2.count - 2] == p)
+                     {
+                       /* hmm, two provides. choose by evrstr */
+                       if (strcmp(evrstr, pool_id2str(pool, prdq2.elements[prdq2.count - 1])) >= 0)
+                         continue;
+                       prdq2.count -= 2;
+                     }
+                   queue_push2(&prdq2, p, rd->evr);
+                 }
+             }
+       }
+    }
+  if (patq2.count)
+    {
+      find_langkeys(repo, SOLVABLE_CATEGORY, &categorykeys);
+      queue_unshift(&categorykeys, SOLVABLE_CATEGORY);
+    }
+  for (i = 0; i < patq2.count; i += 2)
+    {
+      const char *pn = 0;
+      char *newname;
+      Id name, prv, *prvp;
+      const char *str;
+      unsigned long long num;
+
+      s = pool->solvables + patq2.elements[i];
+      /* construct new name */
+      newname = pool_tmpjoin(pool, "pattern:", pool_id2str(pool, patq2.elements[i + 1]), 0);
+      unescape(newname);
+      name = pool_str2id(pool, newname, 0);
+      if (name)
+       {
+         /* check if we already have that pattern */
+         for (j = 0; j < patq.count; j++)
+           {
+             s2 = pool->solvables + patq.elements[j];
+             if (s2->name == name && s2->arch == s->arch && s2->evr == s->evr)
+               break;
+           }
+         if (j < patq.count)
+           continue;   /* yes, do not add again */
+       }
+      /* new pattern */
+      if (!name)
+        name = pool_str2id(pool, newname, 1);
+      if (!data)
+       {
+         repo_internalize(repo);       /* to make that the lookups work */
+         data = repo_add_repodata(repo, flags);
+       }
+      s2 = pool_id2solvable(pool, repo_add_solvable(repo));
+      s = pool->solvables + patq2.elements[i]; /* re-calc pointer */
+      s2->name = name;
+      s2->arch = s->arch;
+      s2->evr = s->evr;
+      s2->vendor = s->vendor;
+      /* add link requires */
+      s2->requires = repo_addid_dep(repo, s2->requires, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1) , 0);
+      /* add autopattern provides */
+      if (!autopattern_id)
+       autopattern_id = pool_str2id(pool, "autopattern()", 1);
+      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autopattern_id, s->name, REL_EQ, 1), 0);
+      /* add self provides */
+      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
+      if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
+       repodata_set_num(data, s2 - pool->solvables, SOLVABLE_INSTALLTIME, num);
+      if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
+       repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
+      if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
+       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
+      if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
+       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
+      /* fill in stuff from provides */
+      prvp = repo->idarraydata + s->provides;
+      while ((prv = *prvp++) != 0)            /* go through all provides */
+       {
+         Id evr = 0;
+         if (ISRELDEP(prv))
+           {
+             Reldep *rd = GETRELDEP(pool, prv);
+             if (rd->flags != REL_EQ)
+               continue;
+             prv = rd->name;
+             evr = rd->evr;
+           }
+         pn = pool_id2str(pool, prv);
+         if (strncmp("pattern-", pn, 8) != 0)
+           continue;
+         newname = 0;
+         if (evr)
+           {
+             newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
+             unescape(newname);
+           }
+         if (!strncmp(pn, "pattern-category(", 17) && evr)
+           {
+             char lang[9];
+             int l = strlen(pn);
+             Id langtag;
+             if (l > 17 + 9 || pn[l - 1] != ')')
+               continue;
+              strncpy(lang, pn + 17, l - 17 - 1);
+             lang[l - 17 - 1] = 0;
+             langtag = SOLVABLE_CATEGORY;
+             if (*lang && strcmp(lang, "en") != 0)
+               langtag = pool_id2langid(pool, SOLVABLE_CATEGORY, lang, 1);
+             if (newname[solv_validutf8(newname)] == 0)
+               repodata_set_str(data, s2 - pool->solvables, langtag, newname);
+             else
+               {
+                 char *ustr = solv_latin1toutf8(newname);
+                 repodata_set_str(data, s2 - pool->solvables, langtag, ustr);
+                 solv_free(ustr);
+               }
+           }
+         else if (!strcmp(pn, "pattern-includes()") && evr)
+           repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_INCLUDES, pool_tmpjoin(pool, "pattern:", newname, 0));
+         else if (!strcmp(pn, "pattern-extends()") && evr)
+           repodata_add_poolstr_array(data, s2 - pool->solvables, SOLVABLE_EXTENDS, pool_tmpjoin(pool, "pattern:", newname, 0));
+         else if (!strcmp(pn, "pattern-icon()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ICON, newname);
+         else if (!strcmp(pn, "pattern-order()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ORDER, newname);
+         else if (!strcmp(pn, "pattern-visible()"))
+           {
+             if (!evr)
+               repodata_set_void(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE);
+             else
+               repodata_set_str(data, s2 - pool->solvables, SOLVABLE_ISVISIBLE, newname);
+           }
+       }
+      /* also try to copy the pattern category from the solvable */
+      for (j = 0; j < categorykeys.count; j++)
+       {
+         Id catkey = categorykeys.elements[j];
+         if ((str = solvable_lookup_str(s, catkey)) != 0)
+           repodata_set_str(data, s2 - pool->solvables, catkey, str);
+       }
+    }
+  queue_free(&patq);
+  queue_free(&patq2);
+  queue_free(&categorykeys);
+
+  if ((flags & ADD_NO_AUTOPRODUCTS) != 0)
+    queue_empty(&prdq2);
+
+  for (i = 0; i < prdq2.count; i += 2)
+    {
+      const char *pn = 0;
+      char *newname;
+      Id name, evr = 0, prv, *prvp;
+      const char *str;
+      unsigned long long num;
+
+      s = pool->solvables + prdq2.elements[i];
+      /* construct new name */
+      newname = pool_tmpjoin(pool, "product(", pool_id2str(pool, prdq2.elements[i + 1]), ")");
+      unescape(newname);
+      name = pool_str2id(pool, newname, 0);
+      if (!name)
+       continue;       /* must have it in provides! */
+      prvp = repo->idarraydata + s->provides;
+      while ((prv = *prvp++) != 0)            /* go through all provides */
+       {
+         if (ISRELDEP(prv))
+           {
+             Reldep *rd = GETRELDEP(pool, prv);
+             if (rd->name == name && rd->flags == REL_EQ)
+               {
+                 evr = rd->evr;
+                 break;
+               }
+           }
+       }
+      if (!prv)
+       continue;       /* not found in provides */
+      newname = pool_tmpjoin(pool, "product:", pool_id2str(pool, prdq2.elements[i + 1]), 0);
+      unescape(newname);
+      name = pool_str2id(pool, newname, 0);
+      if (name)
+       {
+         /* check if we already have that product */
+         for (j = 0; j < prdq.count; j++)
+           {
+             s2 = pool->solvables + prdq.elements[j];
+             if (s2->name == name && s2->arch == s->arch && s2->evr == evr)
+               break;
+           }
+         if (j < prdq.count)
+           continue;   /* yes, do not add again */
+       }
+      /* new product */
+      if (!name)
+        name = pool_str2id(pool, newname, 1);
+      if (!data)
+       {
+         repo_internalize(repo);       /* to make that the lookups work */
+         data = repo_add_repodata(repo, flags);
+       }
+      if ((num = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0)) != 0)
+       continue;               /* eek, not for installed packages, please! */
+      s2 = pool_id2solvable(pool, repo_add_solvable(repo));
+      s = pool->solvables + prdq2.elements[i]; /* re-calc pointer */
+      s2->name = name;
+      s2->arch = s->arch;
+      s2->evr = evr;
+      s2->vendor = s->vendor;
+      /* add link requires */
+      s2->requires = repo_addid_dep(repo, s2->requires, prv, 0);
+      if (!autoproduct_id)
+       autoproduct_id = pool_str2id(pool, "autoproduct()", 1);
+      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, autoproduct_id, s->name, REL_EQ, 1), 0);
+      /* add self provides */
+      s2->provides = repo_addid_dep(repo, s2->provides, pool_rel2id(pool, s2->name, s2->evr, REL_EQ, 1), 0);
+      if ((num = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0)) != 0)
+       repodata_set_num(data, s2 - pool->solvables, SOLVABLE_BUILDTIME, num);
+      if ((str = solvable_lookup_str(s, SOLVABLE_SUMMARY)) != 0)
+       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_SUMMARY, str);
+      if ((str = solvable_lookup_str(s, SOLVABLE_DESCRIPTION)) != 0)
+       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DESCRIPTION, str);
+      if ((str = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION)) != 0)
+       repodata_set_str(data, s2 - pool->solvables, SOLVABLE_DISTRIBUTION, str);
+      /* fill in stuff from provides */
+      prvp = repo->idarraydata + s->provides;
+      while ((prv = *prvp++) != 0)            /* go through all provides */
+       {
+         Id evr = 0;
+         if (ISRELDEP(prv))
+           {
+             Reldep *rd = GETRELDEP(pool, prv);
+             if (rd->flags != REL_EQ)
+               continue;
+             prv = rd->name;
+             evr = rd->evr;
+           }
+         pn = pool_id2str(pool, prv);
+         if (strncmp("product-", pn, 8) != 0)
+           continue;
+         newname = 0;
+         if (evr)
+           {
+             newname = pool_tmpjoin(pool, pool_id2str(pool, evr), 0, 0);
+             unescape(newname);
+           }
+         if (!strcmp(pn, "product-label()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, PRODUCT_SHORTLABEL, newname);
+         else if (!strcmp(pn, "product-register-target()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_TARGET, newname);
+         else if (!strcmp(pn, "product-register-flavor()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, PRODUCT_REGISTER_FLAVOR, newname);
+         else if (!strcmp(pn, "product-type()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, PRODUCT_TYPE, newname);
+         else if (!strcmp(pn, "product-cpeid()") && evr)
+           repodata_set_str(data, s2 - pool->solvables, SOLVABLE_CPEID, newname);
+         else if (!strcmp(pn, "product-flags()") && evr)
+           repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_FLAGS, newname);
+         else if (!strcmp(pn, "product-updates-repoid()") && evr)
+           {
+             Id h = repodata_new_handle(data);
+             repodata_set_str(data, h, PRODUCT_UPDATES_REPOID, newname);
+             repodata_add_flexarray(data, s2 - pool->solvables, PRODUCT_UPDATES, h);
+           }
+         else if (!strcmp(pn, "product-endoflife()"))
+           {
+             /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */
+             repodata_set_num(data, s2 - pool->solvables, PRODUCT_ENDOFLIFE,(evr ? datestr2timestamp(newname) : 0) );
+           }
+         else if (!strncmp(pn, "product-url(", 12) && evr && pn[12] && pn[13] && strlen(pn + 12) < 32)
+           {
+             char type[34];
+             strcpy(type, pn + 12);
+             type[strlen(type) - 1] = 0;       /* closing ) */
+             repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL_TYPE, type);
+             repodata_add_poolstr_array(data, s2 - pool->solvables, PRODUCT_URL, newname);
+           }
+       }
+    }
+  queue_free(&prdq);
+  queue_free(&prdq2);
+
+  if (data && !(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  else if (!data && !(flags & REPO_NO_INTERNALIZE))
+    repo_internalize(repo);
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/ext/repo_autopattern.h b/libsolv-0.7.2/ext/repo_autopattern.h
new file mode 100644 (file)
index 0000000..b9cbada
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define ADD_NO_AUTOPRODUCTS    (1 << 8)
+
+extern int repo_add_autopattern(Repo *repo, int flags);
diff --git a/libsolv-0.7.2/ext/repo_comps.c b/libsolv-0.7.2/ext/repo_comps.c
new file mode 100644 (file)
index 0000000..9400e1e
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * repo_comps.c
+ *
+ * Parses RedHat comps format
+ *
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "solv_xmlparser.h"
+#define DISABLE_SPLIT
+#include "tools_util.h"
+#include "repo_comps.h"
+
+/*
+ * TODO:
+ *
+ * what's the difference between group/category?
+ * handle "default" and "langonly".
+ *
+ * maybe handle REL_COND in solver recommends handling?
+ */
+
+enum state {
+  STATE_START,
+  STATE_COMPS,
+  STATE_GROUP,
+  STATE_ID,
+  STATE_NAME,
+  STATE_DESCRIPTION,
+  STATE_DISPLAY_ORDER,
+  STATE_DEFAULT,
+  STATE_LANGONLY,
+  STATE_LANG_ONLY,
+  STATE_USERVISIBLE,
+  STATE_PACKAGELIST,
+  STATE_PACKAGEREQ,
+  STATE_CATEGORY,
+  STATE_CID,
+  STATE_CNAME,
+  STATE_CDESCRIPTION,
+  STATE_CDISPLAY_ORDER,
+  STATE_GROUPLIST,
+  STATE_GROUPID,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START,       "comps",         STATE_COMPS,         0 },
+  { STATE_COMPS,       "group",         STATE_GROUP,         0 },
+  { STATE_COMPS,       "category",      STATE_CATEGORY,      0 },
+  { STATE_GROUP,       "id",            STATE_ID,            1 },
+  { STATE_GROUP,       "name",          STATE_NAME,          1 },
+  { STATE_GROUP,       "description",   STATE_DESCRIPTION,   1 },
+  { STATE_GROUP,       "uservisible",   STATE_USERVISIBLE,   1 },
+  { STATE_GROUP,       "display_order", STATE_DISPLAY_ORDER, 1 },
+  { STATE_GROUP,       "default",       STATE_DEFAULT,       1 },
+  { STATE_GROUP,       "langonly",      STATE_LANGONLY,      1 },
+  { STATE_GROUP,       "lang_only",     STATE_LANG_ONLY,     1 },
+  { STATE_GROUP,       "packagelist",   STATE_PACKAGELIST,   0 },
+  { STATE_PACKAGELIST, "packagereq",    STATE_PACKAGEREQ,    1 },
+  { STATE_CATEGORY,    "id",            STATE_ID,            1 },
+  { STATE_CATEGORY,    "name",          STATE_NAME,          1 },
+  { STATE_CATEGORY,    "description",   STATE_DESCRIPTION,   1 },
+  { STATE_CATEGORY ,   "grouplist",     STATE_GROUPLIST,     0 },
+  { STATE_CATEGORY ,   "display_order", STATE_DISPLAY_ORDER, 1 },
+  { STATE_GROUPLIST,   "groupid",       STATE_GROUPID,       1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  const char *filename;
+  const char *basename;
+
+  struct solv_xmlparser xmlp;
+  struct joindata jd;
+
+  const char *tmplang;
+  Id reqtype;
+  Id condreq;
+
+  Solvable *solvable;
+  const char *kind;
+  Id handle;
+};
+
+
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+
+  switch(state)
+    {
+    case STATE_GROUP:
+    case STATE_CATEGORY:
+      s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+      pd->handle = s - pool->solvables;
+      pd->kind = state == STATE_GROUP ? "group" : "category";
+      break;
+
+    case STATE_NAME:
+    case STATE_CNAME:
+    case STATE_DESCRIPTION:
+    case STATE_CDESCRIPTION:
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("xml:lang", atts));
+      break;
+
+    case STATE_PACKAGEREQ:
+      {
+       const char *type = solv_xmlparser_find_attr("type", atts);
+       pd->condreq = 0;
+       pd->reqtype = SOLVABLE_RECOMMENDS;
+       if (type && !strcmp(type, "conditional"))
+         {
+           const char *requires = solv_xmlparser_find_attr("requires", atts);
+           if (requires && *requires)
+             pd->condreq = pool_str2id(pool, requires, 1);
+         }
+       else if (type && !strcmp(type, "mandatory"))
+         pd->reqtype = SOLVABLE_REQUIRES;
+       else if (type && !strcmp(type, "optional"))
+         pd->reqtype = SOLVABLE_SUGGESTS;
+       break;
+      }
+
+    default:
+      break;
+    }
+}
+
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Solvable *s = pd->solvable;
+  Id id;
+
+  switch (state)
+    {
+    case STATE_GROUP:
+    case STATE_CATEGORY:
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
+      pd->solvable = 0;
+      break;
+
+    case STATE_ID:
+      s->name = pool_str2id(pd->pool, join2(&pd->jd, pd->kind, ":", content), 1);
+      break;
+
+    case STATE_NAME:
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
+      break;
+
+    case STATE_DESCRIPTION:
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
+      break;
+
+    case STATE_PACKAGEREQ:
+      id = pool_str2id(pd->pool, content, 1);
+      if (pd->condreq)
+       id = pool_rel2id(pd->pool, id, pd->condreq, REL_COND, 1);
+      repo_add_idarray(pd->repo, pd->handle, pd->reqtype, id);
+      break;
+
+    case STATE_GROUPID:
+      id = pool_str2id(pd->pool, join2(&pd->jd, "group", ":", content), 1);
+      s->requires = repo_addid_dep(pd->repo, s->requires, id, 0);
+      break;
+
+    case STATE_USERVISIBLE:
+      repodata_set_void(pd->data, pd->handle, SOLVABLE_ISVISIBLE);
+      break;
+
+    case STATE_DISPLAY_ORDER:
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_ORDER, content);
+      break;
+
+    default:
+      break;
+    }
+}
+
+int
+repo_add_comps(Repo *repo, FILE *fp, int flags)
+{
+  Repodata *data;
+  struct parsedata pd;
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pool_debug(pd.pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+  join_freemem(&pd.jd);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/ext/repo_comps.h b/libsolv-0.7.2/ext/repo_comps.h
new file mode 100644 (file)
index 0000000..8998b07
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_comps(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.7.2/ext/repo_content.c b/libsolv-0.7.2/ext/repo_content.c
new file mode 100644 (file)
index 0000000..f361900
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * repo_content.c
+ *
+ * Parses 'content' file into .solv
+ * A 'content' file is the repomd.xml of the susetags format
+ *
+ * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata/content for a description
+ * of the syntax
+ *
+ *
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "chksum.h"
+#include "repo_content.h"
+#define DISABLE_SPLIT
+#define DISABLE_JOIN2
+#include "tools_util.h"
+
+/* split off a word, return null terminated pointer to it.
+ * return NULL if there is no word left. */
+static char *
+splitword(char **lp)
+{
+  char *w, *l = *lp;
+
+  while (*l == ' ' || *l == '\t')
+    l++;
+  w = *l ? l : 0;
+  while (*l && *l != ' ' && *l != '\t')
+    l++;
+  if (*l)
+    *l++ = 0;          /* terminate word */
+  while (*l == ' ' || *l == '\t')
+    l++;               /* convenience: advance to next word */
+  *lp = l;
+  return w;
+}
+
+struct parsedata {
+  Repo *repo;
+  char *tmp;
+  int tmpl;
+
+  const char *tmpvers;
+  const char *tmprel;
+};
+
+/*
+ * dependency relations
+ */
+
+static char *flagtab[] = {
+  ">",
+  "=",
+  ">=",
+  "<",
+  "!=",
+  "<="
+};
+
+
+/*
+ * join up to three strings into one
+ */
+
+static char *
+join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
+{
+  int l = 1;
+  char *p;
+
+  if (s1)
+    l += strlen(s1);
+  if (s2)
+    l += strlen(s2);
+  if (s3)
+    l += strlen(s3);
+  if (l > pd->tmpl)
+    {
+      pd->tmpl = l + 256;
+      pd->tmp = solv_realloc(pd->tmp, pd->tmpl);
+    }
+  p = pd->tmp;
+  if (s1)
+    {
+      strcpy(p, s1);
+      p += strlen(s1);
+    }
+  if (s2)
+    {
+      strcpy(p, s2);
+      p += strlen(s2);
+    }
+  if (s3)
+    {
+      strcpy(p, s3);
+      p += strlen(s3);
+    }
+  *p = 0;
+  return pd->tmp;
+}
+
+
+/*
+ * add dependency to pool
+ * OBSOLETES product:SUSE_LINUX product:openSUSE < 11.0 package:openSUSE < 11.0
+ */
+
+static unsigned int
+adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
+{
+  char *name;
+  Id id;
+
+  while ((name = splitword(&line)) != 0)
+    {
+      /* Hack, as the content file adds 'package:' for package
+         dependencies sometimes.  */
+      if (!strncmp (name, "package:", 8))
+        name += 8;
+      id = pool_str2id(pool, name, 1);
+      if (*line == '<' || *line == '>' || *line == '=')        /* rel follows */
+       {
+         char *rel = splitword(&line);
+          char *evr = splitword(&line);
+         int flags;
+
+         if (!rel || !evr)
+           {
+             pool_debug(pool, SOLV_ERROR, "repo_content: bad relation '%s %s'\n", name, rel);
+             continue;
+           }
+         for (flags = 0; flags < 6; flags++)
+           if (!strcmp(rel, flagtab[flags]))
+             break;
+         if (flags == 6)
+           {
+             pool_debug(pool, SOLV_ERROR, "repo_content: unknown relation '%s'\n", rel);
+             continue;
+           }
+         id = pool_rel2id(pool, id, pool_str2id(pool, evr, 1), flags + 1, 1);
+       }
+      olddeps = repo_addid_dep(pd->repo, olddeps, id, marker);
+    }
+  return olddeps;
+}
+
+
+/*
+ * split value and add to pool
+ */
+
+static void
+add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
+{
+  char *str;
+
+  while ((str = splitword(&value)) != 0)
+    repodata_add_poolstr_array(data, handle, name, str);
+}
+
+/*
+ * split value and add to pool
+ */
+
+static void
+add_multiple_urls(Repodata *data, Id handle, char *value, Id type)
+{
+  char *url;
+
+  while ((url = splitword(&value)) != 0)
+    {
+      repodata_add_poolstr_array(data, handle, PRODUCT_URL, url);
+      repodata_add_idarray(data, handle, PRODUCT_URL_TYPE, type);
+    }
+}
+
+
+
+/*
+ * add 'content' to repo
+ *
+ */
+
+int
+repo_add_content(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  char *line, *linep;
+  int aline;
+  Solvable *s;
+  struct parsedata pd;
+  Repodata *data;
+  Id handle = 0;
+  int contentstyle = 0;
+  char *descrdir = 0;
+  char *datadir = 0;
+  char *defvendor = 0;
+
+  int i = 0;
+  int res = 0;
+
+  /* architectures
+     we use the first architecture in BASEARCHS or noarch
+     for the product. At the end we create (clone) the product
+     for each one of the remaining architectures
+     we allow max 4 archs
+  */
+  unsigned int numotherarchs = 0;
+  Id *otherarchs = 0;
+
+  memset(&pd, 0, sizeof(pd));
+  line = solv_malloc(1024);
+  aline = 1024;
+
+  pd.repo = repo;
+  linep = line;
+  s = 0;
+
+  data = repo_add_repodata(repo, flags);
+
+  for (;;)
+    {
+      char *key, *value;
+
+      /* read line into big-enough buffer */
+      if (linep - line + 16 > aline)
+       {
+         aline = linep - line;
+         line = solv_realloc(line, aline + 512);
+         linep = line + aline;
+         aline += 512;
+       }
+      if (!fgets(linep, aline - (linep - line), fp))
+       break;
+      linep += strlen(linep);
+      if (linep == line || linep[-1] != '\n')
+        continue;
+      while ( --linep > line && ( linep[-1] == ' ' ||  linep[-1] == '\t' ) )
+        ; /* skip trailing ws */
+      *linep = 0;
+      linep = line;
+
+      /* expect "key value" lines */
+      value = line;
+      key = splitword(&value);
+
+      if (key)
+        {
+#if 0
+         fprintf (stderr, "key %s, value %s\n", key, value);
+#endif
+
+#define istag(x) (!strcmp (key, x))
+#define code10 (contentstyle == 10)
+#define code11 (contentstyle == 11)
+
+
+         if (istag ("CONTENTSTYLE"))
+           {
+             if (contentstyle)
+               pool_debug(pool, SOLV_ERROR, "repo_content: 'CONTENTSTYLE' must be first line of 'content'\n");
+             contentstyle = atoi(value);
+             continue;
+           }
+         if (!contentstyle)
+           contentstyle = 10;
+
+         /* repository tags */
+          /* we also replicate some of them into the product solvables
+           * to be backward compatible */
+
+         if (istag ("REPOID"))
+           {
+             repodata_add_poolstr_array(data, SOLVID_META, REPOSITORY_REPOID, value);
+             continue;
+           }
+         if (istag ("REPOKEYWORDS"))
+           {
+             add_multiple_strings(data, SOLVID_META, REPOSITORY_KEYWORDS, value);
+             continue;
+           }
+         if (istag ("DISTRO"))
+           {
+             Id dh = repodata_new_handle(data);
+             char *p;
+             /* like with createrepo --distro */
+             if ((p = strchr(value, ',')) != 0)
+               {
+                 *p++ = 0;
+                 if (*value)
+                   repodata_set_poolstr(data, dh, REPOSITORY_PRODUCT_CPEID, value);
+               }
+             else
+               p = value;
+             if (*p)
+               repodata_set_str(data, dh, REPOSITORY_PRODUCT_LABEL, p);
+             repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DISTROS, dh);
+             continue;
+           }
+
+         if (istag ("DESCRDIR"))
+           {
+             if (descrdir)
+               free(descrdir);
+             else
+               repodata_set_str(data, SOLVID_META, SUSETAGS_DESCRDIR, value);
+             if (s)
+               repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, value);
+             descrdir = solv_strdup(value);
+             continue;
+           }
+         if (istag ("DATADIR"))
+           {
+             if (datadir)
+               free(datadir);
+             else
+               repodata_set_str(data, SOLVID_META, SUSETAGS_DATADIR, value);
+             if (s)
+               repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, value);
+             datadir = solv_strdup(value);
+             continue;
+           }
+         if (istag ("VENDOR"))
+           {
+             if (defvendor)
+               free(defvendor);
+             else
+               repodata_set_poolstr(data, SOLVID_META, SUSETAGS_DEFAULTVENDOR, value);
+             if (s)
+               s->vendor = pool_str2id(pool, value, 1);
+             defvendor = solv_strdup(value);
+             continue;
+           }
+
+         if (istag ("META") || istag ("HASH") || istag ("KEY"))
+           {
+             char *checksumtype, *checksum;
+             Id fh, type;
+             int l;
+
+             if ((checksumtype = splitword(&value)) == 0)
+               continue;
+             if ((checksum = splitword(&value)) == 0)
+               continue;
+             if (!*value)
+               continue;
+             type = solv_chksum_str2type(checksumtype);
+             if (!type)
+               {
+                 pool_error(pool, -1, "%s: unknown checksum type '%s'", value, checksumtype);
+                 res = 1;
+                 continue;
+               }
+              l = solv_chksum_len(type);
+             if (strlen(checksum) != 2 * l)
+               {
+                 pool_error(pool, -1, "%s: invalid checksum length for %s", value, checksumtype);
+                 res = 1;
+                 continue;
+               }
+             fh = repodata_new_handle(data);
+             repodata_set_poolstr(data, fh, SUSETAGS_FILE_TYPE, key);
+             repodata_set_str(data, fh, SUSETAGS_FILE_NAME, value);
+             repodata_set_checksum(data, fh, SUSETAGS_FILE_CHECKSUM, type, checksum);
+             repodata_add_flexarray(data, SOLVID_META, SUSETAGS_FILE, fh);
+             continue;
+           }
+
+         /* product tags */
+
+         if ((code10 && istag ("PRODUCT"))
+             || (code11 && istag ("NAME")))
+           {
+             if (s && !s->name)
+               {
+                 /* this solvable was created without seeing a
+                    PRODUCT entry, just set the name and continue */
+                 s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
+                 continue;
+               }
+             if (s)
+               {
+                 /* finish old solvable */
+                 if (!s->arch)
+                   s->arch = ARCH_NOARCH;
+                 if (!s->evr)
+                   s->evr = ID_EMPTY;
+                 if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+                   s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+                 if (code10)
+                   repo_rewrite_suse_deps(s, 0);
+               }
+             /* create new solvable */
+             s = pool_id2solvable(pool, repo_add_solvable(repo));
+             handle = s - pool->solvables;
+             s->name = pool_str2id(pool, join(&pd, "product", ":", value), 1);
+             if (datadir)
+               repodata_set_str(data, s - pool->solvables, SUSETAGS_DATADIR, datadir);
+             if (descrdir)
+               repodata_set_str(data, s - pool->solvables, SUSETAGS_DESCRDIR, descrdir);
+             if (defvendor)
+               s->vendor = pool_str2id(pool, defvendor, 1);
+             continue;
+           }
+
+         /* Sometimes PRODUCT/NAME is not the first entry, but we need a solvable
+            from here on.  */
+         if (!s)
+           {
+             s = pool_id2solvable(pool, repo_add_solvable(repo));
+             handle = s - pool->solvables;
+           }
+
+         if (istag ("VERSION"))
+            pd.tmpvers = solv_strdup(value);
+          else if (istag ("RELEASE"))
+            pd.tmprel = solv_strdup(value);
+         else if (code11 && istag ("DISTRIBUTION"))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_DISTRIBUTION, value);
+         else if (istag ("UPDATEURLS"))
+           add_multiple_urls(data, handle, value, pool_str2id(pool, "update", 1));
+         else if (istag ("EXTRAURLS"))
+           add_multiple_urls(data, handle, value, pool_str2id(pool, "extra", 1));
+         else if (istag ("OPTIONALURLS"))
+           add_multiple_urls(data, handle, value, pool_str2id(pool, "optional", 1));
+         else if (istag ("RELNOTESURL"))
+           add_multiple_urls(data, handle, value, pool_str2id(pool, "releasenotes", 1));
+         else if (istag ("SHORTLABEL"))
+           repodata_set_str(data, s - pool->solvables, PRODUCT_SHORTLABEL, value);
+         else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
+           repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, value);
+         else if (!strncmp (key, "LABEL.", 6))
+           repodata_set_str(data, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
+         else if (istag ("FLAGS"))
+           add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
+         else if (istag ("VENDOR"))    /* actually already handled above */
+           s->vendor = pool_str2id(pool, value, 1);
+          else if (istag ("BASEARCHS"))
+            {
+              char *arch;
+
+             if ((arch = splitword(&value)) != 0)
+               {
+                 s->arch = pool_str2id(pool, arch, 1);
+                 while ((arch = splitword(&value)) != 0)
+                   {
+                      otherarchs = solv_extend(otherarchs, numotherarchs, 1, sizeof(Id), 7);
+                      otherarchs[numotherarchs++] = pool_str2id(pool, arch, 1);
+                   }
+               }
+            }
+         if (!code10)
+           continue;
+
+         /*
+          * Every tag below is Code10 only
+          *
+          */
+
+         if (istag ("ARCH"))
+           /* Theoretically we want to have the best arch of the given
+              modifiers which still is compatible with the system
+              arch.  We don't know the latter here, though.  */
+           s->arch = ARCH_NOARCH;
+         else if (istag ("PREREQUIRES"))
+           s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
+         else if (istag ("REQUIRES"))
+           s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
+         else if (istag ("PROVIDES"))
+           s->provides = adddep(pool, &pd, s->provides, value, 0);
+         else if (istag ("CONFLICTS"))
+           s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
+         else if (istag ("OBSOLETES"))
+           s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
+         else if (istag ("RECOMMENDS"))
+           s->recommends = adddep(pool, &pd, s->recommends, value, 0);
+         else if (istag ("SUGGESTS"))
+           s->suggests = adddep(pool, &pd, s->suggests, value, 0);
+         else if (istag ("SUPPLEMENTS"))
+           s->supplements = adddep(pool, &pd, s->supplements, value, 0);
+         else if (istag ("ENHANCES"))
+           s->enhances = adddep(pool, &pd, s->enhances, value, 0);
+         /* FRESHENS doesn't seem to exist.  */
+         else if (istag ("TYPE"))
+           repodata_set_str(data, s - pool->solvables, PRODUCT_TYPE, value);
+
+         /* XXX do something about LINGUAS and ARCH?
+          * <ma>: Don't think so. zypp does not use or propagate them.
+          */
+#undef istag
+       }
+      else
+       pool_debug(pool, SOLV_ERROR, "repo_content: malformed line: %s\n", line);
+    }
+
+  if (datadir)
+    free(datadir);
+  if (descrdir)
+    free(descrdir);
+  if (defvendor)
+    free(defvendor);
+
+  if (s && !s->name)
+    {
+      pool_debug(pool, SOLV_ERROR, "repo_content: 'content' incomplete, no product solvable created!\n");
+      s = solvable_free(s, 1);
+    }
+  if (s)
+    {
+      if (pd.tmprel)
+       s->evr = makeevr(pool, join(&pd, pd.tmpvers, "-", pd.tmprel));
+      else
+       s->evr = makeevr(pool, pd.tmpvers);
+      pd.tmpvers = solv_free((void *)pd.tmpvers);
+      pd.tmprel = solv_free((void *)pd.tmprel);
+
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+        s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      if (code10)
+       repo_rewrite_suse_deps(s, 0);
+
+      /* now for every other arch, clone the product except the architecture */
+      for (i = 0; i < numotherarchs; ++i)
+       {
+         Solvable *p = pool_id2solvable(pool, repo_add_solvable(repo));
+         p->name = s->name;
+         p->evr = s->evr;
+         p->vendor = s->vendor;
+         p->arch = otherarchs[i];
+
+         /* self provides */
+         if (s->name && p->arch != ARCH_SRC && p->arch != ARCH_NOSRC)
+             p->provides = repo_addid_dep(repo, p->provides, pool_rel2id(pool, p->name, p->evr, REL_EQ, 1), 0);
+
+         /* now merge the attributes */
+         repodata_merge_attrs(data, p - pool->solvables, s - pool->solvables);
+       }
+    }
+
+  if (pd.tmp)
+    solv_free(pd.tmp);
+  solv_free(line);
+  solv_free(otherarchs);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return res;
+}
diff --git a/libsolv-0.7.2/ext/repo_content.h b/libsolv-0.7.2/ext/repo_content.h
new file mode 100644 (file)
index 0000000..2a70ce4
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_content(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.7.2/ext/repo_cudf.c b/libsolv-0.7.2/ext/repo_cudf.c
new file mode 100644 (file)
index 0000000..64bb86f
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "chksum.h"
+#include "solver.h"
+#include "repo_cudf.h"
+
+static Id
+parseonedep(Pool *pool, char *p)
+{
+  char *n, *ne, *e, *ee;
+  Id name, evr;
+  int flags;
+
+  while (*p == ' ' || *p == '\t' || *p == '\n')
+    p++;
+  if (!*p)
+    return 0;
+  if (!strcmp(p, "!true"))
+    return 0;
+  if (!strcmp(p, "!false"))
+    return pool_str2id(pool, p, 1);
+  n = p;
+  /* find end of name */
+  while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
+    p++;
+  ne = p;
+  while (*p == ' ' || *p == '\t' || *p == '\n')
+    p++;
+  evr = 0;
+  flags = 0;
+  e = ee = 0;
+  if (*p == '>' || *p == '<' || *p == '=' || *p == '!')
+    {
+      if (*p == '>')
+       flags |= REL_GT;
+      else if (*p == '=')
+       flags |= REL_EQ;
+      else if (*p == '<')
+       flags |= REL_LT;
+      else if (*p == '!')
+       flags |= REL_LT | REL_GT | REL_EQ;
+      p++;
+      if (flags && *p == '=')
+       {
+         if (p[-1] != '=')
+           flags ^= REL_EQ;
+         p++;
+       }
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+      e = p;
+      while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '|')
+       p++;
+      ee = p;
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+    }
+  name = pool_strn2id(pool, n, ne - n, 1);
+  if (e)
+    {
+      evr = pool_strn2id(pool, e, ee - e, 1);
+      name = pool_rel2id(pool, name, evr, flags, 1);
+    }
+  if (*p == '|')
+    {
+      Id id = parseonedep(pool, p + 1);
+      if (id)
+       name = pool_rel2id(pool, name, id, REL_OR, 1);
+    }
+  return name;
+}
+static unsigned int
+makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
+{
+  Pool *pool = repo->pool;
+  char *p;
+  Id id;
+
+  while ((p = strchr(deps, ',')) != 0)
+    {
+      *p = 0;
+      olddeps = makedeps(repo, deps, olddeps, marker);
+      *p = ',';
+      deps = p + 1;
+    }
+  id = parseonedep(pool, deps);
+  if (!id)
+    return olddeps;
+  return repo_addid_dep(repo, olddeps, id, marker);
+}
+
+static Offset
+copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
+{
+  Id *ida, *from;
+  int cc;
+  Offset off;
+
+  if (!fromoff)
+    return 0;
+  from = fromrepo->idarraydata + fromoff;
+  for (ida = from, cc = 0; *ida; ida++, cc++)
+    ;
+  if (cc == 0)
+    return 0;
+  off = repo_reserve_ids(repo, 0, cc);
+  memcpy(repo->idarraydata + off, from, (cc + 1) * sizeof(Id));
+  repo->idarraysize += cc + 1;
+  return off;
+}
+
+static void
+copysolvabledata(Pool *pool, Solvable *s, Repo *repo)
+{
+  Repo *srepo = s->repo;
+  if (srepo == repo)
+    return;
+  s->provides = copydeps(pool, repo, s->provides, srepo);
+  s->requires = copydeps(pool, repo, s->requires, srepo);
+  s->conflicts = copydeps(pool, repo, s->conflicts, srepo);
+  s->obsoletes = copydeps(pool, repo, s->obsoletes, srepo);
+  s->recommends = copydeps(pool, repo, s->recommends, srepo);
+  s->suggests = copydeps(pool, repo, s->suggests, srepo);
+  s->supplements = copydeps(pool, repo, s->supplements, srepo);
+  s->enhances  = copydeps(pool, repo, s->enhances, srepo);
+}
+
+#define KEEP_VERSION 1
+#define KEEP_PACKAGE 2
+#define KEEP_FEATURE 3
+
+static void
+finishpackage(Pool *pool, Solvable *s, int keep, Queue *job)
+{
+  Id *idp, id, sid;
+  if (!s)
+    return;
+  if (!s->arch)
+    s->arch = ARCH_ANY;
+  if (!s->evr)
+    s->evr = ID_EMPTY;
+  sid = pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
+  s->provides = repo_addid_dep(s->repo, s->provides, sid, 0);
+  if (!job || !pool->installed || s->repo != pool->installed)
+    return;
+  if (keep == KEEP_VERSION)
+    queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, sid);
+  else if (keep == KEEP_PACKAGE)
+    queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, s->name);
+  else if (keep == KEEP_FEATURE)
+    {
+      for (idp = s->repo->idarraydata + s->provides; (id = *idp) != 0; idp++)
+       {
+         if (id != sid)        /* skip self-provides */
+           queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
+       }
+    }
+}
+
+int
+repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
+{
+  Pool *pool;
+  char *buf, *p;
+  int bufa, bufl, c;
+  Solvable *s;
+  int instanza = 0;
+  int inrequest = 0;
+  int isinstalled = 0;
+  int keep = 0;
+  Repo *xrepo;
+
+  xrepo = repo ? repo : installedrepo;
+  if (!xrepo)
+    return -1;
+  pool = xrepo->pool;
+
+  buf = solv_malloc(4096);
+  bufa = 4096;
+  bufl = 0;
+  s = 0;
+
+  while (fgets(buf + bufl, bufa - bufl, fp) > 0)
+    {
+      bufl += strlen(buf + bufl);
+      if (bufl && buf[bufl - 1] != '\n')
+       {
+         if (bufa - bufl < 256)
+           {
+             bufa += 4096;
+             buf = solv_realloc(buf, bufa);
+           }
+         continue;
+       }
+      buf[--bufl] = 0;
+      c = getc(fp);
+      if (c == ' ' || c == '\t')
+       {
+         /* continuation line */
+         buf[bufl++] = ' ';
+         continue;
+       }
+      if (c != EOF)
+       ungetc(c, fp);
+      bufl = 0;
+      if (*buf == '#')
+       continue;
+      if (!*buf)
+       {
+         if (s && !repo && !isinstalled)
+           s = solvable_free(s, 1);
+         if (s)
+           finishpackage(pool, s, keep, job);
+         s = 0;
+         keep = 0;
+         instanza = 0;
+         inrequest = 0;
+         continue;
+       }
+      p = strchr(buf, ':');
+      if (!p)
+       continue;       /* hmm */
+      *p++ = 0;
+      while (*p == ' ' || *p == '\t')
+       p++;
+      if (!instanza)
+       {
+         instanza = 1;
+         inrequest = 0;
+         if (!strcmp(buf, "request"))
+           {
+             inrequest = 1;
+             continue;
+           }
+         if (!strcmp(buf, "package"))
+           {
+             s = pool_id2solvable(pool, repo_add_solvable(xrepo));
+             isinstalled = 0;
+             keep = 0;
+           }
+       }
+      if (inrequest)
+       {
+         if (!job)
+           continue;
+         if (!strcmp(buf, "install"))
+           {
+             Id id, *idp;
+             Offset off = makedeps(xrepo, p, 0, 0);
+             for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
+               queue_push2(job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, id);
+           }
+         else if (!strcmp(buf, "remove"))
+           {
+             Id id, *idp;
+             Offset off = makedeps(xrepo, p, 0, 0);
+             for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
+               queue_push2(job, SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES, id);
+           }
+         else if (!strcmp(buf, "upgrade"))
+           {
+             Id id, *idp;
+             Offset off = makedeps(xrepo, p, 0, 0);
+             for (idp = xrepo->idarraydata + off; (id = *idp) != 0; idp++)
+               queue_push2(job, SOLVER_INSTALL|SOLVER_ORUPDATE|SOLVER_SOLVABLE_PROVIDES, id);
+           }
+         continue;
+       }
+      if (!s)
+       continue;       /* we ignore the preamble for now */
+      switch (buf[0])
+       {
+       case 'c':
+         if (!strcmp(buf, "conflicts"))
+           {
+             s->conflicts = makedeps(s->repo, p, s->conflicts, 0);
+             continue;
+           }
+       case 'd':
+         if (!strcmp(buf, "depends"))
+           {
+             s->requires = makedeps(s->repo, p, s->requires, 0);
+             continue;
+           }
+         break;
+       case 'k':
+         if (!strcmp(buf, "keep"))
+           {
+             if (!job)
+               continue;
+             if (!strcmp(p, "version"))
+               keep = KEEP_VERSION;
+             else if (!strcmp(p, "package"))
+               keep = KEEP_PACKAGE;
+             else if (!strcmp(p, "feature"))
+               keep = KEEP_FEATURE;
+             continue;
+           }
+         break;
+       case 'i':
+         if (!strcmp(buf, "installed"))
+           {
+             if (!strcmp(p, "true"))
+               {
+                 isinstalled = 1;
+                 if (!installedrepo)
+                   s = solvable_free(s, 1);
+                 else if (s->repo != installedrepo)
+                   {
+                     copysolvabledata(pool, s, installedrepo);
+                     s->repo->nsolvables--;
+                     s->repo = installedrepo;
+                     if (s - pool->solvables < s->repo->start)
+                       s->repo->start = s - pool->solvables;
+                     if (s - pool->solvables >= s->repo->end)
+                       s->repo->end = s - pool->solvables + 1;
+                     s->repo->nsolvables++;
+                   }
+               }
+             continue;
+           }
+         break;
+       case 'p':
+         if (!strcmp(buf, "package"))
+           {
+             s->name = pool_str2id(pool, p, 1);
+             continue;
+           }
+         if (!strcmp(buf, "provides"))
+           {
+             s->provides = makedeps(s->repo, p, s->provides, 0);
+             continue;
+           }
+         break;
+       case 'r':
+         if (!strcmp(buf, "depends"))
+           {
+             s->recommends = makedeps(s->repo, p, s->recommends, 0);
+             continue;
+           }
+         break;
+       case 'v':
+         if (!strcmp(buf, "version"))
+           {
+             s->evr = pool_str2id(pool, p, 1);
+             continue;
+           }
+         break;
+       }
+    }
+  if (s && !repo && !isinstalled)
+    s = solvable_free(s, 1);
+  if (s)
+    finishpackage(pool, s, keep, job);
+  solv_free(buf);
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/ext/repo_cudf.h b/libsolv-0.7.2/ext/repo_cudf.h
new file mode 100644 (file)
index 0000000..fc9a0d6
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags);
+
diff --git a/libsolv-0.7.2/ext/repo_deb.c b/libsolv-0.7.2/ext/repo_deb.c
new file mode 100644 (file)
index 0000000..0f17fea
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef ENABLE_ZLIB_COMPRESSION
+#include <zlib.h>
+#endif
+#ifdef ENABLE_LZMA_COMPRESSION
+#include <lzma.h>
+#endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+#include <zstd.h>
+#endif
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "solver.h"    /* for GET_USERINSTALLED_ flags */
+#include "chksum.h"
+#include "repo_deb.h"
+
+#define MAX_CONTROL_SIZE       0x1000000
+
+#ifdef ENABLE_ZLIB_COMPRESSION
+
+static unsigned char *
+decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  z_stream strm;
+  int outl, ret;
+  unsigned char *bp, *out;
+
+  /* first skip the gz header */
+  if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b)
+    return 0;
+  if (in[2] != 8 || (in[3] & 0xe0) != 0)
+    return 0;
+  bp = in + 4;
+  bp += 6;     /* skip time, xflags and OS code */
+  if (in[3] & 0x04)
+    {
+      /* skip extra field */
+      int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8);
+      bp += l + 2;
+    }
+  if (in[3] & 0x08)    /* orig filename */
+    while (bp < in + inl && *bp++)
+      ;
+  if (in[3] & 0x10)    /* file comment */
+    while (bp < in + inl && *bp++)
+      ;
+  if (in[3] & 0x02)    /* header crc */
+    bp += 2;
+  if (bp >= in + inl)
+    return 0;
+  inl -= bp - in;
+  in = bp;
+
+  memset(&strm, 0, sizeof(strm));
+  strm.next_in = in;
+  strm.avail_in = inl;
+  out = solv_malloc(4096);
+  strm.next_out = out;
+  strm.avail_out = 4096;
+  outl = 0;
+  ret = inflateInit2(&strm, -MAX_WBITS);
+  if (ret != Z_OK)
+    {
+      free(out);
+      return 0;
+    }
+  for (;;)
+    {
+      if (strm.avail_out == 0)
+       {
+         outl += 4096;
+         if (outl >= maxoutl)
+           {
+             inflateEnd(&strm);
+             free(out);
+             return 0;
+           }
+         out = solv_realloc(out, outl + 4096);
+         strm.next_out = out + outl;
+         strm.avail_out = 4096;
+       }
+      ret = inflate(&strm, Z_NO_FLUSH);
+      if (ret == Z_STREAM_END)
+       break;
+      if (ret != Z_OK)
+       {
+         inflateEnd(&strm);
+         free(out);
+         return 0;
+       }
+    }
+  outl += 4096 - strm.avail_out;
+  inflateEnd(&strm);
+  *outlp = outl;
+  return out;
+}
+
+#else
+
+static unsigned char *
+decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  return 0;
+}
+
+#endif /* ENABLE_ZLIB_COMPRESSION */
+
+#ifdef ENABLE_LZMA_COMPRESSION
+
+static unsigned char *
+decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  static lzma_stream stream_init = LZMA_STREAM_INIT;
+  lzma_stream strm;
+  int outl, ret;
+  unsigned char *out;
+
+  strm = stream_init;
+  strm.next_in = in;
+  strm.avail_in = inl;
+  out = solv_malloc(4096);
+  strm.next_out = out;
+  strm.avail_out = 4096;
+  outl = 0;
+  ret = lzma_auto_decoder(&strm, 100 << 20, 0);
+  if (ret != LZMA_OK)
+    {
+      free(out);
+      return 0;
+    }
+  for (;;)
+    {
+      if (strm.avail_out == 0)
+       {
+         outl += 4096;
+         if (outl >= maxoutl)
+           {
+             lzma_end(&strm);
+             free(out);
+             return 0;
+           }
+         out = solv_realloc(out, outl + 4096);
+         strm.next_out = out + outl;
+         strm.avail_out = 4096;
+       }
+      ret = lzma_code(&strm, LZMA_RUN);
+      if (ret == LZMA_STREAM_END)
+       break;
+      if (ret != LZMA_OK)
+       {
+         lzma_end(&strm);
+         free(out);
+         return 0;
+       }
+    }
+  outl += 4096 - strm.avail_out;
+  lzma_end(&strm);
+  *outlp = outl;
+  return out;
+}
+
+#else
+
+static unsigned char *
+decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  return 0;
+}
+
+#endif /* ENABLE_LZMA_COMPRESSION */
+
+#ifdef ENABLE_ZSTD_COMPRESSION
+
+static unsigned char *
+decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  ZSTD_DStream *dstream;
+  ZSTD_inBuffer inbuf;
+  ZSTD_outBuffer outbuf;
+  int ret;
+
+  dstream = ZSTD_createDStream();
+  if (!dstream)
+    return 0;
+  if (ZSTD_isError(ZSTD_initDStream(dstream)))
+    {
+      ZSTD_freeDStream(dstream);
+      return 0;
+    }
+  inbuf.src = in;
+  inbuf.pos = 0;
+  inbuf.size = inl;
+  outbuf.dst = solv_malloc(4096);
+  outbuf.pos = 0;
+  outbuf.size = 4096;
+  for (;;)
+    {
+      if (outbuf.pos == outbuf.size)
+       {
+         outbuf.size += 4096;
+         if (outbuf.size >= maxoutl)
+           {
+             ret = 1;
+             break;
+           }
+         outbuf.dst = solv_realloc(outbuf.dst, outbuf.size + 4096);
+       }
+      ret = ZSTD_decompressStream(dstream, &outbuf, &inbuf);
+      if (ret == 0 && inbuf.pos == inbuf.size)
+       break;
+      if (ZSTD_isError(ret) || (inbuf.pos == inbuf.size && outbuf.pos < outbuf.size))
+       {
+         ret = 1;
+         break;
+       }
+    }
+  ZSTD_freeDStream(dstream);
+  if (ret)
+    {
+      solv_free(outbuf.dst);
+      return 0;
+    }
+  *outlp = outbuf.pos;
+  return outbuf.dst;
+}
+
+#else
+
+static unsigned char *
+decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  return 0;
+}
+
+#endif /* ENABLE_ZSTD_COMPRESSION */
+
+static Id
+parseonedep(Pool *pool, char *p)
+{
+  char *n, *ne, *e, *ee;
+  Id name, evr;
+  int flags;
+
+  while (*p == ' ' || *p == '\t' || *p == '\n')
+    p++;
+  if (!*p || *p == '(')
+    return 0;
+  n = p;
+  /* find end of name */
+  while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
+    p++;
+  ne = p;
+  while (*p == ' ' || *p == '\t' || *p == '\n')
+    p++;
+  evr = 0;
+  flags = 0;
+  e = ee = 0;
+  if (*p == '(')
+    {
+      p++;
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+      if (*p == '>')
+       flags |= REL_GT;
+      else if (*p == '=')
+       flags |= REL_EQ;
+      else if (*p == '<')
+       flags |= REL_LT;
+      if (flags)
+       {
+         p++;
+         if (*p == '>')
+           flags |= REL_GT;
+         else if (*p == '=')
+           flags |= REL_EQ;
+         else if (*p == '<')
+           flags |= REL_LT;
+         else
+           p--;
+         p++;
+       }
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+      e = p;
+      while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
+       p++;
+      ee = p;
+      while (*p && *p != ')')
+       p++;
+      if (*p)
+       p++;
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+    }
+  if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4))
+    {
+      /* multiarch annotation */
+      name = pool_strn2id(pool, n, ne - n - 4, 1);
+      name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1);
+    }
+  else
+    name = pool_strn2id(pool, n, ne - n, 1);
+  if (e)
+    {
+      evr = pool_strn2id(pool, e, ee - e, 1);
+      name = pool_rel2id(pool, name, evr, flags, 1);
+    }
+  if (*p == '|')
+    {
+      Id id = parseonedep(pool, p + 1);
+      if (id)
+       name = pool_rel2id(pool, name, id, REL_OR, 1);
+    }
+  return name;
+}
+
+static unsigned int
+makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
+{
+  Pool *pool = repo->pool;
+  char *p;
+  Id id;
+
+  while ((p = strchr(deps, ',')) != 0)
+    {
+      *p = 0;
+      olddeps = makedeps(repo, deps, olddeps, marker);
+      *p = ',';
+      deps = p + 1;
+    }
+  id = parseonedep(pool, deps);
+  if (!id)
+    return olddeps;
+  return repo_addid_dep(repo, olddeps, id, marker);
+}
+
+
+/* put data from control file into the solvable */
+/* warning: does inplace changes */
+static void
+control2solvable(Solvable *s, Repodata *data, char *control)
+{
+  Repo *repo = s->repo;
+  Pool *pool = repo->pool;
+  char *p, *q, *end, *tag;
+  int x, l;
+  int havesource = 0;
+  char checksum[32 * 2 + 1];
+  Id checksumtype = 0;
+  Id newtype;
+
+  p = control;
+  while (*p)
+    {
+      p = strchr(p, '\n');
+      if (!p)
+       break;
+      if (p[1] == ' ' || p[1] == '\t')
+       {
+         char *q;
+         /* continuation line */
+         q = p - 1;
+         while (q >= control && *q == ' ' && *q == '\t')
+           q--;
+         l = q + 1 - control;
+         if (l)
+           memmove(p + 1 - l, control, l);
+         control = p + 1 - l;
+         p[1] = '\n';
+         p += 2;
+         continue;
+       }
+      end = p - 1;
+      if (*p)
+        *p++ = 0;
+      /* strip trailing space */
+      while (end >= control && (*end == ' ' || *end == '\t'))
+       *end-- = 0;
+      tag = control;
+      control = p;
+      q = strchr(tag, ':');
+      if (!q || q - tag < 4)
+       continue;
+      *q++ = 0;
+      while (*q == ' ' || *q == '\t')
+       q++;
+      x = '@' + (tag[0] & 0x1f);
+      x = (x << 8) + '@' + (tag[1] & 0x1f);
+      switch(x)
+       {
+       case 'A' << 8 | 'R':
+         if (!strcasecmp(tag, "architecture"))
+           s->arch = pool_str2id(pool, q, 1);
+         break;
+       case 'B' << 8 | 'R':
+         if (!strcasecmp(tag, "breaks"))
+           s->conflicts = makedeps(repo, q, s->conflicts, 0);
+         break;
+       case 'C' << 8 | 'O':
+         if (!strcasecmp(tag, "conflicts"))
+           s->conflicts = makedeps(repo, q, s->conflicts, 0);
+         break;
+       case 'D' << 8 | 'E':
+         if (!strcasecmp(tag, "depends"))
+           s->requires = makedeps(repo, q, s->requires, -SOLVABLE_PREREQMARKER);
+         else if (!strcasecmp(tag, "description"))
+           {
+             char *ld = strchr(q, '\n');
+             if (ld)
+               {
+                 *ld++ = 0;
+                 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, ld);
+               }
+             else
+               repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, q);
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, q);
+           }
+         break;
+       case 'E' << 8 | 'N':
+         if (!strcasecmp(tag, "enhances"))
+           s->enhances = makedeps(repo, q, s->enhances, 0);
+         break;
+       case 'F' << 8 | 'I':
+         if (!strcasecmp(tag, "filename"))
+           repodata_set_location(data, s - pool->solvables, 0, 0, q);
+         break;
+       case 'H' << 8 | 'O':
+         if (!strcasecmp(tag, "homepage"))
+           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
+         break;
+       case 'I' << 8 | 'N':
+         if (!strcasecmp(tag, "installed-size"))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10);
+         break;
+       case 'M' << 8 | 'D':
+         if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
+           {
+             strcpy(checksum, q);
+             checksumtype = REPOKEY_TYPE_MD5;
+           }
+         break;
+       case 'P' << 8 | 'A':
+         if (!strcasecmp(tag, "package"))
+           s->name = pool_str2id(pool, q, 1);
+         break;
+       case 'P' << 8 | 'R':
+         if (!strcasecmp(tag, "pre-depends"))
+           s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER);
+         else if (!strcasecmp(tag, "provides"))
+           s->provides = makedeps(repo, q, s->provides, 0);
+         break;
+       case 'R' << 8 | 'E':
+         if (!strcasecmp(tag, "replaces"))
+           s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
+         else if (!strcasecmp(tag, "recommends"))
+           s->recommends = makedeps(repo, q, s->recommends, 0);
+         break;
+       case 'S' << 8 | 'H':
+         newtype = solv_chksum_str2type(tag);
+         if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
+           break;
+         if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
+           {
+             strcpy(checksum, q);
+             checksumtype = newtype;
+           }
+         break;
+       case 'S' << 8 | 'O':
+         if (!strcasecmp(tag, "source"))
+           {
+             char *q2;
+             /* ignore version for now */
+             for (q2 = q; *q2; q2++)
+               if (*q2 == ' ' || *q2 == '\t')
+                 {
+                   *q2 = 0;
+                   break;
+                 }
+             if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
+               repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+             else
+               repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
+             havesource = 1;
+           }
+         break;
+       case 'S' << 8 | 'T':
+         if (!strcasecmp(tag, "status"))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
+         break;
+       case 'S' << 8 | 'U':
+         if (!strcasecmp(tag, "suggests"))
+           s->suggests = makedeps(repo, q, s->suggests, 0);
+         break;
+       case 'V' << 8 | 'E':
+         if (!strcasecmp(tag, "version"))
+           s->evr = pool_str2id(pool, q, 1);
+         break;
+       }
+    }
+  if (checksumtype)
+    repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
+  if (!s->arch)
+    s->arch = ARCH_ALL;
+  if (!s->evr)
+    s->evr = ID_EMPTY;
+  if (s->name)
+    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+  if (s->name && !havesource)
+    repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+  if (s->obsoletes)
+    {
+      /* obsoletes only count when the packages also conflict */
+      /* XXX: should not transcode here */
+      int i, j, k;
+      Id d, cid;
+      for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
+       {
+         if (!s->conflicts)
+           continue;
+         for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
+           {
+             if (repo->idarraydata[k] == cid)
+               break;
+             if (ISRELDEP(cid))
+               {
+                 Reldep *rd = GETRELDEP(pool, cid);
+                 if (rd->flags < 8 && rd->name == d)
+                   break;      /* specialize obsoletes */
+               }
+           }
+         if (cid)
+           repo->idarraydata[j++] = cid;
+       }
+      repo->idarraydata[j] = 0;
+      if (j == s->obsoletes)
+       s->obsoletes = 0;
+    }
+}
+
+int
+repo_add_debpackages(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  char *buf, *p;
+  int bufl, l, ll;
+  Solvable *s;
+
+  data = repo_add_repodata(repo, flags);
+  buf = solv_malloc(4096);
+  bufl = 4096;
+  l = 0;
+  buf[l] = 0;
+  p = buf;
+  for (;;)
+    {
+      if (!(p = strchr(p, '\n')))
+       {
+         int l3;
+         while (l + 1024 >= bufl)
+           {
+             buf = solv_realloc(buf, bufl + 4096);
+             bufl += 4096;
+           }
+         p = buf + l;
+         ll = fread(p, 1, bufl - l - 1, fp);
+         if (ll <= 0)
+           break;
+         p[ll] = 0;
+         while ((l3 = strlen(p)) < ll)
+           p[l3] = '\n';
+         l += ll;
+         if (p != buf)
+           p--;
+         continue;
+       }
+      p++;
+      if (*p != '\n')
+       continue;
+      *p = 0;
+      ll = p - buf + 1;
+      s = pool_id2solvable(pool, repo_add_solvable(repo));
+      control2solvable(s, data, buf);
+      if (!s->name)
+       s = solvable_free(s, 1);
+      if (l > ll)
+        memmove(buf, p + 1, l - ll);
+      l -= ll;
+      p = buf;
+      buf[l] = 0;
+    }
+  if (l)
+    {
+      s = pool_id2solvable(pool, repo_add_solvable(repo));
+      control2solvable(s, data, buf);
+      if (!s->name)
+       s = solvable_free(s, 1);
+    }
+  solv_free(buf);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+int
+repo_add_debdb(Repo *repo, int flags)
+{
+  FILE *fp;
+  const char *path = "/var/lib/dpkg/status";
+  if (flags & REPO_USE_ROOTDIR)
+    path = pool_prepend_rootdir_tmp(repo->pool, path);
+  if ((fp = fopen(path, "r")) == 0)
+    return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
+  repo_add_debpackages(repo, fp, flags);
+  fclose(fp);
+  return 0;
+}
+
+#define CONTROL_COMP_NONE      0
+#define CONTROL_COMP_GZIP      1
+#define CONTROL_COMP_XZ                2
+#define CONTROL_COMP_ZSTD      3
+
+Id
+repo_add_deb(Repo *repo, const char *deb, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  unsigned char buf[4096], *bp;
+  int l, l2, vlen, clen, ctarlen;
+  int control_comp;
+  unsigned char *ctgz;
+  unsigned char pkgid[16];
+  unsigned char *ctar;
+  int gotpkgid;
+  FILE *fp;
+  Solvable *s;
+  struct stat stb;
+
+  data = repo_add_repodata(repo, flags);
+  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
+    {
+      pool_error(pool, -1, "%s: %s", deb, strerror(errno));
+      return 0;
+    }
+  if (fstat(fileno(fp), &stb))
+    {
+      pool_error(pool, -1, "fstat: %s", strerror(errno));
+      fclose(fp);
+      return 0;
+    }
+  l = fread(buf, 1, sizeof(buf), fp);
+  if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/  ", 8 + 16) != 0))
+    {
+      pool_error(pool, -1, "%s: not a deb package", deb);
+      fclose(fp);
+      return 0;
+    }
+  vlen = atoi((char *)buf + 8 + 48);
+  if (vlen < 0 || vlen > l)
+    {
+      pool_error(pool, -1, "%s: not a deb package", deb);
+      fclose(fp);
+      return 0;
+    }
+  vlen += vlen & 1;
+  if (l < 8 + 60 + vlen + 60)
+    {
+      pool_error(pool, -1, "%s: unhandled deb package", deb);
+      fclose(fp);
+      return 0;
+    }
+  control_comp = 0;
+  if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
+    control_comp = CONTROL_COMP_GZIP;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
+    control_comp = CONTROL_COMP_XZ;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16))
+    control_comp = CONTROL_COMP_ZSTD;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
+    control_comp = CONTROL_COMP_NONE;
+  else
+    {
+      pool_error(pool, -1, "%s: control.tar is not second entry", deb);
+      fclose(fp);
+      return 0;
+    }
+  /* dpkg has no actual maximum size for the control.tar member, so this
+   * just keeps from allocating arbitrarily large amounts of memory.
+   */
+  clen = atoi((char *)buf + 8 + 60 + vlen + 48);
+  if (clen <= 0 || clen >= MAX_CONTROL_SIZE)
+    {
+      pool_error(pool, -1, "%s: control.tar has illegal size", deb);
+      fclose(fp);
+      return 0;
+    }
+  ctgz = solv_calloc(1, clen + 4);
+  bp = buf + 8 + 60 + vlen + 60;
+  l -= 8 + 60 + vlen + 60;
+  if (l > clen)
+    l = clen;
+  if (l)
+    memcpy(ctgz, bp, l);
+  if (l < clen)
+    {
+      if (fread(ctgz + l, clen - l, 1, fp) != 1)
+       {
+         pool_error(pool, -1, "%s: unexpected EOF", deb);
+         solv_free(ctgz);
+         fclose(fp);
+         return 0;
+       }
+    }
+  fclose(fp);
+  gotpkgid = 0;
+  if (flags & DEBS_ADD_WITH_PKGID)
+    {
+      Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+      solv_chksum_add(chk, ctgz, clen);
+      solv_chksum_free(chk, pkgid);
+      gotpkgid = 1;
+    }
+  ctar = 0;
+  if (control_comp == CONTROL_COMP_GZIP)
+    ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
+  else if (control_comp == CONTROL_COMP_XZ)
+    ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
+  else if (control_comp == CONTROL_COMP_ZSTD)
+    ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
+  else
+    {
+      ctarlen = clen;
+      ctar = solv_memdup(ctgz, clen);
+    }
+  solv_free(ctgz);
+  if (!ctar)
+    {
+      pool_error(pool, -1, "%s: control.tar decompression error", deb);
+      return 0;
+    }
+  bp = ctar;
+  l = ctarlen;
+  l2 = 0;
+  while (l > 512)
+    {
+      int j;
+      l2 = 0;
+      for (j = 124; j < 124 + 12; j++)
+       if (bp[j] >= '0' && bp[j] <= '7')
+         l2 = l2 * 8 + (bp[j] - '0');
+      if (l2 < 0 || l2 > l)
+       {
+         l2 = 0;
+         break;
+       }
+      bp[124] = 0;
+      if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
+       break;
+      l2 = 512 + ((l2 + 511) & ~511);
+      l -= l2;
+      bp += l2;
+    }
+  if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
+    {
+      pool_error(pool, -1, "%s: control.tar contains no control file", deb);
+      free(ctar);
+      return 0;
+    }
+  memmove(ctar, bp + 512, l2);
+  ctar = solv_realloc(ctar, l2 + 1);
+  ctar[l2] = 0;
+  s = pool_id2solvable(pool, repo_add_solvable(repo));
+  control2solvable(s, data, (char *)ctar);
+  if (!(flags & REPO_NO_LOCATION))
+    repodata_set_location(data, s - pool->solvables, 0, 0, deb);
+  if (S_ISREG(stb.st_mode))
+    repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
+  if (gotpkgid)
+    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
+  solv_free(ctar);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return s - pool->solvables;
+}
+
+void
+pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
+{
+  Id name = 0, arch = 0;
+  int autoinstalled = -1;
+  char *buf, *bp;
+  int x, l, bufl, eof = 0;
+  Id p, pp;
+
+  queue_empty(q);
+  buf = solv_malloc(4096);
+  bufl = 4096;
+  l = 0;
+  while (!eof)
+    {
+      while (bufl - l < 1024)
+       {
+         bufl += 4096;
+         if (bufl > 1024 * 64)
+           break;      /* hmm? */
+         buf = solv_realloc(buf, bufl);
+       }
+      if (!fgets(buf + l, bufl - l, fp))
+       {
+         eof = 1;
+         buf[l] = '\n';
+         buf[l + 1] = 0;
+       }
+      l = strlen(buf);
+      if (l && buf[l - 1] == '\n')
+       buf[--l] = 0;
+      if (!*buf || eof)
+       {
+         l = 0;
+         if (name && autoinstalled > 0)
+           {
+             if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+               queue_push2(q, name, arch);
+             else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+               queue_push(q, name);
+             else
+               {
+                 FOR_PROVIDES(p, pp, name)
+                   {
+                     Solvable *s = pool->solvables + p;
+                     if (s->name != name)
+                       continue;
+                     if (arch && s->arch != arch)
+                       continue;
+                     queue_push(q, p);
+                   }
+               }
+           }
+         name = arch = 0;
+         autoinstalled = -1;
+         continue;
+       }
+      /* strip trailing space */
+      while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+       buf[--l] = 0;
+      l = 0;
+
+      bp = strchr(buf, ':');
+      if (!bp || bp - buf < 4)
+       continue;
+      *bp++ = 0;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      x = '@' + (buf[0] & 0x1f);
+      x = (x << 8) + '@' + (buf[1] & 0x1f);
+      switch(x)
+       {
+       case 'P' << 8 | 'A':
+         if (!strcasecmp(buf, "package"))
+           name = pool_str2id(pool, bp, 1);
+         break;
+       case 'A' << 8 | 'R':
+         if (!strcasecmp(buf, "architecture"))
+           arch = pool_str2id(pool, bp, 1);
+         break;
+       case 'A' << 8 | 'U':
+         if (!strcasecmp(buf, "auto-installed"))
+           autoinstalled = atoi(bp);
+         break;
+       default:
+         break;
+       }
+    }
+}
+
diff --git a/libsolv-0.7.2/ext/repo_deb.c.orig b/libsolv-0.7.2/ext/repo_deb.c.orig
new file mode 100644 (file)
index 0000000..5dd79f4
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ * Copyright (c) 2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <zlib.h>
+#include <lzma.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "solver.h"    /* for GET_USERINSTALLED_ flags */
+#include "chksum.h"
+#include "repo_deb.h"
+
+static unsigned char *
+decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  z_stream strm;
+  int outl, ret;
+  unsigned char *bp, *out;
+
+  /* first skip the gz header */
+  if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b)
+    return 0;
+  if (in[2] != 8 || (in[3] & 0xe0) != 0)
+    return 0;
+  bp = in + 4;
+  bp += 6;     /* skip time, xflags and OS code */
+  if (in[3] & 0x04)
+    {
+      /* skip extra field */
+      int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8);
+      bp += l + 2;
+    }
+  if (in[3] & 0x08)    /* orig filename */
+    while (bp < in + inl && *bp++)
+      ;
+  if (in[3] & 0x10)    /* file comment */
+    while (bp < in + inl && *bp++)
+      ;
+  if (in[3] & 0x02)    /* header crc */
+    bp += 2;
+  if (bp >= in + inl)
+    return 0;
+  inl -= bp - in;
+  in = bp;
+
+  memset(&strm, 0, sizeof(strm));
+  strm.next_in = in;
+  strm.avail_in = inl;
+  out = solv_malloc(4096);
+  strm.next_out = out;
+  strm.avail_out = 4096;
+  outl = 0;
+  ret = inflateInit2(&strm, -MAX_WBITS);
+  if (ret != Z_OK)
+    {
+      free(out);
+      return 0;
+    }
+  for (;;)
+    {
+      if (strm.avail_out == 0)
+       {
+         outl += 4096;
+         if (outl >= maxoutl)
+           {
+             inflateEnd(&strm);
+             free(out);
+             return 0;
+           }
+         out = solv_realloc(out, outl + 4096);
+         strm.next_out = out + outl;
+         strm.avail_out = 4096;
+       }
+      ret = inflate(&strm, Z_NO_FLUSH);
+      if (ret == Z_STREAM_END)
+       break;
+      if (ret != Z_OK)
+       {
+         inflateEnd(&strm);
+         free(out);
+         return 0;
+       }
+    }
+  outl += 4096 - strm.avail_out;
+  inflateEnd(&strm);
+  *outlp = outl;
+  return out;
+}
+
+static unsigned char *
+decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  static lzma_stream stream_init = LZMA_STREAM_INIT;
+  lzma_stream strm;
+  int outl, ret;
+  unsigned char *out;
+
+  strm = stream_init;
+  strm.next_in = in;
+  strm.avail_in = inl;
+  out = solv_malloc(4096);
+  strm.next_out = out;
+  strm.avail_out = 4096;
+  outl = 0;
+  ret = lzma_auto_decoder(&strm, 100 << 20, 0);
+  if (ret != LZMA_OK)
+    {
+      free(out);
+      return 0;
+    }
+  for (;;)
+    {
+      if (strm.avail_out == 0)
+       {
+         outl += 4096;
+         if (outl >= maxoutl)
+           {
+             lzma_end(&strm);
+             free(out);
+             return 0;
+           }
+         out = solv_realloc(out, outl + 4096);
+         strm.next_out = out + outl;
+         strm.avail_out = 4096;
+       }
+      ret = lzma_code(&strm, LZMA_RUN);
+      if (ret == LZMA_STREAM_END)
+       break;
+      if (ret != LZMA_OK)
+       {
+         lzma_end(&strm);
+         free(out);
+         return 0;
+       }
+    }
+  outl += 4096 - strm.avail_out;
+  lzma_end(&strm);
+  *outlp = outl;
+  return out;
+}
+
+static Id
+parseonedep(Pool *pool, char *p)
+{
+  char *n, *ne, *e, *ee;
+  Id name, evr;
+  int flags;
+
+  while (*p == ' ' || *p == '\t' || *p == '\n')
+    p++;
+  if (!*p || *p == '(')
+    return 0;
+  n = p;
+  /* find end of name */
+  while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
+    p++;
+  ne = p;
+  while (*p == ' ' || *p == '\t' || *p == '\n')
+    p++;
+  evr = 0;
+  flags = 0;
+  e = ee = 0;
+  if (*p == '(')
+    {
+      p++;
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+      if (*p == '>')
+       flags |= REL_GT;
+      else if (*p == '=')
+       flags |= REL_EQ;
+      else if (*p == '<')
+       flags |= REL_LT;
+      if (flags)
+       {
+         p++;
+         if (*p == '>')
+           flags |= REL_GT;
+         else if (*p == '=')
+           flags |= REL_EQ;
+         else if (*p == '<')
+           flags |= REL_LT;
+         else
+           p--;
+         p++;
+       }
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+      e = p;
+      while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
+       p++;
+      ee = p;
+      while (*p && *p != ')')
+       p++;
+      if (*p)
+       p++;
+      while (*p == ' ' || *p == '\t' || *p == '\n')
+       p++;
+    }
+  if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4))
+    {
+      /* multiarch annotation */
+      name = pool_strn2id(pool, n, ne - n - 4, 1);
+      name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1);
+    }
+  else
+    name = pool_strn2id(pool, n, ne - n, 1);
+  if (e)
+    {
+      evr = pool_strn2id(pool, e, ee - e, 1);
+      name = pool_rel2id(pool, name, evr, flags, 1);
+    }
+  if (*p == '|')
+    {
+      Id id = parseonedep(pool, p + 1);
+      if (id)
+       name = pool_rel2id(pool, name, id, REL_OR, 1);
+    }
+  return name;
+}
+
+static unsigned int
+makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
+{
+  Pool *pool = repo->pool;
+  char *p;
+  Id id;
+
+  while ((p = strchr(deps, ',')) != 0)
+    {
+      *p = 0;
+      olddeps = makedeps(repo, deps, olddeps, marker);
+      *p = ',';
+      deps = p + 1;
+    }
+  id = parseonedep(pool, deps);
+  if (!id)
+    return olddeps;
+  return repo_addid_dep(repo, olddeps, id, marker);
+}
+
+
+/* put data from control file into the solvable */
+/* warning: does inplace changes */
+static void
+control2solvable(Solvable *s, Repodata *data, char *control)
+{
+  Repo *repo = s->repo;
+  Pool *pool = repo->pool;
+  char *p, *q, *end, *tag;
+  int x, l;
+  int havesource = 0;
+  char checksum[32 * 2 + 1];
+  Id checksumtype = 0;
+  Id newtype;
+
+  p = control;
+  while (*p)
+    {
+      p = strchr(p, '\n');
+      if (!p)
+       break;
+      if (p[1] == ' ' || p[1] == '\t')
+       {
+         char *q;
+         /* continuation line */
+         q = p - 1;
+         while (q >= control && *q == ' ' && *q == '\t')
+           q--;
+         l = q + 1 - control;
+         if (l)
+           memmove(p + 1 - l, control, l);
+         control = p + 1 - l;
+         p[1] = '\n';
+         p += 2;
+         continue;
+       }
+      end = p - 1;
+      if (*p)
+        *p++ = 0;
+      /* strip trailing space */
+      while (end >= control && (*end == ' ' || *end == '\t'))
+       *end-- = 0;
+      tag = control;
+      control = p;
+      q = strchr(tag, ':');
+      if (!q || q - tag < 4)
+       continue;
+      *q++ = 0;
+      while (*q == ' ' || *q == '\t')
+       q++;
+      x = '@' + (tag[0] & 0x1f);
+      x = (x << 8) + '@' + (tag[1] & 0x1f);
+      switch(x)
+       {
+       case 'A' << 8 | 'R':
+         if (!strcasecmp(tag, "architecture"))
+           s->arch = pool_str2id(pool, q, 1);
+         break;
+       case 'B' << 8 | 'R':
+         if (!strcasecmp(tag, "breaks"))
+           s->conflicts = makedeps(repo, q, s->conflicts, 0);
+         break;
+       case 'C' << 8 | 'O':
+         if (!strcasecmp(tag, "conflicts"))
+           s->conflicts = makedeps(repo, q, s->conflicts, 0);
+         break;
+       case 'D' << 8 | 'E':
+         if (!strcasecmp(tag, "depends"))
+           s->requires = makedeps(repo, q, s->requires, -SOLVABLE_PREREQMARKER);
+         else if (!strcasecmp(tag, "description"))
+           {
+             char *ld = strchr(q, '\n');
+             if (ld)
+               {
+                 *ld++ = 0;
+                 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, ld);
+               }
+             else
+               repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, q);
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, q);
+           }
+         break;
+       case 'E' << 8 | 'N':
+         if (!strcasecmp(tag, "enhances"))
+           s->enhances = makedeps(repo, q, s->enhances, 0);
+         break;
+       case 'F' << 8 | 'I':
+         if (!strcasecmp(tag, "filename"))
+           repodata_set_location(data, s - pool->solvables, 0, 0, q);
+         break;
+       case 'H' << 8 | 'O':
+         if (!strcasecmp(tag, "homepage"))
+           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
+         break;
+       case 'I' << 8 | 'N':
+         if (!strcasecmp(tag, "installed-size"))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10);
+         break;
+       case 'M' << 8 | 'D':
+         if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
+           {
+             strcpy(checksum, q);
+             checksumtype = REPOKEY_TYPE_MD5;
+           }
+         break;
+       case 'P' << 8 | 'A':
+         if (!strcasecmp(tag, "package"))
+           s->name = pool_str2id(pool, q, 1);
+         break;
+       case 'P' << 8 | 'R':
+         if (!strcasecmp(tag, "pre-depends"))
+           s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER);
+         else if (!strcasecmp(tag, "provides"))
+           s->provides = makedeps(repo, q, s->provides, 0);
+         break;
+       case 'R' << 8 | 'E':
+         if (!strcasecmp(tag, "replaces"))
+           s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
+         else if (!strcasecmp(tag, "recommends"))
+           s->recommends = makedeps(repo, q, s->recommends, 0);
+         break;
+       case 'S' << 8 | 'H':
+         newtype = solv_chksum_str2type(tag);
+         if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
+           break;
+         if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
+           {
+             strcpy(checksum, q);
+             checksumtype = newtype;
+           }
+         break;
+       case 'S' << 8 | 'O':
+         if (!strcasecmp(tag, "source"))
+           {
+             char *q2;
+             /* ignore version for now */
+             for (q2 = q; *q2; q2++)
+               if (*q2 == ' ' || *q2 == '\t')
+                 {
+                   *q2 = 0;
+                   break;
+                 }
+             if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
+               repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+             else
+               repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
+             havesource = 1;
+           }
+         break;
+       case 'S' << 8 | 'T':
+         if (!strcasecmp(tag, "status"))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
+         break;
+       case 'S' << 8 | 'U':
+         if (!strcasecmp(tag, "suggests"))
+           s->suggests = makedeps(repo, q, s->suggests, 0);
+         break;
+       case 'V' << 8 | 'E':
+         if (!strcasecmp(tag, "version"))
+           s->evr = pool_str2id(pool, q, 1);
+         break;
+       }
+    }
+  if (checksumtype)
+    repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
+  if (!s->arch)
+    s->arch = ARCH_ALL;
+  if (!s->evr)
+    s->evr = ID_EMPTY;
+  if (s->name)
+    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+  if (s->name && !havesource)
+    repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+  if (s->obsoletes)
+    {
+      /* obsoletes only count when the packages also conflict */
+      /* XXX: should not transcode here */
+      int i, j, k;
+      Id d, cid;
+      for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
+       {
+         if (!s->conflicts)
+           continue;
+         for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
+           {
+             if (repo->idarraydata[k] == cid)
+               break;
+             if (ISRELDEP(cid))
+               {
+                 Reldep *rd = GETRELDEP(pool, cid);
+                 if (rd->flags < 8 && rd->name == d)
+                   break;      /* specialize obsoletes */
+               }
+           }
+         if (cid)
+           repo->idarraydata[j++] = cid;
+       }
+      repo->idarraydata[j] = 0;
+      if (j == s->obsoletes)
+       s->obsoletes = 0;
+    }
+}
+
+int
+repo_add_debpackages(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  char *buf, *p;
+  int bufl, l, ll;
+  Solvable *s;
+
+  data = repo_add_repodata(repo, flags);
+  buf = solv_malloc(4096);
+  bufl = 4096;
+  l = 0;
+  buf[l] = 0;
+  p = buf;
+  for (;;)
+    {
+      if (!(p = strchr(p, '\n')))
+       {
+         int l3;
+         while (l + 1024 >= bufl)
+           {
+             buf = solv_realloc(buf, bufl + 4096);
+             bufl += 4096;
+           }
+         p = buf + l;
+         ll = fread(p, 1, bufl - l - 1, fp);
+         if (ll <= 0)
+           break;
+         p[ll] = 0;
+         while ((l3 = strlen(p)) < ll)
+           p[l3] = '\n';
+         l += ll;
+         if (p != buf)
+           p--;
+         continue;
+       }
+      p++;
+      if (*p != '\n')
+       continue;
+      *p = 0;
+      ll = p - buf + 1;
+      s = pool_id2solvable(pool, repo_add_solvable(repo));
+      control2solvable(s, data, buf);
+      if (!s->name)
+       s = solvable_free(s, 1);
+      if (l > ll)
+        memmove(buf, p + 1, l - ll);
+      l -= ll;
+      p = buf;
+      buf[l] = 0;
+    }
+  if (l)
+    {
+      s = pool_id2solvable(pool, repo_add_solvable(repo));
+      control2solvable(s, data, buf);
+      if (!s->name)
+       s = solvable_free(s, 1);
+    }
+  solv_free(buf);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+int
+repo_add_debdb(Repo *repo, int flags)
+{
+  FILE *fp;
+  const char *path = "/var/lib/dpkg/status";
+  if (flags & REPO_USE_ROOTDIR)
+    path = pool_prepend_rootdir_tmp(repo->pool, path);
+  if ((fp = fopen(path, "r")) == 0)
+    return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
+  repo_add_debpackages(repo, fp, flags);
+  fclose(fp);
+  return 0;
+}
+
+#define CONTROL_COMP_NONE      0
+#define CONTROL_COMP_GZIP      1
+#define CONTROL_COMP_XZ                2
+
+Id
+repo_add_deb(Repo *repo, const char *deb, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  unsigned char buf[4096], *bp;
+  int l, l2, vlen, clen, ctarlen;
+  int control_comp;
+  unsigned char *ctgz;
+  unsigned char pkgid[16];
+  unsigned char *ctar;
+  int gotpkgid;
+  FILE *fp;
+  Solvable *s;
+  struct stat stb;
+
+  data = repo_add_repodata(repo, flags);
+  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
+    {
+      pool_error(pool, -1, "%s: %s", deb, strerror(errno));
+      return 0;
+    }
+  if (fstat(fileno(fp), &stb))
+    {
+      pool_error(pool, -1, "fstat: %s", strerror(errno));
+      fclose(fp);
+      return 0;
+    }
+  l = fread(buf, 1, sizeof(buf), fp);
+  if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/  ", 8 + 16) != 0))
+    {
+      pool_error(pool, -1, "%s: not a deb package", deb);
+      fclose(fp);
+      return 0;
+    }
+  vlen = atoi((char *)buf + 8 + 48);
+  if (vlen < 0 || vlen > l)
+    {
+      pool_error(pool, -1, "%s: not a deb package", deb);
+      fclose(fp);
+      return 0;
+    }
+  vlen += vlen & 1;
+  if (l < 8 + 60 + vlen + 60)
+    {
+      pool_error(pool, -1, "%s: unhandled deb package", deb);
+      fclose(fp);
+      return 0;
+    }
+  control_comp = 0;
+  if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
+    control_comp = CONTROL_COMP_GZIP;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
+    control_comp = CONTROL_COMP_XZ;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
+    control_comp = CONTROL_COMP_NONE;
+  else
+    {
+      pool_error(pool, -1, "%s: control.tar is not second entry", deb);
+      fclose(fp);
+      return 0;
+    }
+  /* dpkg has no actual maximum size for the control.tar member, so this
+   * just keeps from allocating arbitrarily large amounts of memory.
+   */
+  clen = atoi((char *)buf + 8 + 60 + vlen + 48);
+  if (clen <= 0 || clen >= 0x1000000)
+    {
+      pool_error(pool, -1, "%s: control.tar has illegal size", deb);
+      fclose(fp);
+      return 0;
+    }
+  ctgz = solv_calloc(1, clen + 4);
+  bp = buf + 8 + 60 + vlen + 60;
+  l -= 8 + 60 + vlen + 60;
+  if (l > clen)
+    l = clen;
+  if (l)
+    memcpy(ctgz, bp, l);
+  if (l < clen)
+    {
+      if (fread(ctgz + l, clen - l, 1, fp) != 1)
+       {
+         pool_error(pool, -1, "%s: unexpected EOF", deb);
+         solv_free(ctgz);
+         fclose(fp);
+         return 0;
+       }
+    }
+  fclose(fp);
+  gotpkgid = 0;
+  if (flags & DEBS_ADD_WITH_PKGID)
+    {
+      Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+      solv_chksum_add(chk, ctgz, clen);
+      solv_chksum_free(chk, pkgid);
+      gotpkgid = 1;
+    }
+  ctar = 0;
+  if (control_comp == CONTROL_COMP_GZIP)
+    ctar = decompress_gz(ctgz, clen, &ctarlen, 0x1000000);
+  else if (control_comp == CONTROL_COMP_XZ)
+    ctar = decompress_xz(ctgz, clen, &ctarlen, 0x1000000);
+  else
+    {
+      ctarlen = clen;
+      ctar = solv_memdup(ctgz, clen);
+    }
+  solv_free(ctgz);
+  if (!ctar)
+    {
+      pool_error(pool, -1, "%s: control.tar is corrupt", deb);
+      return 0;
+    }
+  bp = ctar;
+  l = ctarlen;
+  l2 = 0;
+  while (l > 512)
+    {
+      int j;
+      l2 = 0;
+      for (j = 124; j < 124 + 12; j++)
+       if (bp[j] >= '0' && bp[j] <= '7')
+         l2 = l2 * 8 + (bp[j] - '0');
+      if (l2 < 0 || l2 > l)
+       {
+         l2 = 0;
+         break;
+       }
+      bp[124] = 0;
+      if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
+       break;
+      l2 = 512 + ((l2 + 511) & ~511);
+      l -= l2;
+      bp += l2;
+    }
+  if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
+    {
+      pool_error(pool, -1, "%s: control.tar contains no control file", deb);
+      free(ctar);
+      return 0;
+    }
+  memmove(ctar, bp + 512, l2);
+  ctar = solv_realloc(ctar, l2 + 1);
+  ctar[l2] = 0;
+  s = pool_id2solvable(pool, repo_add_solvable(repo));
+  control2solvable(s, data, (char *)ctar);
+  if (!(flags & REPO_NO_LOCATION))
+    repodata_set_location(data, s - pool->solvables, 0, 0, deb);
+  if (S_ISREG(stb.st_mode))
+    repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
+  if (gotpkgid)
+    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
+  solv_free(ctar);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return s - pool->solvables;
+}
+
+void
+pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
+{
+  Id name = 0, arch = 0;
+  int autoinstalled = -1;
+  char *buf, *bp;
+  int x, l, bufl, eof = 0;
+  Id p, pp;
+
+  queue_empty(q);
+  buf = solv_malloc(4096);
+  bufl = 4096;
+  l = 0;
+  while (!eof)
+    {
+      while (bufl - l < 1024)
+       {
+         bufl += 4096;
+         if (bufl > 1024 * 64)
+           break;      /* hmm? */
+         buf = solv_realloc(buf, bufl);
+       }
+      if (!fgets(buf + l, bufl - l, fp))
+       {
+         eof = 1;
+         buf[l] = '\n';
+         buf[l + 1] = 0;
+       }
+      l = strlen(buf);
+      if (l && buf[l - 1] == '\n')
+       buf[--l] = 0;
+      if (!*buf || eof)
+       {
+         l = 0;
+         if (name && autoinstalled > 0)
+           {
+             if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+               queue_push2(q, name, arch);
+             else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+               queue_push(q, name);
+             else
+               {
+                 FOR_PROVIDES(p, pp, name)
+                   {
+                     Solvable *s = pool->solvables + p;
+                     if (s->name != name)
+                       continue;
+                     if (arch && s->arch != arch)
+                       continue;
+                     queue_push(q, p);
+                   }
+               }
+           }
+         name = arch = 0;
+         autoinstalled = -1;
+         continue;
+       }
+      /* strip trailing space */
+      while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+       buf[--l] = 0;
+      l = 0;
+
+      bp = strchr(buf, ':');
+      if (!bp || bp - buf < 4)
+       continue;
+      *bp++ = 0;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      x = '@' + (buf[0] & 0x1f);
+      x = (x << 8) + '@' + (buf[1] & 0x1f);
+      switch(x)
+       {
+       case 'P' << 8 | 'A':
+         if (!strcasecmp(buf, "package"))
+           name = pool_str2id(pool, bp, 1);
+         break;
+       case 'A' << 8 | 'R':
+         if (!strcasecmp(buf, "architecture"))
+           arch = pool_str2id(pool, bp, 1);
+         break;
+       case 'A' << 8 | 'U':
+         if (!strcasecmp(buf, "auto-installed"))
+           autoinstalled = atoi(bp);
+         break;
+       default:
+         break;
+       }
+    }
+}
+
diff --git a/libsolv-0.7.2/ext/repo_deb.h b/libsolv-0.7.2/ext/repo_deb.h
new file mode 100644 (file)
index 0000000..5993991
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_debpackages(Repo *repo, FILE *fp, int flags);
+extern int repo_add_debdb(Repo *repo, int flags);
+extern Id repo_add_deb(Repo *repo, const char *deb, int flags);
+extern void pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags);
+
+#define DEBS_ADD_WITH_PKGID    (1 << 8)
diff --git a/libsolv-0.7.2/ext/repo_deltainfoxml.c b/libsolv-0.7.2/ext/repo_deltainfoxml.c
new file mode 100644 (file)
index 0000000..ad315da
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "solv_xmlparser.h"
+#include "repo_deltainfoxml.h"
+
+/*
+ * <deltainfo>
+ *   <newpackage name="libtool" epoch="0" version="1.5.24" release="6.fc9" arch="i386">
+ *     <delta oldepoch="0" oldversion="1.5.24" oldrelease="3.fc8">
+ *       <filename>DRPMS/libtool-1.5.24-3.fc8_1.5.24-6.fc9.i386.drpm</filename>
+ *       <sequence>libtool-1.5.24-3.fc8-d3571f98b048b1a870e40241bb46c67ab4</sequence>
+ *       <size>22452</size>
+ *       <checksum type="sha">8f05394695dee9399c204614e21e5f6848990ab7</checksum>
+ *     </delta>
+ *     <delta oldepoch="0" oldversion="1.5.22" oldrelease="11.fc7">
+ *       <filename>DRPMS/libtool-1.5.22-11.fc7_1.5.24-6.fc9.i386.drpm</filename>
+ *        <sequence>libtool-1.5.22-11.fc7-e82691677eee1e83b4812572c5c9ce8eb</sequence>
+ *        <size>110362</size>
+ *        <checksum type="sha">326658fee45c0baec1e70231046dbaf560f941ce</checksum>
+ *      </delta>
+ *    </newpackage>
+ *  </deltainfo>
+ */
+
+enum state {
+  STATE_START,
+  STATE_NEWPACKAGE,     /* 1 */
+  STATE_DELTA,          /* 2 */
+  STATE_FILENAME,       /* 3 */
+  STATE_SEQUENCE,       /* 4 */
+  STATE_SIZE,           /* 5 */
+  STATE_CHECKSUM,       /* 6 */
+  STATE_LOCATION,       /* 7 */
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  /* compatibility with old yum-presto */
+  { STATE_START,       "prestodelta",     STATE_START, 0 },
+  { STATE_START,       "deltainfo",       STATE_START, 0 },
+  { STATE_START,       "newpackage",      STATE_NEWPACKAGE,  0 },
+  { STATE_NEWPACKAGE,  "delta",           STATE_DELTA,       0 },
+  /* compatibility with yum-presto */
+  { STATE_DELTA,       "filename",        STATE_FILENAME,    1 },
+  { STATE_DELTA,       "location",        STATE_LOCATION,    0 },
+  { STATE_DELTA,       "sequence",        STATE_SEQUENCE,    1 },
+  { STATE_DELTA,       "size",            STATE_SIZE,        1 },
+  { STATE_DELTA,       "checksum",        STATE_CHECKSUM,    1 },
+  { NUMSTATES }
+};
+
+/* Cumulated info about the current deltarpm or patchrpm */
+struct deltarpm {
+  char *location;
+  char *locbase;
+  unsigned int buildtime;
+  unsigned long long downloadsize;
+  char *filechecksum;
+  int filechecksumtype;
+  /* Baseversion.  deltarpm only has one. */
+  Id *bevr;
+  unsigned nbevr;
+  Id seqname;
+  Id seqevr;
+  char *seqnum;
+};
+
+struct parsedata {
+  int ret;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+
+  struct deltarpm delta;
+  Id newpkgevr;
+  Id newpkgname;
+  Id newpkgarch;
+
+  Id *handles;
+  int nhandles;
+
+  struct solv_xmlparser xmlp;
+};
+
+
+/*
+ * create evr (as Id) from 'epoch', 'version' and 'release' attributes
+ */
+
+static Id
+makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
+{
+  const char *e, *v, *r, *v2;
+  char *c, *space;
+  int l;
+
+  e = v = r = 0;
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, "oldepoch"))
+        e = atts[1];
+      else if (!strcmp(*atts, "epoch"))
+       e = atts[1];
+      else if (!strcmp(*atts, "version"))
+       v = atts[1];
+      else if (!strcmp(*atts, "oldversion"))
+       v = atts[1];
+      else if (!strcmp(*atts, "release"))
+       r = atts[1];
+      else if (!strcmp(*atts, "oldrelease"))
+       r = atts[1];
+    }
+  if (e && (!*e || !strcmp(e, "0")))
+    e = 0;
+  if (v && !e)
+    {
+      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
+        ;
+      if (v2 > v && *v2 == ':')
+       e = "0";
+    }
+  l = 1;
+  if (e)
+    l += strlen(e) + 1;
+  if (v)
+    l += strlen(v);
+  if (r)
+    l += strlen(r) + 1;
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
+  if (e)
+    {
+      strcpy(c, e);
+      c += strlen(c);
+      *c++ = ':';
+    }
+  if (v)
+    {
+      strcpy(c, v);
+      c += strlen(c);
+    }
+  if (r)
+    {
+      *c++ = '-';
+      strcpy(c, r);
+      c += strlen(c);
+    }
+  *c = 0;
+  if (!*space)
+    return 0;
+#if 0
+  fprintf(stderr, "evr: %s\n", space);
+#endif
+  return pool_str2id(pool, space, 1);
+}
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  const char *str;
+
+  switch(state)
+    {
+    case STATE_NEWPACKAGE:
+      if ((str = solv_xmlparser_find_attr("name", atts)) != 0)
+       pd->newpkgname = pool_str2id(pool, str, 1);
+      pd->newpkgevr = makeevr_atts(pool, pd, atts);
+      if ((str = solv_xmlparser_find_attr("arch", atts)) != 0)
+       pd->newpkgarch = pool_str2id(pool, str, 1);
+      break;
+
+    case STATE_DELTA:
+      memset(&pd->delta, 0, sizeof(pd->delta));
+      pd->delta.bevr = solv_extend(pd->delta.bevr, pd->delta.nbevr, 1, sizeof(Id), 7);
+      pd->delta.bevr[pd->delta.nbevr++] = makeevr_atts(pool, pd, atts);
+      break;
+
+    case STATE_FILENAME:
+      if ((str = solv_xmlparser_find_attr("xml:base", atts)))
+        pd->delta.locbase = solv_strdup(str);
+      break;
+
+    case STATE_LOCATION:
+      pd->delta.location = solv_strdup(solv_xmlparser_find_attr("href", atts));
+      if ((str = solv_xmlparser_find_attr("xml:base", atts)))
+        pd->delta.locbase = solv_strdup(str);
+      break;
+
+    case STATE_CHECKSUM:
+      pd->delta.filechecksum = 0;
+      pd->delta.filechecksumtype = REPOKEY_TYPE_SHA1;
+      if ((str = solv_xmlparser_find_attr("type", atts)) != 0)
+       {
+         pd->delta.filechecksumtype = solv_chksum_str2type(str);
+         if (!pd->delta.filechecksumtype)
+           pool_debug(pool, SOLV_ERROR, "unknown checksum type: '%s'\n", str);
+       }
+      break;
+
+    default:
+      break;
+    }
+}
+
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  const char *str;
+
+  switch (state)
+    {
+    case STATE_DELTA:
+      {
+       /* read all data for a deltarpm. commit into attributes */
+       Id handle;
+       struct deltarpm *d = &pd->delta;
+
+       handle = repodata_new_handle(pd->data);
+       /* we commit all handles later on in one go so that the
+         * repodata code doesn't need to realloc every time */
+       pd->handles = solv_extend(pd->handles, pd->nhandles, 1, sizeof(Id), 63);
+        pd->handles[pd->nhandles++] = handle;
+       repodata_set_id(pd->data, handle, DELTA_PACKAGE_NAME, pd->newpkgname);
+       repodata_set_id(pd->data, handle, DELTA_PACKAGE_EVR, pd->newpkgevr);
+       repodata_set_id(pd->data, handle, DELTA_PACKAGE_ARCH, pd->newpkgarch);
+       if (d->location)
+         {
+           repodata_set_deltalocation(pd->data, handle, 0, 0, d->location);
+           if (d->locbase)
+             repodata_set_poolstr(pd->data, handle, DELTA_LOCATION_BASE, d->locbase);
+         }
+       if (d->downloadsize)
+         repodata_set_num(pd->data, handle, DELTA_DOWNLOADSIZE, d->downloadsize);
+       if (d->filechecksum)
+         repodata_set_checksum(pd->data, handle, DELTA_CHECKSUM, d->filechecksumtype, d->filechecksum);
+       if (d->seqnum)
+         {
+           repodata_set_id(pd->data, handle, DELTA_BASE_EVR, d->bevr[0]);
+           repodata_set_id(pd->data, handle, DELTA_SEQ_NAME, d->seqname);
+           repodata_set_id(pd->data, handle, DELTA_SEQ_EVR, d->seqevr);
+           /* should store as binary blob! */
+           repodata_set_str(pd->data, handle, DELTA_SEQ_NUM, d->seqnum);
+         }
+      }
+      pd->delta.filechecksum = solv_free(pd->delta.filechecksum);
+      pd->delta.bevr = solv_free(pd->delta.bevr);
+      pd->delta.nbevr = 0;
+      pd->delta.seqnum = solv_free(pd->delta.seqnum);
+      pd->delta.location = solv_free(pd->delta.location);
+      pd->delta.locbase = solv_free(pd->delta.locbase);
+      break;
+    case STATE_FILENAME:
+      pd->delta.location = solv_strdup(content);
+      break;
+    case STATE_CHECKSUM:
+      pd->delta.filechecksum = solv_strdup(content);
+      break;
+    case STATE_SIZE:
+      pd->delta.downloadsize = strtoull(content, 0, 10);
+      break;
+    case STATE_SEQUENCE:
+      if ((str = content) != 0)
+       {
+         const char *s1, *s2;
+         s1 = strrchr(str, '-');
+         if (s1)
+           {
+             for (s2 = s1 - 1; s2 > str; s2--)
+               if (*s2 == '-')
+                 break;
+             if (*s2 == '-')
+               {
+                 for (s2 = s2 - 1; s2 > str; s2--)
+                   if (*s2 == '-')
+                     break;
+                 if (*s2 == '-')
+                   {
+                     pd->delta.seqevr = pool_strn2id(pool, s2 + 1, s1 - s2 - 1, 1);
+                     pd->delta.seqname = pool_strn2id(pool, str, s2 - str, 1);
+                     str = s1 + 1;
+                   }
+               }
+           }
+         pd->delta.seqnum = solv_strdup(str);
+      }
+    default:
+      break;
+    }
+}
+
+int
+repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  struct parsedata pd;
+  int i;
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+     pd.ret = pool_error(pd.pool, -1, "repo_deltainfoxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+
+  /* now commit all handles */
+  if (!pd.ret)
+    for (i = 0; i < pd.nhandles; i++)
+      repodata_add_flexarray(pd.data, SOLVID_META, REPOSITORY_DELTAINFO, pd.handles[i]);
+  solv_free(pd.handles);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return pd.ret;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/ext/repo_deltainfoxml.h b/libsolv-0.7.2/ext/repo_deltainfoxml.h
new file mode 100644 (file)
index 0000000..6647b15
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.7.2/ext/repo_haiku.cpp b/libsolv-0.7.2/ext/repo_haiku.cpp
new file mode 100644 (file)
index 0000000..a624df1
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2011-2013, Ingo Weinhold <ingo_weinhold@gmx.de>
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <package/PackageInfo.h>
+#include <package/PackageInfoSet.h>
+#include <package/PackageRoster.h>
+#include <package/PackageVersion.h>
+#include <package/RepositoryCache.h>
+#include <package/RepositoryConfig.h>
+
+#include "repo_haiku.h"
+
+using namespace BPackageKit;
+using namespace BPackageKit::BHPKG;
+
+static void add_dependency(Repo *repo, Offset &dependencies, const char *name,
+  const char *version, int flags, const char* compatVersion = NULL)
+{
+  Pool *pool = repo->pool;
+
+  Id dependency = pool_str2id(pool, name, 1);
+
+  if (version && version[0] != '\0')
+  {
+    Id versionId = pool_str2id(pool, version, 1);
+
+    if (compatVersion && compatVersion[0] != '\0')
+      {
+        versionId = pool_rel2id(pool, versionId, pool_str2id(pool, compatVersion, 1),
+          REL_COMPAT, 1);
+      }
+
+    dependency = pool_rel2id(pool, dependency, versionId, flags, 1);
+  }
+
+  dependencies = repo_addid_dep(repo, dependencies, dependency, 0);
+}
+
+static void add_dependency(Repo *repo, Offset &dependencies, const char *name,
+  const BPackageVersion &version, int flags)
+{
+  add_dependency(repo, dependencies, name, version.ToString(),
+    flags);
+}
+
+static void add_resolvables(Repo *repo, Offset &dependencies,
+  const BObjectList<BPackageResolvable> &resolvables)
+{
+  for (int32 i = 0; BPackageResolvable *resolvable = resolvables.ItemAt(i); i++)
+    {
+      add_dependency(repo, dependencies, resolvable->Name(),
+        resolvable->Version().ToString(), REL_EQ,
+        resolvable->CompatibleVersion().ToString());
+    }
+}
+
+static void add_resolvable_expressions(Repo *repo, Offset &dependencies,
+  const BObjectList<BPackageResolvableExpression> &expressions)
+{
+  for (int32 i = 0;
+    BPackageResolvableExpression *expression = expressions.ItemAt(i); i++)
+    {
+      // It is possible that no version is specified. In that case any version
+      // is acceptable.
+      if (expression->Version().InitCheck() != B_OK)
+        {
+          BPackageVersion version;
+          add_dependency(repo, dependencies, expression->Name(), NULL, 0);
+          continue;
+        }
+
+      int flags = 0;
+      switch (expression->Operator())
+        {
+          case B_PACKAGE_RESOLVABLE_OP_LESS:
+            flags |= REL_LT;
+            break;
+          case B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL:
+            flags |= REL_LT | REL_EQ;
+            break;
+          case B_PACKAGE_RESOLVABLE_OP_EQUAL:
+            flags |= REL_EQ;
+            break;
+          case B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL:
+            break;
+          case B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL:
+            flags |= REL_GT | REL_EQ;
+            break;
+          case B_PACKAGE_RESOLVABLE_OP_GREATER:
+              flags |= REL_GT;
+            break;
+        }
+
+      add_dependency(repo, dependencies, expression->Name(),
+        expression->Version(), flags);
+    }
+}
+
+static void add_replaces_list(Repo *repo, Offset &dependencies,
+  const BStringList &packageNames)
+{
+  int32 count = packageNames.CountStrings();
+  for (int32 i = 0; i < count; i++)
+    {
+      const BString &packageName = packageNames.StringAt(i);
+      add_dependency(repo, dependencies, packageName, BPackageVersion(), 0);
+    }
+}
+
+static Id add_package_info_to_repo(Repo *repo, Repodata *repoData,
+  const BPackageInfo &packageInfo)
+{
+  Pool *pool = repo->pool;
+
+  Id solvableId = repo_add_solvable(repo);
+  Solvable *solvable = pool_id2solvable(pool, solvableId);
+  // Prepend "pkg:" to package name, so "provides" don't match unless explicitly
+  // specified this way.
+  BString name("pkg:");
+  name << packageInfo.Name();
+  solvable->name = pool_str2id(pool, name, 1);
+  if (packageInfo.Architecture() == B_PACKAGE_ARCHITECTURE_ANY)
+    solvable->arch = ARCH_ANY;
+  else if (packageInfo.Architecture() == B_PACKAGE_ARCHITECTURE_SOURCE)
+    solvable->arch = ARCH_SRC;
+  else
+    solvable->arch = pool_str2id(pool,
+      BPackageInfo::kArchitectureNames[packageInfo.Architecture()], 1);
+  solvable->evr = pool_str2id(pool, packageInfo.Version().ToString(), 1);
+  solvable->vendor = pool_str2id(pool, packageInfo.Vendor(), 1);
+  repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_SUMMARY,
+    packageInfo.Summary());
+  repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_DESCRIPTION,
+    packageInfo.Description());
+  repodata_set_str(repoData, solvable - pool->solvables, SOLVABLE_PACKAGER,
+    packageInfo.Packager());
+
+  if (!packageInfo.Checksum().IsEmpty())
+    repodata_set_checksum(repoData, solvable - pool->solvables,
+      SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, packageInfo.Checksum());
+
+  solvable->provides = repo_addid_dep(repo, solvable->provides,
+    pool_rel2id(pool, solvable->name, solvable->evr, REL_EQ, 1), 0);
+
+  add_resolvables(repo, solvable->provides, packageInfo.ProvidesList());
+  add_resolvable_expressions(repo, solvable->requires,
+    packageInfo.RequiresList());
+  add_resolvable_expressions(repo, solvable->supplements,
+    packageInfo.SupplementsList());
+  add_resolvable_expressions(repo, solvable->conflicts,
+    packageInfo.ConflictsList());
+  add_resolvable_expressions(repo, solvable->enhances,
+    packageInfo.FreshensList());
+  add_replaces_list(repo, solvable->obsoletes, packageInfo.ReplacesList());
+  // TODO: Check whether freshens and replaces does indeed work as intended
+  // here.
+
+  // TODO: copyrights, licenses, URLs, source URLs
+
+  return solvableId;
+}
+
+static void add_installed_packages(Repo *repo, Repodata *repoData,
+  BPackageInstallationLocation location)
+{
+  BPackageRoster roster;
+  BPackageInfoSet packageInfos;
+  if (roster.GetActivePackages(location, packageInfos) == B_OK)
+    {
+      BRepositoryCache::Iterator it = packageInfos.GetIterator();
+      while (const BPackageInfo *packageInfo = it.Next())
+        add_package_info_to_repo(repo, repoData, *packageInfo);
+    }
+}
+
+int repo_add_haiku_installed_packages(Repo *repo, const char *rootdir,
+  int flags)
+{
+  Repodata *repoData = repo_add_repodata(repo, flags);
+
+  add_installed_packages(repo, repoData,
+    B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
+  add_installed_packages(repo, repoData, B_PACKAGE_INSTALLATION_LOCATION_HOME);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(repoData);
+
+  return 0;
+}
+
+Id repo_add_haiku_package(Repo *repo, const char *hpkgPath, int flags)
+{
+  BPackageInfo packageInfo;
+  if (packageInfo.ReadFromPackageFile(hpkgPath) != B_OK)
+    return 0;
+
+  return repo_add_haiku_package_info(repo, packageInfo, flags);
+}
+
+int repo_add_haiku_packages(Repo *repo, const char *repoName, int flags)
+{
+  BPackageRoster roster;
+  BRepositoryCache cache;
+  if (roster.GetRepositoryCache(repoName, &cache) != B_OK)
+    return 0;
+
+  Repodata *repoData = repo_add_repodata(repo, flags);
+
+  BRepositoryCache::Iterator it = cache.GetIterator();
+  while (const BPackageInfo *packageInfo = it.Next())
+    add_package_info_to_repo(repo, repoData, *packageInfo);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(repoData);
+
+  return 0;
+}
+
+Id repo_add_haiku_package_info(Repo *repo,
+  const BPackageKit::BPackageInfo &packageInfo, int flags)
+{
+  if (packageInfo.InitCheck() != B_OK)
+    return 0;
+  
+  Repodata *repoData = repo_add_repodata(repo, flags);
+
+  Id id = add_package_info_to_repo(repo, repoData, packageInfo);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(repoData);
+
+  return id;
+}
diff --git a/libsolv-0.7.2/ext/repo_haiku.h b/libsolv-0.7.2/ext/repo_haiku.h
new file mode 100644 (file)
index 0000000..6770666
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2011-2013, Ingo Weinhold <ingo_weinhold@gmx.de>
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+#ifndef REPO_HAIKU_H
+#define REPO_HAIKU_H
+
+#include "repo.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int repo_add_haiku_installed_packages(Repo *repo, const char *rootdir,
+  int flags);
+Id repo_add_haiku_package(Repo *repo, const char *hpkgPath, int flags);
+int repo_add_haiku_packages(Repo *repo, const char *repoName, int flags);
+
+#ifdef __cplusplus
+
+namespace BPackageKit {
+  class BPackageInfo;
+}
+
+Id repo_add_haiku_package_info(Repo *repo,
+  const BPackageKit::BPackageInfo &packageInfo, int flags);
+
+} /* extern "C" */
+
+#endif /*__cplusplus*/
+
+#endif /* REPO_HAIKU_H */
diff --git a/libsolv-0.7.2/ext/repo_helix.c b/libsolv-0.7.2/ext/repo_helix.c
new file mode 100644 (file)
index 0000000..37359bb
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_helix.c
+ *
+ * Parse 'helix' XML representation
+ * and create 'repo'
+ *
+ * A bit of history: "Helix Code" was the name of the company that
+ * wrote Red Carpet. The company was later renamed to Ximian.
+ * The Red Carpet solver was merged into the ZYPP project, the
+ * library used both by ZENworks and YaST for package management.
+ * Red Carpet came with solver testcases in its own repository
+ * format, the 'helix' format.
+ *
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "queue.h"
+#include "solv_xmlparser.h"
+#include "repo_helix.h"
+#include "evr.h"
+
+
+/* XML parser states */
+
+enum state {
+  STATE_START,
+  STATE_CHANNEL,
+  STATE_SUBCHANNEL,
+  STATE_PACKAGE,
+  STATE_NAME,
+  STATE_VENDOR,
+  STATE_BUILDTIME,
+  STATE_HISTORY,
+  STATE_UPDATE,
+  STATE_EPOCH,
+  STATE_VERSION,
+  STATE_RELEASE,
+  STATE_ARCH,
+  STATE_PROVIDES,
+  STATE_PROVIDESENTRY,
+  STATE_REQUIRES,
+  STATE_REQUIRESENTRY,
+  STATE_PREREQUIRES,
+  STATE_PREREQUIRESENTRY,
+  STATE_OBSOLETES,
+  STATE_OBSOLETESENTRY,
+  STATE_CONFLICTS,
+  STATE_CONFLICTSENTRY,
+  STATE_RECOMMENDS,
+  STATE_RECOMMENDSENTRY,
+  STATE_SUPPLEMENTS,
+  STATE_SUPPLEMENTSENTRY,
+  STATE_SUGGESTS,
+  STATE_SUGGESTSENTRY,
+  STATE_ENHANCES,
+  STATE_ENHANCESENTRY,
+  STATE_FRESHENS,
+  STATE_FRESHENSENTRY,
+
+  STATE_SELECTTION,
+  STATE_PATTERN,
+  STATE_ATOM,
+  STATE_PATCH,
+  STATE_PRODUCT,
+
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START,       "channel",         STATE_CHANNEL, 0 },
+  { STATE_CHANNEL,     "subchannel",      STATE_SUBCHANNEL, 0 },
+  { STATE_SUBCHANNEL,  "package",         STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "srcpackage",      STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "selection",       STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "pattern",         STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "atom",            STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "patch",           STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "product",         STATE_PACKAGE, 0 },
+  { STATE_SUBCHANNEL,  "application",     STATE_PACKAGE, 0 },
+  { STATE_PACKAGE,     "name",            STATE_NAME, 1 },
+  { STATE_PACKAGE,     "vendor",          STATE_VENDOR, 1 },
+  { STATE_PACKAGE,     "buildtime",       STATE_BUILDTIME, 1 },
+  { STATE_PACKAGE,     "epoch",           STATE_EPOCH, 1 },
+  { STATE_PACKAGE,     "version",         STATE_VERSION, 1 },
+  { STATE_PACKAGE,     "release",         STATE_RELEASE, 1 },
+  { STATE_PACKAGE,     "arch",            STATE_ARCH, 1 },
+  { STATE_PACKAGE,     "history",         STATE_HISTORY, 0 },
+  { STATE_PACKAGE,     "provides",        STATE_PROVIDES, 0 },
+  { STATE_PACKAGE,     "requires",        STATE_REQUIRES, 0 },
+  { STATE_PACKAGE,     "prerequires",     STATE_PREREQUIRES, 0 },
+  { STATE_PACKAGE,     "obsoletes",       STATE_OBSOLETES , 0 },
+  { STATE_PACKAGE,     "conflicts",       STATE_CONFLICTS , 0 },
+  { STATE_PACKAGE,     "recommends" ,     STATE_RECOMMENDS , 0 },
+  { STATE_PACKAGE,     "supplements",     STATE_SUPPLEMENTS, 0 },
+  { STATE_PACKAGE,     "suggests",        STATE_SUGGESTS, 0 },
+  { STATE_PACKAGE,     "enhances",        STATE_ENHANCES, 0 },
+  { STATE_PACKAGE,     "freshens",        STATE_FRESHENS, 0 },
+  { STATE_PACKAGE,     "deps",            STATE_PACKAGE, 0 },  /* ignore deps element */
+
+  { STATE_HISTORY,     "update",          STATE_UPDATE, 0 },
+  { STATE_UPDATE,      "epoch",           STATE_EPOCH, 1 },
+  { STATE_UPDATE,      "version",         STATE_VERSION, 1 },
+  { STATE_UPDATE,      "release",         STATE_RELEASE, 1 },
+  { STATE_UPDATE,      "arch",            STATE_ARCH, 1 },
+
+  { STATE_PROVIDES,    "dep",             STATE_PROVIDESENTRY, 0 },
+  { STATE_REQUIRES,    "dep",             STATE_REQUIRESENTRY, 0 },
+  { STATE_PREREQUIRES, "dep",             STATE_PREREQUIRESENTRY, 0 },
+  { STATE_OBSOLETES,   "dep",             STATE_OBSOLETESENTRY, 0 },
+  { STATE_CONFLICTS,   "dep",             STATE_CONFLICTSENTRY, 0 },
+  { STATE_RECOMMENDS,  "dep",             STATE_RECOMMENDSENTRY, 0 },
+  { STATE_SUPPLEMENTS, "dep",             STATE_SUPPLEMENTSENTRY, 0 },
+  { STATE_SUGGESTS,    "dep",             STATE_SUGGESTSENTRY, 0 },
+  { STATE_ENHANCES,    "dep",             STATE_ENHANCESENTRY, 0 },
+  { STATE_FRESHENS,    "dep",             STATE_FRESHENSENTRY, 0 },
+  { NUMSTATES }
+
+};
+
+/*
+ * parser data
+ */
+
+struct parsedata {
+  int ret;
+  /* repo data */
+  Pool *pool;          /* current pool */
+  Repo *repo;          /* current repo */
+  Repodata *data;       /* current repo data */
+  Solvable *solvable;  /* current solvable */
+  Offset freshens;     /* current freshens vector */
+
+  /* package data */
+  int  srcpackage;     /* is srcpackage element */
+  int  epoch;          /* epoch (as offset into evrspace) */
+  int  version;                /* version (as offset into evrspace) */
+  int  release;                /* release (as offset into evrspace) */
+  char *evrspace;      /* buffer for evr */
+  int  aevrspace;      /* actual buffer space */
+  int  levrspace;      /* actual evr length */
+  char *kind;
+
+  struct solv_xmlparser xmlp;
+};
+
+
+/*------------------------------------------------------------------*/
+/* E:V-R handling */
+
+/* create Id from epoch:version-release */
+
+static Id
+evr2id(Pool *pool, struct parsedata *pd, const char *e, const char *v, const char *r)
+{
+  char *c, *space;
+  int l;
+
+  /* treat explitcit 0 as NULL */
+  if (e && (!*e || !strcmp(e, "0")))
+    e = 0;
+
+  if (v && !e)
+    {
+      const char *v2;
+      /* scan version for ":" */
+      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)     /* skip leading digits */
+        ;
+      /* if version contains ":", set epoch to "0" */
+      if (v2 > v && *v2 == ':')
+       e = "0";
+    }
+
+  /* compute length of Id string */
+  l = 1;  /* for the \0 */
+  if (e)
+    l += strlen(e) + 1;  /* e: */
+  if (v)
+    l += strlen(v);      /* v */
+  if (r)
+    l += strlen(r) + 1;  /* -r */
+
+  /* get content space */
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
+
+  /* copy e-v-r */
+  if (e)
+    {
+      strcpy(c, e);
+      c += strlen(c);
+      *c++ = ':';
+    }
+  if (v)
+    {
+      strcpy(c, v);
+      c += strlen(c);
+    }
+  if (r)
+    {
+      *c++ = '-';
+      strcpy(c, r);
+      c += strlen(c);
+    }
+  *c = 0;
+  /* if nothing inserted, return Id 0 */
+  if (!*space)
+    return 0;
+#if 0
+  fprintf(stderr, "evr: %s\n", space);
+#endif
+  /* intern and create */
+  return pool_str2id(pool, space, 1);
+}
+
+
+/* create e:v-r from attributes
+ * atts is array of name,value pairs, NULL at end
+ *   even index into atts is name
+ *   odd index is value
+ */
+static Id
+evr_atts2id(Pool *pool, struct parsedata *pd, const char **atts)
+{
+  const char *e, *v, *r;
+  e = v = r = 0;
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, "epoch"))
+       e = atts[1];
+      else if (!strcmp(*atts, "version"))
+       v = atts[1];
+      else if (!strcmp(*atts, "release"))
+       r = atts[1];
+    }
+  return evr2id(pool, pd, e, v, r);
+}
+
+/*------------------------------------------------------------------*/
+/* rel operator handling */
+
+struct flagtab {
+  char *from;
+  int to;
+};
+
+static struct flagtab flagtab[] = {
+  { ">",  REL_GT },
+  { "=",  REL_EQ },
+  { ">=", REL_GT|REL_EQ },
+  { "<",  REL_LT },
+  { "!=", REL_GT|REL_LT },
+  { "<=", REL_LT|REL_EQ },
+  { "(any)", REL_LT|REL_EQ|REL_GT },
+  { "==", REL_EQ },
+  { "gt", REL_GT },
+  { "eq", REL_EQ },
+  { "ge", REL_GT|REL_EQ },
+  { "lt", REL_LT },
+  { "ne", REL_GT|REL_LT },
+  { "le", REL_LT|REL_EQ },
+  { "gte", REL_GT|REL_EQ },
+  { "lte", REL_LT|REL_EQ },
+  { "GT", REL_GT },
+  { "EQ", REL_EQ },
+  { "GE", REL_GT|REL_EQ },
+  { "LT", REL_LT },
+  { "NE", REL_GT|REL_LT },
+  { "LE", REL_LT|REL_EQ }
+};
+
+/*
+ * process new dependency from parser
+ *  olddeps = already collected deps, this defines the 'kind' of dep
+ *  atts = array of name,value attributes of dep
+ *  isreq == 1 if its a requires
+ */
+
+static unsigned int
+adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, Id marker)
+{
+  Id id, name;
+  const char *n, *f, *k;
+  const char **a;
+
+  n = f = k = NULL;
+
+  /* loop over name,value pairs */
+  for (a = atts; *a; a += 2)
+    {
+      if (!strcmp(*a, "name"))
+       n = a[1];
+      if (!strcmp(*a, "kind"))
+       k = a[1];
+      else if (!strcmp(*a, "op"))
+       f = a[1];
+      else if (marker && !strcmp(*a, "pre") && a[1][0] == '1')
+        marker = SOLVABLE_PREREQMARKER;
+    }
+  if (!n)                             /* quit if no name found */
+    return olddeps;
+
+  /* kind, name */
+  if (k && !strcmp(k, "package"))
+    k = NULL;                         /* package is default */
+
+  if (k)                              /* if kind!=package, intern <kind>:<name> */
+    {
+      int l = strlen(k) + 1 + strlen(n) + 1;
+      char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
+      sprintf(space, "%s:%s", k, n);
+      name = pool_str2id(pool, space, 1);
+    }
+  else
+    {
+      name = pool_str2id(pool, n, 1);       /* package: just intern <name> */
+    }
+
+  if (f)                              /* operator ? */
+    {
+      /* intern e:v-r */
+      Id evr = evr_atts2id(pool, pd, atts);
+      /* parser operator to flags */
+      int flags;
+      for (flags = 0; flags < sizeof(flagtab)/sizeof(*flagtab); flags++)
+       if (!strcmp(f, flagtab[flags].from))
+         {
+           flags = flagtab[flags].to;
+           break;
+         }
+      if (flags > 7)
+       flags = 0;
+      /* intern rel */
+      id = pool_rel2id(pool, name, evr, flags, 1);
+    }
+  else
+    id = name;                        /* no operator */
+
+  /* add new dependency to repo */
+  return repo_addid_dep(pd->repo, olddeps, id, marker);
+}
+
+
+/*----------------------------------------------------------------*/
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+
+  switch (state)
+    {
+
+    case STATE_NAME:
+      if (pd->kind)                   /* if kind is set (non package) */
+        {
+          strcpy(xmlp->content, pd->kind);
+          xmlp->lcontent = strlen(xmlp->content);
+         xmlp->content[xmlp->lcontent++] = ':';   /* prefix name with '<kind>:' */
+         xmlp->content[xmlp->lcontent] = 0;
+       }
+      break;
+
+    case STATE_PACKAGE:                       /* solvable name */
+      pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+      pd->srcpackage = 0;
+      pd->kind = NULL;                /* default is (src)package */
+      if (!strcmp(name, "selection"))
+        pd->kind = "selection";
+      else if (!strcmp(name, "pattern"))
+        pd->kind = "pattern";
+      else if (!strcmp(name, "atom"))
+        pd->kind = "atom";
+      else if (!strcmp(name, "product"))
+        pd->kind = "product";
+      else if (!strcmp(name, "patch"))
+        pd->kind = "patch";
+      else if (!strcmp(name, "application"))
+        pd->kind = "application";
+      else if (!strcmp(name, "srcpackage"))
+       pd->srcpackage = 1;
+      pd->levrspace = 1;
+      pd->epoch = 0;
+      pd->version = 0;
+      pd->release = 0;
+      pd->freshens = 0;
+#if 0
+      fprintf(stderr, "package #%d\n", s - pool->solvables);
+#endif
+      break;
+
+    case STATE_UPDATE:
+      pd->levrspace = 1;
+      pd->epoch = 0;
+      pd->version = 0;
+      pd->release = 0;
+      break;
+
+    case STATE_PROVIDES:              /* start of provides */
+      s->provides = 0;
+      break;
+    case STATE_PROVIDESENTRY:         /* entry within provides */
+      s->provides = adddep(pool, pd, s->provides, atts, 0);
+      break;
+    case STATE_REQUIRESENTRY:
+      s->requires = adddep(pool, pd, s->requires, atts, -SOLVABLE_PREREQMARKER);
+      break;
+    case STATE_PREREQUIRESENTRY:
+      s->requires = adddep(pool, pd, s->requires, atts, SOLVABLE_PREREQMARKER);
+      break;
+    case STATE_OBSOLETES:
+      s->obsoletes = 0;
+      break;
+    case STATE_OBSOLETESENTRY:
+      s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
+      break;
+    case STATE_CONFLICTS:
+      s->conflicts = 0;
+      break;
+    case STATE_CONFLICTSENTRY:
+      s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
+      break;
+    case STATE_RECOMMENDS:
+      s->recommends = 0;
+      break;
+    case STATE_RECOMMENDSENTRY:
+      s->recommends = adddep(pool, pd, s->recommends, atts, 0);
+      break;
+    case STATE_SUPPLEMENTS:
+      s->supplements= 0;
+      break;
+    case STATE_SUPPLEMENTSENTRY:
+      s->supplements = adddep(pool, pd, s->supplements, atts, 0);
+      break;
+    case STATE_SUGGESTS:
+      s->suggests = 0;
+      break;
+    case STATE_SUGGESTSENTRY:
+      s->suggests = adddep(pool, pd, s->suggests, atts, 0);
+      break;
+    case STATE_ENHANCES:
+      s->enhances = 0;
+      break;
+    case STATE_ENHANCESENTRY:
+      s->enhances = adddep(pool, pd, s->enhances, atts, 0);
+      break;
+    case STATE_FRESHENS:
+      pd->freshens = 0;
+      break;
+    case STATE_FRESHENSENTRY:
+      pd->freshens = adddep(pool, pd, pd->freshens, atts, 0);
+      break;
+    default:
+      break;
+    }
+}
+
+static const char *
+findKernelFlavor(struct parsedata *pd, Solvable *s)
+{
+  Pool *pool = pd->pool;
+  Id pid, *pidp;
+
+  if (s->provides)
+    {
+      pidp = pd->repo->idarraydata + s->provides;
+      while ((pid = *pidp++) != 0)
+       {
+         Reldep *prd;
+         const char *depname;
+
+         if (!ISRELDEP(pid))
+           continue;               /* wrong provides name */
+         prd = GETRELDEP(pool, pid);
+         depname = pool_id2str(pool, prd->name);
+         if (!strncmp(depname, "kernel-", 7))
+           return depname + 7;
+       }
+    }
+
+  if (s->requires)
+    {
+      pidp = pd->repo->idarraydata + s->requires;
+      while ((pid = *pidp++) != 0)
+       {
+         const char *depname;
+
+         if (!ISRELDEP(pid))
+           {
+             depname = pool_id2str(pool, pid);
+           }
+         else
+           {
+             Reldep *prd = GETRELDEP(pool, pid);
+             depname = pool_id2str(pool, prd->name);
+           }
+         if (!strncmp(depname, "kernel-", 7))
+           return depname + 7;
+       }
+    }
+
+  return 0;
+}
+
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+  Id evr;
+  unsigned int t = 0;
+  const char *flavor;
+
+  switch (state)
+    {
+
+    case STATE_PACKAGE:                       /* package complete */
+      if (pd->srcpackage && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->arch = ARCH_SRC;
+      if (!s->arch)                    /* default to "noarch" */
+       s->arch = ARCH_NOARCH;
+
+      if (!s->evr && pd->version)      /* set solvable evr */
+        s->evr = evr2id(pool, pd,
+                        pd->epoch   ? pd->evrspace + pd->epoch   : 0,
+                        pd->version ? pd->evrspace + pd->version : 0,
+                        pd->release ? pd->evrspace + pd->release : 0);
+      /* ensure self-provides */
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+        s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      repo_rewrite_suse_deps(s, pd->freshens);
+      pd->freshens = 0;
+
+      /* see bugzilla bnc#190163 */
+      flavor = findKernelFlavor(pd, s);
+      if (flavor)
+       {
+         char *cflavor = solv_strdup(flavor);  /* make pointer safe */
+
+         Id npr;
+         Id pid;
+
+         /* this is either a kernel package or a kmp */
+         if (s->provides)
+           {
+             Offset prov = s->provides;
+             npr = 0;
+             while ((pid = pd->repo->idarraydata[prov++]) != 0)
+               {
+                 const char *depname = 0;
+                 Reldep *prd = 0;
+
+                 if (ISRELDEP(pid))
+                   {
+                     prd = GETRELDEP(pool, pid);
+                     depname = pool_id2str(pool, prd->name);
+                   }
+                 else
+                   {
+                     depname = pool_id2str(pool, pid);
+                   }
+
+
+                 if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
+                   {
+                     char newdep[100];
+                     snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
+                     pid = pool_str2id(pool, newdep, 1);
+                     if (prd)
+                       pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
+                   }
+
+                 npr = repo_addid_dep(pd->repo, npr, pid, 0);
+               }
+             s->provides = npr;
+           }
+#if 1
+
+         if (s->requires)
+           {
+             Offset reqs = s->requires;
+             npr = 0;
+             while ((pid = pd->repo->idarraydata[reqs++]) != 0)
+               {
+                 const char *depname = 0;
+                 Reldep *prd = 0;
+
+                 if (ISRELDEP(pid))
+                   {
+                     prd = GETRELDEP(pool, pid);
+                     depname = pool_id2str(pool, prd->name);
+                   }
+                 else
+                   {
+                     depname = pool_id2str(pool, pid);
+                   }
+
+                 if (!strncmp(depname, "kernel(", 7) && !strchr(depname, ':'))
+                   {
+                     char newdep[100];
+                     snprintf(newdep, sizeof(newdep), "kernel(%s:%s", cflavor, depname + 7);
+                     pid = pool_str2id(pool, newdep, 1);
+                     if (prd)
+                       pid = pool_rel2id(pool, pid, prd->evr, prd->flags, 1);
+                   }
+                 npr = repo_addid_dep(pd->repo, npr, pid, 0);
+               }
+             s->requires = npr;
+           }
+#endif
+         free(cflavor);
+       }
+      break;
+    case STATE_NAME:
+      s->name = pool_str2id(pool, content, 1);
+      break;
+    case STATE_VENDOR:
+      s->vendor = pool_str2id(pool, content, 1);
+      break;
+    case STATE_BUILDTIME:
+      t = atoi(content);
+      if (t)
+       repodata_set_num(pd->data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
+      break;   
+    case STATE_UPDATE:                /* new version, keeping all other metadata */
+      evr = evr2id(pool, pd,
+                   pd->epoch   ? pd->evrspace + pd->epoch   : 0,
+                   pd->version ? pd->evrspace + pd->version : 0,
+                   pd->release ? pd->evrspace + pd->release : 0);
+      pd->levrspace = 1;
+      pd->epoch = 0;
+      pd->version = 0;
+      pd->release = 0;
+      /* use highest evr */
+      if (!s->evr || pool_evrcmp(pool, s->evr, evr, EVRCMP_COMPARE) <= 0)
+       s->evr = evr;
+      break;
+    case STATE_EPOCH:
+    case STATE_VERSION:
+    case STATE_RELEASE:
+      /* ensure buffer space */
+      if (xmlp->lcontent + 1 + pd->levrspace > pd->aevrspace)
+       {
+         pd->aevrspace = xmlp->lcontent + 1 + pd->levrspace + 256;
+         pd->evrspace = (char *)realloc(pd->evrspace, pd->aevrspace);
+       }
+      memcpy(pd->evrspace + pd->levrspace, xmlp->content, xmlp->lcontent + 1);
+      if (state == STATE_EPOCH)
+       pd->epoch = pd->levrspace;
+      else if (state == STATE_VERSION)
+       pd->version = pd->levrspace;
+      else
+       pd->release = pd->levrspace;
+      pd->levrspace += xmlp->lcontent + 1;
+      break;
+    case STATE_ARCH:
+      s->arch = pool_str2id(pool, content, 1);
+      break;
+    default:
+      break;
+    }
+}
+
+/*-------------------------------------------------------------------*/
+
+/*
+ * read 'helix' type xml from fp
+ * add packages to pool/repo
+ *
+ */
+
+int
+repo_add_helix(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  struct parsedata pd;
+  Repodata *data;
+  unsigned int now;
+
+  now = solv_timems(0);
+  data = repo_add_repodata(repo, flags);
+
+  /* prepare parsedata */
+  memset(&pd, 0, sizeof(pd));
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = data;
+
+  pd.evrspace = (char *)solv_malloc(256);
+  pd.aevrspace = 256;
+  pd.levrspace = 1;
+
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pd.pool, -1, "repo_helix: %s at line %u", pd.xmlp.errstr, pd.xmlp.line);
+  solv_xmlparser_free(&pd.xmlp);
+
+  solv_free(pd.evrspace);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_helix took %d ms\n", solv_timems(now));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
+  return pd.ret;
+}
diff --git a/libsolv-0.7.2/ext/repo_helix.h b/libsolv-0.7.2/ext/repo_helix.h
new file mode 100644 (file)
index 0000000..d883dd9
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_helix.h
+ * 
+ */
+
+#ifndef LIBSOLV_REPO_HELIX_H
+#define LIBSOLV_REPO_HELIX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "pool.h"
+#include "repo.h"
+
+extern int repo_add_helix(Repo *repo, FILE *fp, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+    
+
+#endif /* LIBSOLV_REPO_HELIX_H */
diff --git a/libsolv-0.7.2/ext/repo_mdk.c b/libsolv-0.7.2/ext/repo_mdk.c
new file mode 100644 (file)
index 0000000..4d3e102
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "chksum.h"
+#include "solv_xmlparser.h"
+#include "repo_mdk.h"
+
+static Offset
+parse_deps(Solvable *s, char *bp, Id marker)
+{
+  Pool *pool = s->repo->pool;
+  Offset deps = 0;
+  char *nbp, *ebp;
+  for (; bp; bp = nbp)
+    {
+      int ispre = 0;
+      Id id, evr = 0;
+      int flags = 0;
+
+      nbp = strchr(bp, '@');
+      if (!nbp)
+       ebp = bp + strlen(bp);
+      else
+       {
+         ebp = nbp;
+         *nbp++ = 0;
+       }
+      if (ebp[-1] == ']')
+       {
+         char *sbp = ebp - 1;
+         while (sbp >= bp && *sbp != '[')
+           sbp--;
+         if (sbp >= bp && sbp[1] != '*')
+           {
+             char *fbp;
+             for (fbp = sbp + 1;; fbp++)
+               {
+                 if (*fbp == '>')
+                   flags |= REL_GT;
+                 else if (*fbp == '=')
+                   flags |= REL_EQ;
+                 else if (*fbp == '<')
+                   flags |= REL_LT;
+                 else
+                   break;
+               }
+             if (*fbp == ' ')
+               fbp++;
+             evr = pool_strn2id(pool, fbp, ebp - 1 - fbp, 1);
+             ebp = sbp;
+           }
+       }
+      if (ebp[-1] == ']' && ebp >= bp + 3 && !strncmp(ebp - 3, "[*]", 3))
+       {
+         ispre = 1;
+         ebp -= 3;
+       }
+      id = pool_strn2id(pool, bp, ebp - bp, 1);
+      if (evr)
+       id = pool_rel2id(pool, id, evr, flags, 1);
+      deps = repo_addid_dep(s->repo, deps, id, ispre ? marker : 0);
+      bp = nbp;
+    }
+  return deps;
+}
+
+int
+repo_add_mdk(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  Solvable *s;
+  char *buf;
+  int bufa, bufl;
+
+  data = repo_add_repodata(repo, flags);
+  bufa = 4096;
+  buf = solv_malloc(bufa);
+  bufl = 0;
+  s = 0;
+  while (fgets(buf + bufl, bufa - bufl, fp) > 0)
+    {
+      bufl += strlen(buf + bufl);
+      if (!bufl)
+       continue;
+      if (buf[bufl - 1] != '\n')
+       {
+         if (bufa - bufl < 256)
+           {
+             bufa += 4096;
+             buf = solv_realloc(buf, bufa);
+           }
+         continue;
+       }
+      buf[bufl - 1] = 0;
+      bufl = 0;
+      if (buf[0] != '@')
+       {
+         pool_debug(pool, SOLV_ERROR, "bad line <%s>\n", buf);
+         continue;
+       }
+      if (!s)
+       s = pool_id2solvable(pool, repo_add_solvable(repo));
+      if (!strncmp(buf + 1, "filesize@", 9))
+       repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(buf + 10, 0, 10));
+      else if (!strncmp(buf + 1, "summary@", 8))
+       repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, buf + 9);
+      else if (!strncmp(buf + 1, "provides@", 9))
+       s->provides = parse_deps(s, buf + 10, 0);
+      else if (!strncmp(buf + 1, "requires@", 9))
+       s->requires = parse_deps(s, buf + 10, SOLVABLE_PREREQMARKER);
+      else if (!strncmp(buf + 1, "recommends@", 11))
+       s->recommends = parse_deps(s, buf + 10, 0);
+      else if (!strncmp(buf + 1, "suggests@", 9))
+       s->suggests = parse_deps(s, buf + 10, 0);
+      else if (!strncmp(buf + 1, "obsoletes@", 10))
+       s->obsoletes = parse_deps(s, buf + 11, 0);
+      else if (!strncmp(buf + 1, "conflicts@", 10))
+       s->conflicts = parse_deps(s, buf + 11, 0);
+      else if (!strncmp(buf + 1, "info@", 5))
+       {
+         char *nvra = buf + 6;
+         char *epochstr;
+         char *arch;
+         char *version;
+         char *filename;
+         char *disttag = 0;
+         char *distepoch = 0;
+         if ((epochstr = strchr(nvra, '@')) != 0)
+           {
+             char *sizestr;
+             *epochstr++ = 0;
+             if ((sizestr = strchr(epochstr, '@')) != 0)
+               {
+                 char *groupstr;
+                 *sizestr++ = 0;
+                 if ((groupstr = strchr(sizestr, '@')) != 0)
+                   {
+                     *groupstr++ = 0;
+                     if ((disttag = strchr(groupstr, '@')) != 0)
+                       {
+                         *disttag++ = 0;
+                         if ((distepoch = strchr(disttag, '@')) != 0)
+                           {
+                             char *n;
+                             *distepoch++ = 0;
+                             if ((n = strchr(distepoch, '@')) != 0)
+                               *n = 0;
+                           }
+                       }
+                     if (*groupstr)
+                       repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, groupstr);
+                   }
+                 if (*sizestr)
+                   repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(sizestr, 0, 10));
+               }
+           }
+          filename = pool_tmpjoin(pool, nvra, ".rpm", 0);
+         arch = strrchr(nvra, '.');
+         if (arch)
+           {
+             *arch++ = 0;
+             s->arch = pool_str2id(pool, arch, 1);
+           }
+         if (disttag && *disttag)
+           {
+             /* strip disttag from release */
+             char *n = strrchr(nvra, '-');
+             if (n && !strncmp(n + 1, disttag, strlen(disttag)))
+               *n = 0;
+           }
+         if (distepoch && *distepoch)
+           {
+             /* add distepoch */
+             int le = strlen(distepoch);
+             int ln = strlen(nvra);
+             nvra[ln++] = ':';
+             memmove(nvra + ln, distepoch, le);        /* may overlap */
+             nvra[le + ln] = 0;
+           }
+         version = strrchr(nvra, '-');
+         if (version)
+           {
+             char *release = version;
+             *release = 0;
+             version = strrchr(nvra, '-');
+             *release = '-';
+             if (!version)
+               version = release;
+             *version++ = 0;
+           }
+         else
+           version = "";
+         s->name = pool_str2id(pool, nvra, 1);
+         if (epochstr && *epochstr && strcmp(epochstr, "0") != 0)
+           {
+             char *evr = pool_tmpjoin(pool, epochstr, ":", version);
+             s->evr = pool_str2id(pool, evr, 1);
+           }
+         else
+           s->evr = pool_str2id(pool, version, 1);
+         repodata_set_location(data, s - pool->solvables, 0, 0, filename);
+         if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+           s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+          s = 0;
+       }
+      else
+       {
+         char *tagend = strchr(buf + 1, '@');
+         if (tagend)
+           *tagend = 0;
+         pool_debug(pool, SOLV_ERROR, "unknown tag <%s>\n", buf + 1);
+         continue;
+       }
+    }
+  if (s)
+    {
+      pool_debug(pool, SOLV_ERROR, "unclosed package at EOF\n");
+      s = solvable_free(s, 1);
+    }
+  solv_free(buf);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+enum state {
+  STATE_START,
+  STATE_MEDIA_INFO,
+  STATE_INFO,
+  STATE_FILES,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START, "media_info", STATE_MEDIA_INFO, 0 },
+  { STATE_MEDIA_INFO, "info", STATE_INFO, 1 },
+  { STATE_MEDIA_INFO, "files", STATE_FILES, 1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  Solvable *solvable;
+  Hashtable joinhash;
+  Hashval joinhashmask;
+  struct solv_xmlparser xmlp;
+};
+
+static Hashtable
+joinhash_init(Repo *repo, Hashval *hmp)
+{
+  Hashval hm = mkmask(repo->nsolvables);
+  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
+  Hashval h, hh;
+  Solvable *s;
+  int i;
+
+  FOR_REPO_SOLVABLES(repo, i, s)
+    {
+      hh = HASHCHAIN_START;
+      h = s->name & hm;
+      while (ht[h])
+        h = HASHCHAIN_NEXT(h, hh, hm);
+      ht[h] = i;
+    }
+  *hmp = hm;
+  return ht;
+}
+
+static Solvable *
+joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, const char *fn, const char *distepoch)
+{
+  Hashval h, hh;
+  const char *p, *vrstart, *vrend;
+  Id name, arch;
+
+  if (!fn || !*fn)
+    return 0;
+  if (distepoch && !*distepoch)
+    distepoch = 0;
+  p = fn + strlen(fn);
+  while (--p > fn)
+    if (*p == '.')
+      break;
+  if (p == fn)
+    return 0;
+  arch = pool_str2id(repo->pool, p + 1, 0);
+  if (!arch)
+    return 0;
+  if (distepoch)
+    {
+      while (--p > fn)
+        if (*p == '-')
+          break;
+      if (p == fn)
+       return 0;
+    }
+  vrend = p;
+  while (--p > fn)
+    if (*p == '-')
+      break;
+  if (p == fn)
+    return 0;
+  while (--p > fn)
+    if (*p == '-')
+      break;
+  if (p == fn)
+    return 0;
+  vrstart = p + 1;
+  name = pool_strn2id(repo->pool, fn, p - fn, 0);
+  if (!name)
+    return 0;
+  hh = HASHCHAIN_START;
+  h = name & hm;
+  while (ht[h])
+    {
+      Solvable *s = repo->pool->solvables + ht[h];
+      if (s->name == name && s->arch == arch)
+       {
+         /* too bad we don't know the epoch... */
+         const char *evr = pool_id2str(repo->pool, s->evr);
+         for (p = evr; *p >= '0' && *p <= '9'; p++)
+           ;
+         if (p > evr && *p == ':')
+           evr = p + 1;
+         if (distepoch)
+           {
+              if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == ':' && !strcmp(distepoch, evr + (vrend - vrstart + 1)))
+               return s;
+           }
+          else if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == 0)
+           return s;
+       }
+      h = HASHCHAIN_NEXT(h, hh, hm);
+    }
+  return 0;
+}
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+
+  switch (state)
+    {
+    case STATE_INFO:
+      {
+       const char *fn = solv_xmlparser_find_attr("fn", atts);
+       const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
+       const char *str;
+       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
+       if (!pd->solvable)
+         break;
+       str = solv_xmlparser_find_attr("url", atts);
+       if (str && *str)
+         repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str);
+       str = solv_xmlparser_find_attr("license", atts);
+       if (str && *str)
+         repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str);
+       str = solv_xmlparser_find_attr("sourcerpm", atts);
+       if (str && *str)
+         repodata_set_sourcepkg(pd->data, pd->solvable - pool->solvables, str);
+        break;
+      }
+    case STATE_FILES:
+      {
+       const char *fn = solv_xmlparser_find_attr("fn", atts);
+       const char *distepoch = solv_xmlparser_find_attr("distepoch", atts);
+       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
+        break;
+      }
+    default:
+      break;
+    }
+}
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Solvable *s = pd->solvable;
+  switch (state)
+    {
+    case STATE_INFO:
+      if (s && *content)
+        repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, content);
+      break;
+    case STATE_FILES:
+      if (s && *content)
+       {
+         char *np, *p, *sl;
+         for (p = content; p && *p; p = np)
+           {
+             Id id;
+             np = strchr(p, '\n');
+             if (np)
+               *np++ = 0;
+             if (!*p)
+               continue;
+             sl = strrchr(p, '/');
+             if (sl)
+               {
+                 *sl++ = 0;
+                 id = repodata_str2dir(pd->data, p, 1);
+               }
+             else
+               {
+                 sl = p;
+                 id = 0;
+               }
+             if (!id)
+               id = repodata_str2dir(pd->data, "/", 1);
+             repodata_add_dirstr(pd->data, s - pd->pool->solvables, SOLVABLE_FILELIST, id, sl);
+           }
+       }
+      break;
+    default:
+      break;
+    }
+}
+
+int
+repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
+{
+  Repodata *data;
+  struct parsedata pd;
+
+  if (!(flags & REPO_EXTEND_SOLVABLES))
+    {
+      pool_debug(repo->pool, SOLV_ERROR, "repo_add_mdk_info: can only extend existing solvables\n");
+      return -1;
+    }
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+  solv_free(pd.joinhash);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
diff --git a/libsolv-0.7.2/ext/repo_mdk.h b/libsolv-0.7.2/ext/repo_mdk.h
new file mode 100644 (file)
index 0000000..270c42e
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_mdk(Repo *repo, FILE *fp, int flags);
+extern int repo_add_mdk_info(Repo *repo, FILE *fp, int flags);
+
diff --git a/libsolv-0.7.2/ext/repo_products.c b/libsolv-0.7.2/ext/repo_products.c
new file mode 100644 (file)
index 0000000..edf15bf
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * repo_products.c
+ *
+ * Parses all files below 'proddir'
+ * See http://en.opensuse.org/Product_Management/Code11
+ *
+ *
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "solv_xmlparser.h"
+#define DISABLE_SPLIT
+#include "tools_util.h"
+#include "repo_content.h"
+#include "repo_zyppdb.h"
+#include "repo_products.h"
+#include "repo_releasefile_products.h"
+
+
+enum state {
+  STATE_START,
+  STATE_PRODUCT,
+  STATE_VENDOR,
+  STATE_NAME,
+  STATE_VERSION,
+  STATE_RELEASE,
+  STATE_ARCH,
+  STATE_SUMMARY,
+  STATE_SHORTSUMMARY,
+  STATE_DESCRIPTION,
+  STATE_UPDATEREPOKEY,
+  STATE_CPEID,
+  STATE_URLS,
+  STATE_URL,
+  STATE_RUNTIMECONFIG,
+  STATE_LINGUAS,
+  STATE_LANG,
+  STATE_REGISTER,
+  STATE_TARGET,
+  STATE_REGRELEASE,
+  STATE_REGFLAVOR,
+  STATE_PRODUCTLINE,
+  STATE_REGUPDATES,
+  STATE_REGUPDREPO,
+  STATE_ENDOFLIFE,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START,     "product",       STATE_PRODUCT,       0 },
+  { STATE_PRODUCT,   "vendor",        STATE_VENDOR,        1 },
+  { STATE_PRODUCT,   "name",          STATE_NAME,          1 },
+  { STATE_PRODUCT,   "version",       STATE_VERSION,       1 },
+  { STATE_PRODUCT,   "release",       STATE_RELEASE,       1 },
+  { STATE_PRODUCT,   "arch",          STATE_ARCH,          1 },
+  { STATE_PRODUCT,   "productline",   STATE_PRODUCTLINE,   1 },
+  { STATE_PRODUCT,   "summary",       STATE_SUMMARY,       1 },
+  { STATE_PRODUCT,   "shortsummary",  STATE_SHORTSUMMARY,  1 },
+  { STATE_PRODUCT,   "description",   STATE_DESCRIPTION,   1 },
+  { STATE_PRODUCT,   "register",      STATE_REGISTER,      0 },
+  { STATE_PRODUCT,   "urls",          STATE_URLS,          0 },
+  { STATE_PRODUCT,   "runtimeconfig", STATE_RUNTIMECONFIG, 0 },
+  { STATE_PRODUCT,   "linguas",       STATE_LINGUAS,       0 },
+  { STATE_PRODUCT,   "updaterepokey", STATE_UPDATEREPOKEY, 1 },
+  { STATE_PRODUCT,   "cpeid",         STATE_CPEID,         1 },
+  { STATE_PRODUCT,   "endoflife",     STATE_ENDOFLIFE,     1 },
+  { STATE_URLS,      "url",           STATE_URL,           1 },
+  { STATE_LINGUAS,   "lang",          STATE_LANG,          0 },
+  { STATE_REGISTER,  "target",        STATE_TARGET,        1 },
+  { STATE_REGISTER,  "release",       STATE_REGRELEASE,    1 },
+  { STATE_REGISTER,  "flavor",        STATE_REGFLAVOR,     1 },
+  { STATE_REGISTER,  "updates",       STATE_REGUPDATES,    0 },
+  { STATE_REGUPDATES, "repository",   STATE_REGUPDREPO,    0 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  const char *filename;
+  const char *basename;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+
+  struct solv_xmlparser xmlp;
+  struct joindata jd;
+
+  const char *tmplang;
+
+  const char *tmpvers;
+  const char *tmprel;
+  Id urltype;
+
+  unsigned int ctime;
+
+  Solvable *solvable;
+  Id handle;
+
+  ino_t baseproduct;
+  ino_t currentproduct;
+  int productscheme;
+};
+
+
+static time_t
+datestr2timestamp(const char *date)
+{
+  const char *p; 
+  struct tm tm; 
+
+  if (!date || !*date)
+    return 0;
+  for (p = date; *p >= '0' && *p <= '9'; p++)
+    ;   
+  if (!*p)
+    return atoi(date);
+  memset(&tm, 0, sizeof(tm));
+  p = strptime(date, "%F%T", &tm);
+  if (!p)
+    {
+      memset(&tm, 0, sizeof(tm));
+      p = strptime(date, "%F", &tm);
+      if (!p || *p)
+       return 0;
+    }
+  return timegm(&tm);
+}
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+
+  switch(state)
+    {
+    case STATE_PRODUCT:
+      /* parse 'schemeversion' and store in global variable */
+      {
+        const char * scheme = solv_xmlparser_find_attr("schemeversion", atts);
+        pd->productscheme = (scheme && *scheme) ? atoi(scheme) : -1;
+      }
+      if (!s)
+       {
+         s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+         pd->handle = s - pool->solvables;
+       }
+      break;
+
+      /* <summary lang="xy">... */
+    case STATE_SUMMARY:
+    case STATE_DESCRIPTION:
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
+      break;
+    case STATE_URL:
+      pd->urltype = pool_str2id(pd->pool, solv_xmlparser_find_attr("name", atts), 1);
+      break;
+    case STATE_REGUPDREPO:
+      {
+        const char *repoid = solv_xmlparser_find_attr("repoid", atts);
+       if (repoid && *repoid)
+         {
+           Id h = repodata_new_handle(pd->data);
+           repodata_set_str(pd->data, h, PRODUCT_UPDATES_REPOID, repoid);
+           repodata_add_flexarray(pd->data, pd->handle, PRODUCT_UPDATES, h);
+         }
+       break;
+      }
+    default:
+      break;
+    }
+}
+
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Solvable *s = pd->solvable;
+
+  switch (state)
+    {
+    case STATE_PRODUCT:
+      /* product done, finish solvable */
+      if (pd->ctime)
+        repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, pd->ctime);
+
+      if (pd->basename)
+        repodata_set_str(pd->data, pd->handle, PRODUCT_REFERENCEFILE, pd->basename);
+
+      /* this is where <productsdir>/baseproduct points to */
+      if (pd->currentproduct == pd->baseproduct)
+       repodata_set_str(pd->data, pd->handle, PRODUCT_TYPE, "base");
+
+      if (pd->tmprel)
+       {
+         if (pd->tmpvers)
+           s->evr = makeevr(pd->pool, join2(&pd->jd, pd->tmpvers, "-", pd->tmprel));
+         else
+           {
+             fprintf(stderr, "Seen <release> but no <version>\n");
+           }
+       }
+      else if (pd->tmpvers)
+       s->evr = makeevr(pd->pool, pd->tmpvers); /* just version, no release */
+      pd->tmpvers = solv_free((void *)pd->tmpvers);
+      pd->tmprel = solv_free((void *)pd->tmprel);
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
+      pd->solvable = 0;
+      break;
+    case STATE_VENDOR:
+      s->vendor = pool_str2id(pd->pool, content, 1);
+      break;
+    case STATE_NAME:
+      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1);
+      break;
+    case STATE_VERSION:
+      pd->tmpvers = solv_strdup(content);
+      break;
+    case STATE_RELEASE:
+      pd->tmprel = solv_strdup(content);
+      break;
+    case STATE_ARCH:
+      s->arch = pool_str2id(pd->pool, content, 1);
+      break;
+    case STATE_PRODUCTLINE:
+      repodata_set_str(pd->data, pd->handle, PRODUCT_PRODUCTLINE, content);
+    break;
+    case STATE_UPDATEREPOKEY:
+      /** obsolete **/
+      break;
+    case STATE_SUMMARY:
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
+      break;
+    case STATE_SHORTSUMMARY:
+      repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, content);
+      break;
+    case STATE_DESCRIPTION:
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_DESCRIPTION, pd->tmplang, 1), content);
+      break;
+    case STATE_URL:
+      if (pd->urltype)
+        {
+          repodata_add_poolstr_array(pd->data, pd->handle, PRODUCT_URL, content);
+          repodata_add_idarray(pd->data, pd->handle, PRODUCT_URL_TYPE, pd->urltype);
+        }
+      break;
+    case STATE_TARGET:
+      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_TARGET, content);
+      break;
+    case STATE_REGRELEASE:
+      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_RELEASE, content);
+      break;
+    case STATE_REGFLAVOR:
+      repodata_set_str(pd->data, pd->handle, PRODUCT_REGISTER_FLAVOR, content);
+      break;
+    case STATE_CPEID:
+      if (*content)
+        repodata_set_str(pd->data, pd->handle, SOLVABLE_CPEID, content);
+      break;
+    case STATE_ENDOFLIFE:
+      /* FATE#320699: Support tri-state product-endoflife (tag absent, present but nodate(0), present + date) */
+      repodata_set_num(pd->data, pd->handle, PRODUCT_ENDOFLIFE, (*content ? datestr2timestamp(content) : 0));
+      break;
+    default:
+      break;
+    }
+}
+
+int
+repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
+{
+  Repodata *data;
+  struct parsedata pd;
+  DIR *dir;
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+
+  if (flags & REPO_USE_ROOTDIR)
+    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
+  dir = opendir(dirpath);
+  if (dir)
+    {
+      struct dirent *entry;
+      struct stat st;
+      char *fullpath;
+
+      /* check for <productsdir>/baseproduct on code11 and remember its target inode */
+      if (stat(join2(&pd.jd, dirpath, "/", "baseproduct"), &st) == 0) /* follow symlink */
+       pd.baseproduct = st.st_ino;
+      else
+       pd.baseproduct = 0;
+
+      while ((entry = readdir(dir)))
+       {
+         int len = strlen(entry->d_name);
+         FILE *fp;
+         if (len <= 5 || strcmp(entry->d_name + len - 5, ".prod") != 0)
+           continue;
+         fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
+         fp = fopen(fullpath, "r");
+         if (!fp)
+           {
+             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
+             continue;
+           }
+         if (fstat(fileno(fp), &st))
+           {
+             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
+             fclose(fp);
+             continue;
+           }
+         pd.currentproduct = st.st_ino;
+         pd.ctime = (unsigned int)st.st_ctime;
+         pd.filename = fullpath;
+         pd.basename = entry->d_name;
+         if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+           {
+             pool_debug(pd.pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd.filename, pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+             pd.solvable = solvable_free(pd.solvable, 1);
+           }
+         fclose(fp);
+       }
+      closedir(dir);
+    }
+  solv_xmlparser_free(&pd.xmlp);
+  join_freemem(&pd.jd);
+  if (flags & REPO_USE_ROOTDIR)
+    solv_free((char *)dirpath);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+
+/******************************************************************************************/
+
+
+/*
+ * read all installed products
+ *
+ * try proddir (reading all .xml files from this directory) first
+ * if not available, assume non-code11 layout and parse /etc/xyz-release
+ *
+ * parse each one as a product
+ */
+
+/* Oh joy! Three parsers for the price of one! */
+
+int
+repo_add_products(Repo *repo, const char *proddir, int flags)
+{
+  const char *fullpath;
+  DIR *dir;
+
+  if (proddir)
+    {
+      dir = opendir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(repo->pool, proddir) : proddir);
+      if (dir)
+       {
+         /* assume code11 stype products */
+         closedir(dir);
+         return repo_add_code11_products(repo, proddir, flags);
+       }
+    }
+
+  /* code11 didn't work, try old code10 zyppdb */
+  fullpath = "/var/lib/zypp/db/products";
+  if (flags & REPO_USE_ROOTDIR)
+    fullpath = pool_prepend_rootdir_tmp(repo->pool, fullpath);
+  dir = opendir(fullpath);
+  if (dir)
+    {
+      closedir(dir);
+      /* assume code10 style products */
+      return repo_add_zyppdb_products(repo, "/var/lib/zypp/db/products", flags);
+    }
+
+  /* code10/11 didn't work, try -release files parsing */
+  fullpath = "/etc";
+  if (flags & REPO_USE_ROOTDIR)
+    fullpath = pool_prepend_rootdir_tmp(repo->pool, fullpath);
+  dir = opendir(fullpath);
+  if (dir)
+    {
+      closedir(dir);
+      return repo_add_releasefile_products(repo, "/etc", flags);
+    }
+
+  /* no luck. check if the rootdir exists */
+  fullpath = pool_get_rootdir(repo->pool);
+  if (fullpath && *fullpath)
+    {
+      dir = opendir(fullpath);
+      if (!dir)
+       return pool_error(repo->pool, -1, "%s: %s", fullpath, strerror(errno));
+      closedir(dir);
+    }
+
+  /* the least we can do... */
+  if (!(flags & REPO_NO_INTERNALIZE) && (flags & REPO_REUSE_REPODATA) != 0)
+    repodata_internalize(repo_last_repodata(repo));
+  return 0;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/ext/repo_products.h b/libsolv-0.7.2/ext/repo_products.h
new file mode 100644 (file)
index 0000000..f7e3b0a
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_code11_products(Repo *repo, const char *dirpath, int flags);
+extern int repo_add_products(Repo *repo, const char *proddir, int flags);
diff --git a/libsolv-0.7.2/ext/repo_pubkey.c b/libsolv-0.7.2/ext/repo_pubkey.c
new file mode 100644 (file)
index 0000000..eb83839
--- /dev/null
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (c) 2007-2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_pubkey
+ *
+ * support for pubkey reading
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <rpm/rpmio.h>
+#include <rpm/rpmpgp.h>
+#ifndef RPM5
+#include <rpm/header.h>
+#endif
+#include <rpm/rpmdb.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "hash.h"
+#include "util.h"
+#include "queue.h"
+#include "chksum.h"
+#include "repo_rpmdb.h"
+#include "repo_pubkey.h"
+#ifdef ENABLE_PGPVRFY
+#include "solv_pgpvrfy.h"
+#endif
+
+static void
+setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
+{
+  if (str[solv_validutf8(str)])
+    {
+      char *ustr = solv_latin1toutf8(str);     /* not utf8, assume latin1 */
+      repodata_set_str(repodata, handle, tag, ustr);
+      solv_free(ustr);
+    }
+  else
+    repodata_set_str(repodata, handle, tag, str);
+}
+
+static char *
+r64dec1(char *p, unsigned int *vp, int *eofp)
+{
+  int i, x;
+  unsigned int v = 0;
+
+  for (i = 0; i < 4; )
+    {
+      x = *p++;
+      if (!x)
+       return 0;
+      if (x >= 'A' && x <= 'Z')
+       x -= 'A';
+      else if (x >= 'a' && x <= 'z')
+       x -= 'a' - 26;
+      else if (x >= '0' && x <= '9')
+       x -= '0' - 52;
+      else if (x == '+')
+       x = 62;
+      else if (x == '/')
+       x = 63;
+      else if (x == '=')
+       {
+         x = 0;
+         if (i == 0)
+           {
+             *eofp = 3;
+             *vp = 0;
+             return p - 1;
+           }
+         *eofp += 1;
+       }
+      else
+       continue;
+      v = v << 6 | x;
+      i++;
+    }
+  *vp = v;
+  return p;
+}
+
+static unsigned int
+crc24(unsigned char *p, int len)
+{
+  unsigned int crc = 0xb704ce;
+  int i;
+
+  while (len--)
+    {
+      crc ^= (*p++) << 16;
+      for (i = 0; i < 8; i++)
+        if ((crc <<= 1) & 0x1000000)
+         crc ^= 0x1864cfb;
+    }
+  return crc & 0xffffff;
+}
+
+static int
+unarmor(char *pubkey, unsigned char **pktp, int *pktlp, const char *startstr, const char *endstr)
+{
+  char *p, *pubkeystart = pubkey;
+  int l, eof;
+  unsigned char *buf, *bp;
+  unsigned int v;
+
+  *pktp = 0;
+  *pktlp = 0;
+  if (!pubkey)
+    return 0;
+  l = strlen(startstr);
+  while (strncmp(pubkey, startstr, l) != 0)
+    {
+      pubkey = strchr(pubkey, '\n');
+      if (!pubkey)
+       return 0;
+      pubkey++;
+    }
+  pubkey = strchr(pubkey, '\n');
+  if (!pubkey++)
+    return 0;
+  /* skip header lines */
+  for (;;)
+    {
+      while (*pubkey == ' ' || *pubkey == '\t')
+       pubkey++;
+      if (*pubkey == '\n')
+       break;
+      pubkey = strchr(pubkey, '\n');
+      if (!pubkey++)
+       return 0;
+    }
+  pubkey++;
+  p = strchr(pubkey, '=');
+  if (!p)
+    return 0;
+  l = p - pubkey;
+  bp = buf = solv_malloc(l * 3 / 4 + 4);
+  eof = 0;
+  while (!eof)
+    {
+      pubkey = r64dec1(pubkey, &v, &eof);
+      if (!pubkey)
+       {
+         solv_free(buf);
+         return 0;
+       }
+      *bp++ = v >> 16;
+      *bp++ = v >> 8;
+      *bp++ = v;
+    }
+  while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
+    pubkey++;
+  bp -= eof;
+  if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0)
+    {
+      solv_free(buf);
+      return 0;
+    }
+  if (v != crc24(buf, bp - buf))
+    {
+      solv_free(buf);
+      return 0;
+    }
+  while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r')
+    pubkey++;
+  if (strncmp(pubkey, endstr, strlen(endstr)) != 0)
+    {
+      solv_free(buf);
+      return 0;
+    }
+  p = strchr(pubkey, '\n');
+  if (!p)
+    p = pubkey + strlen(pubkey);
+  *pktp = buf;
+  *pktlp = bp - buf;
+  return (p ? p + 1 : pubkey + strlen(pubkey)) - pubkeystart;
+}
+
+#define ARMOR_NLAFTER  16
+
+static char *
+armor(unsigned char *pkt, int pktl, const char *startstr, const char *endstr, const char *version)
+{
+  static const char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  char *str = solv_malloc(strlen(startstr) + strlen(endstr) + strlen(version) + (pktl / 3) * 4 + (pktl / (ARMOR_NLAFTER * 3)) + 30);
+  char *p = str;
+  int a, b, c, i;
+  unsigned int v;
+
+  v = crc24(pkt, pktl);
+  sprintf(p, "%s\nVersion: %s\n\n", startstr, version);
+  p += strlen(p);
+  for (i = -1; pktl > 0; pktl -= 3)
+    {
+      if (++i == ARMOR_NLAFTER)
+       {
+         i = 0;
+         *p++ = '\n';
+       }
+      a = *pkt++;
+      b = pktl > 1 ? *pkt++ : 0;
+      c = pktl > 2 ? *pkt++ : 0;
+      *p++ = bintoasc[a >> 2];
+      *p++ = bintoasc[(a & 3) << 4 | b >> 4];
+      *p++ = pktl > 1 ? bintoasc[(b & 15) << 2 | c >> 6] : '=';
+      *p++ = pktl > 2 ? bintoasc[c & 63] : '=';
+    }
+  *p++ = '\n';
+  *p++ = '=';
+  *p++ = bintoasc[v >> 18 & 0x3f];
+  *p++ = bintoasc[v >> 12 & 0x3f];
+  *p++ = bintoasc[v >>  6 & 0x3f];
+  *p++ = bintoasc[v       & 0x3f];
+  sprintf(p, "\n%s\n", endstr);
+  return str;
+}
+
+/* internal representation of a signature */
+struct pgpsig {
+  int type;
+  Id hashalgo;
+  unsigned char issuer[8];
+  int haveissuer;
+  unsigned int created;
+  unsigned int expires;
+  unsigned int keyexpires;
+  unsigned char *sigdata;
+  int sigdatal;
+  int mpioff;
+};
+
+static Id
+pgphashalgo2type(int algo)
+{
+  if (algo == 1)
+    return REPOKEY_TYPE_MD5;
+  if (algo == 2)
+    return REPOKEY_TYPE_SHA1;
+  if (algo == 8)
+    return REPOKEY_TYPE_SHA256;
+  if (algo == 9)
+    return REPOKEY_TYPE_SHA384;
+  if (algo == 10)
+    return REPOKEY_TYPE_SHA512;
+  if (algo == 11)
+    return REPOKEY_TYPE_SHA224;
+  return 0;
+}
+
+/* hash the pubkey/userid data for self-sig verification
+ * hash the final trailer
+ * create a "sigdata" block suitable for a call to solv_pgpverify */
+static void
+pgpsig_makesigdata(struct pgpsig *sig, unsigned char *p, int l, unsigned char *pubkey, int pubkeyl, unsigned char *userid, int useridl, Chksum *h)
+{
+  int type = sig->type;
+  unsigned char b[6];
+  const unsigned char *cs;
+  int csl;
+
+  if (!h || sig->mpioff < 2 || l <= sig->mpioff)
+    return;
+  if ((type >= 0x10 && type <= 0x13) || type == 0x1f || type == 0x18 || type == 0x20 || type == 0x28)
+    {
+      b[0] = 0x99;
+      b[1] = pubkeyl >> 8;
+      b[2] = pubkeyl;
+      solv_chksum_add(h, b, 3);
+      solv_chksum_add(h, pubkey, pubkeyl);
+    }
+  if ((type >= 0x10 && type <= 0x13))
+    {
+      if (p[0] != 3)
+       {
+         b[0] = 0xb4;
+         b[1] = useridl >> 24;
+         b[2] = useridl >> 16;
+         b[3] = useridl >> 8;
+         b[4] = useridl;
+         solv_chksum_add(h, b, 5);
+       }
+      solv_chksum_add(h, userid, useridl);
+    }
+  /* add trailer */
+  if (p[0] == 3)
+    solv_chksum_add(h, p + 2, 5);
+  else
+    {
+      int hl = 6 + (p[4] << 8 | p[5]);
+      solv_chksum_add(h, p, hl);
+      b[0] = 4;
+      b[1] = 0xff;
+      b[2] = hl >> 24;
+      b[3] = hl >> 16;
+      b[4] = hl >> 8;
+      b[5] = hl;
+      solv_chksum_add(h, b, 6);
+    }
+  cs = solv_chksum_get(h, &csl);
+  if (cs[0] == p[sig->mpioff - 2] && cs[1] == p[sig->mpioff - 1])
+    {
+      int ml = l - sig->mpioff;
+      sig->sigdata = solv_malloc(2 + csl + ml);
+      sig->sigdatal = 2 + csl + ml;
+      sig->sigdata[0] = p[0] == 3 ? p[15] : p[2];
+      sig->sigdata[1] = p[0] == 3 ? p[16] : p[3];
+      memcpy(sig->sigdata + 2, cs, csl);
+      memcpy(sig->sigdata + 2 + csl, p + sig->mpioff, ml);
+    }
+}
+
+/* parse the header of a subpacket contained in a signature packet
+ * returns: length of the packet header, 0 if there was an error
+ * *pktlp is set to the packet length, the tag is the first byte.
+ */
+static inline int
+parsesubpkglength(unsigned char *q, int ql, int *pktlp)
+{
+  int x, sl, hl;
+  /* decode sub-packet length, ql must be > 0 */
+  x = *q++;
+  if (x < 192)
+    {
+      sl = x;
+      hl = 1;
+    }
+  else if (x == 255)
+    {
+      if (ql < 5 || q[0] != 0)
+       return 0;
+      sl = q[1] << 16 | q[2] << 8 | q[3];
+      hl = 5;
+    }
+  else
+    {
+      if (ql < 2)
+       return 0;
+      sl = ((x - 192) << 8) + q[0] + 192;
+      hl = 2;
+    }
+  if (!sl || ql < sl + hl)     /* sub pkg tag is included in length, i.e. sl must not be zero */
+    return 0;
+  *pktlp = sl;
+  return hl;
+}
+
+/* parse a signature packet, initializing the pgpsig struct */
+static void
+pgpsig_init(struct pgpsig *sig, unsigned char *p, int l)
+{
+  memset(sig, 0, sizeof(*sig));
+  sig->type = -1;
+  if (p[0] == 3)
+    {
+      /* printf("V3 signature packet\n"); */
+      if (l <= 19 || p[1] != 5)
+       return;
+      sig->type = p[2];
+      sig->haveissuer = 1;
+      memcpy(sig->issuer, p + 7, 8);
+      sig->created = p[3] << 24 | p[4] << 16 | p[5] << 8 | p[6];
+      sig->hashalgo = p[16];
+      sig->mpioff = 19;
+    }
+  else if (p[0] == 4)
+    {
+      int j, ql, x;
+      unsigned char *q;
+
+      /* printf("V4 signature packet\n"); */
+      if (l < 6)
+       return;
+      sig->type = p[1];
+      sig->hashalgo = p[3];
+      q = p + 4;
+      sig->keyexpires = -1;
+      for (j = 0; q && j < 2; j++)
+       {
+         if (q + 2 > p + l)
+           {
+             q = 0;
+             break;
+           }
+         ql = q[0] << 8 | q[1];
+         q += 2;
+         if (q + ql > p + l)
+           {
+             q = 0;
+             break;
+           }
+         while (ql > 0)
+           {
+             int sl, hl;
+             hl = parsesubpkglength(q, ql, &sl);
+             if (!hl)
+               {
+                 q = 0;
+                 break;
+               }
+             q += hl;
+             ql -= hl;
+             x = q[0] & 127;   /* strip critical bit */
+             /* printf("%d SIGSUB %d %d\n", j, x, sl); */
+             if (x == 16 && sl == 9 && !sig->haveissuer)
+               {
+                 sig->haveissuer = 1;
+                 memcpy(sig->issuer, q + 1, 8);
+               }
+             if (x == 2 && j == 0)
+               sig->created = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
+             if (x == 3 && j == 0)
+               sig->expires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
+             if (x == 9 && j == 0)
+               sig->keyexpires = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4];
+             q += sl;
+             ql -= sl;
+           }
+       }
+      if (q && q - p + 2 < l)
+       sig->mpioff = q - p + 2;
+    }
+}
+
+/* parse a pgp packet header
+ * returns: length of the packet header, 0 if there was an error
+ * *tagp and *pktlp is set to the packet tag and the packet length
+ */
+static int
+parsepkgheader(unsigned char *p, int pl, int *tagp, int *pktlp)
+{
+  unsigned char *op = p;
+  int x, l;
+
+  if (!pl)
+    return 0;
+  x = *p++;
+  pl--;
+  if (!(x & 128) || pl <= 0)
+    return 0;
+  if ((x & 64) == 0)
+    {
+      *tagp = (x & 0x3c) >> 2;         /* old format */
+      x = 1 << (x & 3);
+      if (x > 4 || pl < x || (x == 4 && p[0]))
+       return 0;
+      pl -= x;
+      for (l = 0; x--;)
+       l = l << 8 | *p++;
+    }
+  else
+    {
+      *tagp = (x & 0x3f);              /* new format */
+      x = *p++;
+      pl--;
+      if (x < 192)
+       l = x;
+      else if (x >= 192 && x < 224)
+       {
+         if (pl <= 0)
+           return 0;
+         l = ((x - 192) << 8) + *p++ + 192;
+         pl--;
+       }
+      else if (x == 255)
+       {
+         if (pl <= 4 || p[0] != 0)     /* sanity: p[0] must be zero */
+           return 0;
+         l = p[1] << 16 | p[2] << 8 | p[3];
+         p += 4;
+         pl -= 4;
+       }
+      else
+       return 0;
+    }
+  if (l > pl)
+    return 0;
+  *pktlp = l;
+  return p - op;
+}
+
+/* parse the first pubkey (possible creating new packages for the subkeys)
+ * returns the number of parsed bytes.
+ * if flags contains ADD_WITH_SUBKEYS, all subkeys will be added as new
+ * solvables as well */
+static int
+parsepubkey(Solvable *s, Repodata *data, unsigned char *p, int pl, int flags)
+{
+  Repo *repo = s->repo;
+  unsigned char *pstart = p;
+  int tag, l;
+  unsigned char keyid[8];
+  char subkeyofstr[17];
+  unsigned int kcr = 0, maxex = 0, maxsigcr = 0;
+  unsigned char *pubkey = 0;
+  int pubkeyl = 0;
+  int insubkey = 0;
+  unsigned char *userid = 0;
+  int useridl = 0;
+  unsigned char *pubdata = 0;
+  int pubdatal = 0;
+
+  *subkeyofstr = 0;
+  for (; ; p += l, pl -= l)
+    {
+      int hl = parsepkgheader(p, pl, &tag, &l);
+      if (!hl || (pubkey && (tag == 6 || tag == 14)))
+       {
+         /* finish old key */
+         if (kcr)
+           repodata_set_num(data, s - repo->pool->solvables, SOLVABLE_BUILDTIME, kcr);
+         if (maxex && maxex != -1)
+           repodata_set_num(data, s - repo->pool->solvables, PUBKEY_EXPIRES, maxex);
+         s->name = pool_str2id(s->repo->pool, insubkey ? "gpg-subkey" : "gpg-pubkey", 1);
+         s->evr = 1;
+         s->arch = 1;
+         if (userid && useridl)
+           {
+             char *useridstr = solv_malloc(useridl + 1);
+             memcpy(useridstr, userid, useridl);
+             useridstr[useridl] = 0;
+             setutf8string(data, s - repo->pool->solvables, SOLVABLE_SUMMARY, useridstr);
+             free(useridstr);
+           }
+         if (pubdata)
+           {
+             char keyidstr[17];
+             char evr[8 + 1 + 8 + 1];
+             solv_bin2hex(keyid, 8, keyidstr);
+             repodata_set_str(data, s - repo->pool->solvables, PUBKEY_KEYID, keyidstr);
+             /* build rpm-style evr */
+             strcpy(evr, keyidstr + 8);
+             sprintf(evr + 8, "-%08x", maxsigcr);
+             s->evr = pool_str2id(repo->pool, evr, 1);
+           }
+         if (insubkey && *subkeyofstr)
+           repodata_set_str(data, s - repo->pool->solvables, PUBKEY_SUBKEYOF, subkeyofstr);
+         if (pubdata)          /* set data blob */
+           repodata_set_binary(data, s - repo->pool->solvables, PUBKEY_DATA, pubdata, pubdatal);
+         if (!pl)
+           break;
+         if (!hl)
+           {
+             p = 0;    /* parse error */
+             break;
+           }
+         if (tag == 6 || (tag == 14 && !(flags & ADD_WITH_SUBKEYS)))
+           break;
+         if (tag == 14 && pubdata && !insubkey)
+           solv_bin2hex(keyid, 8, subkeyofstr);
+         /* create new solvable for subkey */
+         s = pool_id2solvable(repo->pool, repo_add_solvable(repo));
+       }
+      p += hl;
+      pl -= hl;
+      if (!pubkey && tag != 6)
+       continue;
+      if (tag == 6 || (tag == 14 && (flags & ADD_WITH_SUBKEYS) != 0))          /* Public-Key Packet */
+       {
+         if (tag == 6)
+           {
+             pubkey = solv_memdup(p, l);
+             pubkeyl = l;
+           }
+         else
+           insubkey = 1;
+         pubdata = 0;
+         pubdatal = 0;
+         if (p[0] == 3 && l >= 10)
+           {
+             unsigned int ex;
+             Chksum *h;
+             maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
+             ex = 0;
+             if (p[5] || p[6])
+               {
+                 ex = kcr + 24*3600 * (p[5] << 8 | p[6]);
+                 if (ex > maxex)
+                   maxex = ex;
+               }
+             memset(keyid, 0, 8);
+             if (p[7] == 1)    /* RSA */
+               {
+                 int ql, ql2;
+                 unsigned char fp[16];
+                 char fpx[32 + 1];
+                 unsigned char *q;
+
+                 ql = ((p[8] << 8 | p[9]) + 7) / 8;            /* length of public modulus */
+                 if (ql >= 8 && 10 + ql + 2 <= l)
+                   {
+                     memcpy(keyid, p + 10 + ql - 8, 8);        /* keyid is last 64 bits of public modulus */
+                     q = p + 10 + ql;
+                     ql2 = ((q[0] << 8 | q[1]) + 7) / 8;       /* length of encryption exponent */
+                     if (10 + ql + 2 + ql2 <= l)
+                       {
+                         /* fingerprint is the md5 over the two MPI bodies */
+                         h = solv_chksum_create(REPOKEY_TYPE_MD5);
+                         solv_chksum_add(h, p + 10, ql);
+                         solv_chksum_add(h, q + 2, ql2);
+                         solv_chksum_free(h, fp);
+                         solv_bin2hex(fp, 16, fpx);
+                         repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
+                       }
+                   }
+                 pubdata = p + 7;
+                 pubdatal = l - 7;
+               }
+           }
+         else if (p[0] == 4 && l >= 6)
+           {
+             Chksum *h;
+             unsigned char hdr[3];
+             unsigned char fp[20];
+             char fpx[40 + 1];
+
+             maxsigcr = kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4];
+             hdr[0] = 0x99;
+             hdr[1] = l >> 8;
+             hdr[2] = l;
+             /* fingerprint is the sha1 over the packet */
+             h = solv_chksum_create(REPOKEY_TYPE_SHA1);
+             solv_chksum_add(h, hdr, 3);
+             solv_chksum_add(h, p, l);
+             solv_chksum_free(h, fp);
+             solv_bin2hex(fp, 20, fpx);
+             repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx);
+             memcpy(keyid, fp + 12, 8);        /* keyid is last 64 bits of fingerprint */
+             pubdata = p + 5;
+             pubdatal = l - 5;
+           }
+       }
+      if (tag == 2)            /* Signature Packet */
+       {
+         struct pgpsig sig;
+         Id htype;
+         if (!pubdata)
+           continue;
+         pgpsig_init(&sig, p, l);
+         if (!sig.haveissuer || !((sig.type >= 0x10 && sig.type <= 0x13) || sig.type == 0x1f))
+           continue;
+         if (sig.type >= 0x10 && sig.type <= 0x13 && !userid)
+           continue;
+         htype = pgphashalgo2type(sig.hashalgo);
+         if (htype && sig.mpioff)
+           {
+             Chksum *h = solv_chksum_create(htype);
+             pgpsig_makesigdata(&sig, p, l, pubkey, pubkeyl, userid, useridl, h);
+             solv_chksum_free(h, 0);
+           }
+         if (!memcmp(keyid, sig.issuer, 8))
+           {
+#ifdef ENABLE_PGPVRFY
+             /* found self sig, verify */
+             if (solv_pgpvrfy(pubdata, pubdatal, sig.sigdata, sig.sigdatal))
+#endif
+               {
+                 if (sig.keyexpires && maxex != -1)
+                   {
+                     if (sig.keyexpires == -1)
+                       maxex = -1;
+                     else if (sig.keyexpires + kcr > maxex)
+                       maxex = sig.keyexpires + kcr;
+                   }
+                 if (sig.created > maxsigcr)
+                   maxsigcr = sig.created;
+               }
+           }
+         else if (flags & ADD_WITH_KEYSIGNATURES)
+           {
+             char issuerstr[17];
+             Id shandle = repodata_new_handle(data);
+             solv_bin2hex(sig.issuer, 8, issuerstr);
+             repodata_set_str(data, shandle, SIGNATURE_ISSUER, issuerstr);
+             if (sig.created)
+               repodata_set_num(data, shandle, SIGNATURE_TIME, sig.created);
+             if (sig.expires)
+               repodata_set_num(data, shandle, SIGNATURE_EXPIRES, sig.created + sig.expires);
+             if (sig.sigdata)
+               repodata_set_binary(data, shandle, SIGNATURE_DATA, sig.sigdata, sig.sigdatal);
+             repodata_add_flexarray(data, s - s->repo->pool->solvables, PUBKEY_SIGNATURES, shandle);
+           }
+         solv_free(sig.sigdata);
+       }
+      if (tag == 13 && !insubkey)              /* User ID Packet */
+       {
+         userid = solv_realloc(userid, l);
+         if (l)
+           memcpy(userid, p, l);
+         useridl = l;
+       }
+    }
+  solv_free(pubkey);
+  solv_free(userid);
+  return p ? p - pstart : 0;
+}
+
+
+#ifdef ENABLE_RPMDB
+
+/* this is private to rpm, but rpm lacks an interface to retrieve
+ * the values. Sigh. */
+struct pgpDigParams_s {
+    const char * userid;
+    const unsigned char * hash;
+#ifndef HAVE_PGPDIGGETPARAMS
+    const char * params[4];
+#endif
+    unsigned char tag;
+    unsigned char version;               /*!< version number. */
+    unsigned char time[4];               /*!< time that the key was created. */
+    unsigned char pubkey_algo;           /*!< public key algorithm. */
+    unsigned char hash_algo;
+    unsigned char sigtype;
+    unsigned char hashlen;
+    unsigned char signhash16[2];
+    unsigned char signid[8];
+    unsigned char saved;
+};
+
+#ifndef HAVE_PGPDIGGETPARAMS
+struct pgpDig_s {
+    struct pgpDigParams_s signature;
+    struct pgpDigParams_s pubkey;
+};
+#endif
+
+
+/* only rpm knows how to do the release calculation, we don't dare
+ * to recreate all the bugs in libsolv */
+static void
+parsepubkey_rpm(Solvable *s, Repodata *data, unsigned char *pkts, int pktsl)
+{
+  Pool *pool = s->repo->pool;
+  struct pgpDigParams_s *digpubkey;
+  pgpDig dig = 0;
+  char keyid[16 + 1];
+  char evrbuf[8 + 1 + 8 + 1];
+  unsigned int btime;
+
+#ifndef RPM5
+  dig = pgpNewDig();
+#else
+  dig = pgpDigNew(RPMVSF_DEFAULT, 0);
+#endif
+  (void) pgpPrtPkts(pkts, pktsl, dig, 0);
+#ifdef HAVE_PGPDIGGETPARAMS
+  digpubkey = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
+#else
+  digpubkey = &dig->pubkey;
+#endif
+  if (digpubkey)
+    {
+      btime = digpubkey->time[0] << 24 | digpubkey->time[1] << 16 | digpubkey->time[2] << 8 | digpubkey->time[3];
+      solv_bin2hex(digpubkey->signid, 8, keyid);
+      solv_bin2hex(digpubkey->signid + 4, 4, evrbuf);
+      evrbuf[8] = '-';
+      solv_bin2hex(digpubkey->time, 4, evrbuf + 9);
+      s->evr = pool_str2id(pool, evrbuf, 1);
+      repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid);
+      if (digpubkey->userid)
+       setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, digpubkey->userid);
+      if (btime)
+       repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime);
+    }
+#ifndef RPM5
+  (void)pgpFreeDig(dig);
+#else
+  (void)pgpDigFree(dig);
+#endif
+}
+
+#endif /* ENABLE_RPMDB */
+
+/* parse an ascii armored pubkey
+ * adds multiple pubkeys if ADD_MULTIPLE_PUBKEYS is set */
+static int
+pubkey2solvable(Pool *pool, Id p, Repodata *data, char *pubkey, int flags)
+{
+  unsigned char *pkts, *pkts_orig;
+  int pktsl, pl = 0, tag, l, hl;
+
+  if (!unarmor(pubkey, &pkts, &pktsl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----"))
+    {
+      pool_error(pool, 0, "unarmor failure");
+      return 0;
+    }
+  pkts_orig = pkts;
+  tag = 6;
+  while (pktsl)
+    {
+      if (tag == 6)
+       {
+         setutf8string(data, p, SOLVABLE_DESCRIPTION, pubkey);
+         pl = parsepubkey(pool->solvables + p, data, pkts, pktsl, flags);
+#ifdef ENABLE_RPMDB
+         parsepubkey_rpm(pool->solvables + p, data, pkts, pktsl);
+#endif
+         if (!pl || !(flags & ADD_MULTIPLE_PUBKEYS))
+           break;
+       }
+      pkts += pl;
+      pktsl -= pl;
+      hl = parsepkgheader(pkts, pktsl, &tag, &l);
+      if (!hl)
+       break;
+      pl = l + hl;
+      if (tag == 6)
+        p = repo_add_solvable(pool->solvables[p].repo);
+    }
+  solv_free((void *)pkts_orig);
+  return 1;
+}
+
+#ifdef ENABLE_RPMDB
+
+int
+repo_add_rpmdb_pubkeys(Repo *repo, int flags)
+{
+  Pool *pool = repo->pool;
+  Queue q;
+  int i;
+  char *str;
+  Repodata *data;
+  const char *rootdir = 0;
+  void *state;
+
+  data = repo_add_repodata(repo, flags);
+  if (flags & REPO_USE_ROOTDIR)
+    rootdir = pool_get_rootdir(pool);
+  state = rpm_state_create(repo->pool, rootdir);
+  queue_init(&q);
+  rpm_installedrpmdbids(state, "Name", "gpg-pubkey", &q);
+  for (i = 0; i < q.count; i++)
+    {
+      Id p, p2;
+      void *handle;
+      unsigned long long itime;
+
+      handle = rpm_byrpmdbid(state, q.elements[i]);
+      if (!handle)
+       continue;
+      str = rpm_query(handle, SOLVABLE_DESCRIPTION);
+      if (!str)
+       continue;
+      p = repo_add_solvable(repo);
+      if (!pubkey2solvable(pool, p, data, str, flags))
+       {
+         solv_free(str);
+         repo_free_solvable(repo, p, 1);
+         continue;
+       }
+      solv_free(str);
+      itime = rpm_query_num(handle, SOLVABLE_INSTALLTIME, 0);
+      for (p2 = p; p2 < pool->nsolvables; p2++)
+       {
+         if (itime)
+           repodata_set_num(data, p2, SOLVABLE_INSTALLTIME, itime);
+         if (!repo->rpmdbid)
+           repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
+         repo->rpmdbid[p2 - repo->start] = q.elements[i];
+       }
+    }
+  queue_free(&q);
+  rpm_state_free(state);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+#endif
+
+static char *
+solv_slurp(FILE *fp, int *lenp)
+{
+  int l, ll;
+  char *buf = 0;
+  int bufl = 0;
+
+  for (l = 0; ; l += ll)
+    {
+      if (bufl - l < 4096)
+       {
+         bufl += 4096;
+         buf = solv_realloc(buf, bufl);
+       }
+      ll = fread(buf + l, 1, bufl - l, fp);
+      if (ll < 0)
+       {
+         buf = solv_free(buf);
+         l = 0;
+         break;
+       }
+      if (ll == 0)
+       {
+         buf[l] = 0;   /* always zero-terminate */
+         break;
+       }
+    }
+  if (lenp)
+    *lenp = l;
+  return buf;
+}
+
+Id
+repo_add_pubkey(Repo *repo, const char *keyfile, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  Id p;
+  char *buf;
+  FILE *fp;
+
+  data = repo_add_repodata(repo, flags);
+  buf = 0;
+  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keyfile) : keyfile, "r")) == 0)
+    {
+      pool_error(pool, -1, "%s: %s", keyfile, strerror(errno));
+      return 0;
+    }
+  if ((buf = solv_slurp(fp, 0)) == 0)
+    {
+      pool_error(pool, -1, "%s: %s", keyfile, strerror(errno));
+      fclose(fp);
+      return 0;
+    }
+  fclose(fp);
+  p = repo_add_solvable(repo);
+  if (!pubkey2solvable(pool, p, data, buf, flags))
+    {
+      repo_free_solvable(repo, p, 1);
+      solv_free(buf);
+      return 0;
+    }
+  if (!(flags & REPO_NO_LOCATION))
+    {
+      Id p2;
+      for (p2 = p; p2 < pool->nsolvables; p2++)
+        repodata_set_location(data, p2, 0, 0, keyfile);
+    }
+  solv_free(buf);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return p;
+}
+
+static int
+is_sig_packet(unsigned char *sig, int sigl)
+{
+  if (!sigl)
+    return 0;
+  if ((sig[0] & 0x80) == 0 || (sig[0] & 0x40 ? sig[0] & 0x3f : sig[0] >> 2 & 0x0f) != 2)
+    return 0;
+  return 1;
+}
+
+static int
+is_pubkey_packet(unsigned char *pkt, int pktl)
+{
+  if (!pktl)
+    return 0;
+  if ((pkt[0] & 0x80) == 0 || (pkt[0] & 0x40 ? pkt[0] & 0x3f : pkt[0] >> 2 & 0x0f) != 6)
+    return 0;
+  return 1;
+}
+
+static void
+add_one_pubkey(Pool *pool, Repo *repo, Repodata *data, unsigned char *pbuf, int pbufl, int flags)
+{
+  Id p = repo_add_solvable(repo);
+  char *solvversion = pool_tmpjoin(pool, "libsolv-", LIBSOLV_VERSION_STRING, 0);
+  char *descr = armor(pbuf, pbufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----", solvversion);
+  setutf8string(data, p, SOLVABLE_DESCRIPTION, descr);
+  parsepubkey(pool->solvables + p, data, pbuf, pbufl, flags);
+#ifdef ENABLE_RPMDB
+  parsepubkey_rpm(pool->solvables + p, data, pbuf, pbufl);
+#endif
+}
+
+int
+repo_add_keyring(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  unsigned char *buf, *p, *pbuf;
+  int bufl, l, pl, pbufl;
+
+  data = repo_add_repodata(repo, flags);
+  buf = (unsigned char *)solv_slurp(fp, &bufl);
+  if (buf && !is_pubkey_packet(buf, bufl))
+    {
+      /* assume ascii armored */
+      unsigned char *nbuf = 0, *ubuf;
+      int nl, ubufl;
+      bufl = 0;
+      for (l = 0; (nl = unarmor((char *)buf + l, &ubuf, &ubufl, "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----END PGP PUBLIC KEY BLOCK-----")) != 0; l += nl)
+       {
+         /* found another block. concat. */
+         nbuf = solv_realloc(nbuf, bufl + ubufl);
+         if (ubufl)
+           memcpy(nbuf + bufl, ubuf, ubufl);
+          bufl += ubufl;
+         solv_free(ubuf);
+       }
+      solv_free(buf);
+      buf = nbuf;
+    }
+  /* now split into pubkey parts, ignoring the packets we don't know */
+  pbuf = 0;
+  pbufl = 0;
+  for (p = buf; bufl; p += pl, bufl -= pl)
+    {
+      int tag;
+      int hl = parsepkgheader(p, bufl, &tag, &pl);
+      if (!hl)
+       break;
+      pl += hl;
+      if (tag == 6)
+       {
+         /* found new pubkey! flush old */
+         if (pbufl)
+           {
+             add_one_pubkey(pool, repo, data, pbuf, pbufl, flags);
+             pbuf = solv_free(pbuf);
+             pbufl = 0;
+           }
+       }
+      if (tag != 6 && !pbufl)
+       continue;
+      if (tag != 6 && tag != 2 && tag != 13 && tag != 14 && tag != 17)
+       continue;
+      /* we want that packet. concat. */
+      pbuf = solv_realloc(pbuf, pbufl + pl);
+      memcpy(pbuf + pbufl, p, pl);
+      pbufl += pl;
+    }
+  if (pbufl)
+    add_one_pubkey(pool, repo, data, pbuf, pbufl, flags);
+  solv_free(pbuf);
+  solv_free(buf);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+int
+repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  int i, nent, sl;
+  struct dirent **namelist;
+  char *rkeydir;
+
+  data = repo_add_repodata(repo, flags);
+  nent = scandir(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, keydir) : keydir, &namelist, 0, alphasort);
+  if (nent == -1)
+    return pool_error(pool, -1, "%s: %s", keydir, strerror(errno));
+  rkeydir = pool_prepend_rootdir(pool, keydir);
+  sl = suffix ? strlen(suffix) : 0;
+  for (i = 0; i < nent; i++)
+    {
+      const char *dn = namelist[i]->d_name;
+      int l;
+      if (*dn == '.' && !(flags & ADD_KEYDIR_WITH_DOTFILES))
+       continue;
+      l = strlen(dn);
+      if (sl && (l < sl || strcmp(dn + l - sl, suffix) != 0))
+       continue;
+      repo_add_pubkey(repo, pool_tmpjoin(pool, rkeydir, "/", dn), flags | REPO_REUSE_REPODATA);
+    }
+  solv_free(rkeydir);
+  for (i = 0; i < nent; i++)
+    solv_free(namelist[i]);
+  solv_free(namelist);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+Solvsig *
+solvsig_create(FILE *fp)
+{
+  Solvsig *ss;
+  unsigned char *sig;
+  int sigl, hl, tag, pktl;
+  struct pgpsig pgpsig;
+
+  if ((sig = (unsigned char *)solv_slurp(fp, &sigl)) == 0)
+    return 0;
+  if (!is_sig_packet(sig, sigl))
+    {
+      /* not a raw sig, check armored */
+      unsigned char *nsig;
+      if (!unarmor((char *)sig, &nsig, &sigl, "-----BEGIN PGP SIGNATURE-----", "-----END PGP SIGNATURE-----"))
+       {
+         solv_free(sig);
+         return 0;
+       }
+      solv_free(sig);
+      sig = nsig;
+      if (!is_sig_packet(sig, sigl))
+       {
+         solv_free(sig);
+         return 0;
+       }
+    }
+  hl = parsepkgheader(sig, sigl, &tag, &pktl);
+  if (!hl || tag != 2 || !pktl)
+    {
+      solv_free(sig);
+      return 0;
+    }
+  pgpsig_init(&pgpsig, sig + hl, pktl);
+  if (pgpsig.type != 0 || !pgpsig.haveissuer)
+    {
+      solv_free(sig);
+      return 0;
+    }
+  ss = solv_calloc(1, sizeof(*ss));
+  ss->sigpkt = solv_memdup(sig + hl, pktl);
+  ss->sigpktl = pktl;
+  solv_free(sig);
+  solv_bin2hex(pgpsig.issuer, 8, ss->keyid);
+  ss->htype = pgphashalgo2type(pgpsig.hashalgo);
+  ss->created = pgpsig.created;
+  ss->expires = pgpsig.expires;
+  return ss;
+}
+
+void
+solvsig_free(Solvsig *ss)
+{
+  solv_free(ss->sigpkt);
+  solv_free(ss);
+}
+
+static int
+repo_find_all_pubkeys_cmp(const void *va, const void *vb, void *dp)
+{
+  Pool *pool = dp;
+  Id a = *(Id *)va;
+  Id b = *(Id *)vb;
+  /* cannot use evrcmp, as rpm says '0' > 'a' */
+  return strcmp(pool_id2str(pool, pool->solvables[b].evr), pool_id2str(pool, pool->solvables[a].evr));
+}
+
+void
+repo_find_all_pubkeys(Repo *repo, const char *keyid, Queue *q)
+{
+  Id p;
+  Solvable *s;
+
+  queue_empty(q);
+  if (!keyid)
+    return;
+  queue_init(q);
+  FOR_REPO_SOLVABLES(repo, p, s)
+    {
+      const char *kidstr, *evr = pool_id2str(s->repo->pool, s->evr);
+
+      if (!evr || strncmp(evr, keyid + 8, 8) != 0)
+       continue;
+      kidstr = solvable_lookup_str(s, PUBKEY_KEYID);
+      if (kidstr && !strcmp(kidstr, keyid))
+        queue_push(q, p);
+    }
+  if (q->count > 1)
+    solv_sort(q->elements, q->count, sizeof(Id), repo_find_all_pubkeys_cmp, repo->pool);
+}
+
+Id
+repo_find_pubkey(Repo *repo, const char *keyid)
+{
+  Queue q;
+  Id p;
+  queue_init(&q);
+  repo_find_all_pubkeys(repo, keyid, &q);
+  p = q.count ? q.elements[0] : 0;
+  queue_free(&q);
+  return p;
+}
+
+#ifdef ENABLE_PGPVRFY
+
+/* warning: does not check key expiry/revokation, same as with gpgv or rpm */
+/* returns the Id of the pubkey that verified the signature */
+Id
+repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid)
+{
+  Id p;
+  Queue q;
+  int i;
+
+  if (!sigdata || !keyid)
+    return 0;
+  queue_init(&q);
+  repo_find_all_pubkeys(repo, keyid, &q);
+  for (i = 0; i < q.count; i++)
+    {
+      int pubdatal;
+      const unsigned char *pubdata = repo_lookup_binary(repo, q.elements[i], PUBKEY_DATA, &pubdatal);
+      if (pubdata && solv_pgpvrfy(pubdata, pubdatal, sigdata, sigdatal))
+       break;
+    }
+  p = i < q.count? q.elements[i] : 0;
+  queue_free(&q);
+  return p;
+}
+
+Id
+solvsig_verify(Solvsig *ss, Repo *repo, Chksum *chk)
+{
+  struct pgpsig pgpsig;
+  void *chk2;
+  Id p;
+
+  if (!chk || solv_chksum_isfinished(chk))
+    return 0;
+  pgpsig_init(&pgpsig, ss->sigpkt, ss->sigpktl);
+  chk2 = solv_chksum_create_clone(chk);
+  pgpsig_makesigdata(&pgpsig, ss->sigpkt, ss->sigpktl, 0, 0, 0, 0, chk2);
+  solv_chksum_free(chk2, 0);
+  if (!pgpsig.sigdata)
+    return 0;
+  p = repo_verify_sigdata(repo, pgpsig.sigdata, pgpsig.sigdatal, ss->keyid);
+  solv_free(pgpsig.sigdata);
+  return p;
+}
+
+#endif
+
diff --git a/libsolv-0.7.2/ext/repo_pubkey.h b/libsolv-0.7.2/ext/repo_pubkey.h
new file mode 100644 (file)
index 0000000..26cf0e1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include "repo.h"
+#include "chksum.h"
+
+#define ADD_KEYDIR_WITH_DOTFILES       (1 << 8)
+#define ADD_WITH_SUBKEYS               (1 << 9)
+#define ADD_MULTIPLE_PUBKEYS           (1 << 10)
+#define ADD_WITH_KEYSIGNATURES         (1 << 11)
+
+extern int repo_add_rpmdb_pubkeys(Repo *repo, int flags);
+extern Id repo_add_pubkey(Repo *repo, const char *keyfile, int flags);
+extern int repo_add_keyring(Repo *repo, FILE *fp, int flags);
+extern int repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags);
+
+/* signature parsing */
+typedef struct s_Solvsig {
+  unsigned char *sigpkt;
+  int sigpktl;
+  Id htype;
+  unsigned int created;
+  unsigned int expires;
+  char keyid[17];
+} Solvsig;
+
+Solvsig *solvsig_create(FILE *fp);
+void solvsig_free(Solvsig *ss);
+Id solvsig_verify(Solvsig *ss, Repo *repo, Chksum *chk);
+
+Id repo_verify_sigdata(Repo *repo, unsigned char *sigdata, int sigdatal, const char *keyid);
+Id repo_find_pubkey(Repo *repo, const char *keyid);
+void repo_find_all_pubkeys(Repo *repo, const char *keyid, Queue *q);
+
diff --git a/libsolv-0.7.2/ext/repo_releasefile_products.c b/libsolv-0.7.2/ext/repo_releasefile_products.c
new file mode 100644 (file)
index 0000000..a40bc98
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * repo_products.c
+ *
+ * Parses all files below 'proddir'
+ * See http://en.opensuse.org/Product_Management/Code11
+ *
+ *
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#define DISABLE_SPLIT
+#include "tools_util.h"
+#include "repo_releasefile_products.h"
+
+#define BUFF_SIZE 8192
+
+struct parsedata {
+  Repo *repo;
+  struct joindata jd;
+};
+
+static void
+add_releasefile_product(struct parsedata *pd, FILE *fp)
+{
+  Repo *repo = pd->repo;
+  Pool *pool = repo->pool;
+  char buf[BUFF_SIZE];
+  Id name = 0;
+  Id arch = 0;
+  Id version = 0;
+  int lnum = 0; /* line number */
+  char *ptr, *ptr1;
+
+  /* parse /etc/<xyz>-release file */
+  while (fgets(buf, sizeof(buf), fp))
+    {
+      /* remove trailing \n */
+      int l = strlen(buf);
+      if (l && buf[l - 1] == '\n')
+       buf[--l] = 0;
+      ++lnum;
+
+      if (lnum == 1)
+       {
+         /* 1st line, <name> [(<arch>)] */
+         ptr = strchr(buf, '(');
+         if (ptr)
+           {
+             ptr1 = ptr - 1;
+             *ptr++ = 0;
+           }
+         else
+           ptr1 = buf + l - 1;
+
+         /* track back until non-blank, non-digit */
+         while (ptr1 > buf
+                && (*ptr1 == ' ' || isdigit(*ptr1) || *ptr1 == '.'))
+           --ptr1;
+         *(++ptr1) = 0;
+         name = pool_str2id(pool, join2(&pd->jd, "product", ":", buf), 1);
+
+         if (ptr)
+           {
+             /* have arch */
+             char *ptr1 = strchr(ptr, ')');
+             if (ptr1)
+               {
+                 *ptr1 = 0;
+                 /* downcase arch */
+                 ptr1 = ptr;
+                 while (*ptr1)
+                   {
+                     if (isupper(*ptr1))
+                        *ptr1 = tolower(*ptr1);
+                     ++ptr1;
+                   }
+                 arch = pool_str2id(pool, ptr, 1);
+               }
+           }
+       }
+      else if (strncmp(buf, "VERSION", 7) == 0)
+       {
+         ptr = strchr(buf + 7, '=');
+         if (ptr)
+           {
+             while (*++ptr == ' ')
+               ;
+             version = makeevr(pool, ptr);
+           }
+       }
+    }
+  if (name)
+    {
+      Solvable *s = pool_id2solvable(pool, repo_add_solvable(repo));
+      s->name = name;
+      s->evr = version ? version : ID_EMPTY;
+      s->arch = arch ? arch : ARCH_NOARCH;
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+    }
+}
+
+
+int
+repo_add_releasefile_products(Repo *repo, const char *dirpath, int flags)
+{
+  DIR *dir;
+  struct dirent *entry;
+  FILE *fp;
+  char *fullpath;
+  struct parsedata pd;
+
+  if (!dirpath)
+    dirpath = "/etc";
+  if (flags & REPO_USE_ROOTDIR)
+    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
+  dir = opendir(dirpath);
+  if (!dir)
+    {
+      if (flags & REPO_USE_ROOTDIR)
+        solv_free((char *)dirpath);
+      return 0;
+    }
+
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  while ((entry = readdir(dir)))
+    {
+      int len = strlen(entry->d_name);
+      if (len > 8 && !strcmp(entry->d_name + len - 8, "-release"))
+        {
+         /* skip /etc/lsb-release, thats not a product per-se */
+         if (strcmp(entry->d_name, "lsb-release") == 0)
+           continue;
+         fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
+         if ((fp = fopen(fullpath, "r")) == 0)
+           {
+             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
+             continue;
+           }
+         add_releasefile_product(&pd, fp);
+         fclose(fp);
+       }
+    }
+  closedir(dir);
+  join_freemem(&pd.jd);
+  if (flags & REPO_USE_ROOTDIR)
+    solv_free((char *)dirpath);
+
+  if (!(flags & REPO_NO_INTERNALIZE) && (flags & REPO_REUSE_REPODATA) != 0)
+    repodata_internalize(repo_last_repodata(repo));
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/ext/repo_releasefile_products.h b/libsolv-0.7.2/ext/repo_releasefile_products.h
new file mode 100644 (file)
index 0000000..0535975
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_releasefile_products(Repo *repo, const char *dirpath, int flags);
diff --git a/libsolv-0.7.2/ext/repo_repomdxml.c b/libsolv-0.7.2/ext/repo_repomdxml.c
new file mode 100644 (file)
index 0000000..fd46272
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "solv_xmlparser.h"
+#include "repo_repomdxml.h"
+
+/*
+<repomd>
+
+  <!-- these tags are available in create repo > 0.9.6 -->
+  <revision>timestamp_or_arbitrary_user_supplied_string</revision>
+  <tags>
+    <content>opensuse</content>
+    <content>i386</content>
+    <content>other string</content>
+    <distro cpeid="cpe://o:opensuse_project:opensuse:11">openSUSE 11.0</distro>
+  </tags>
+  <!-- end -->
+
+  <data type="primary">
+    <location href="repodata/primary.xml.gz"/>
+    <checksum type="sha">e9162516fa25fec8d60caaf4682d2e49967786cc</checksum>
+    <timestamp>1215708444</timestamp>
+    <open-checksum type="sha">c796c48184cd5abc260e4ba929bdf01be14778a7</open-checksum>
+  </data>
+  <data type="filelists">
+    <location href="repodata/filelists.xml.gz"/>
+    <checksum type="sha">1c638295c49e9707c22810004ebb0799791fcf45</checksum>
+    <timestamp>1215708445</timestamp>
+    <open-checksum type="sha">54a40d5db3df0813b8acbe58cea616987eb9dc16</open-checksum>
+  </data>
+  <data type="other">
+    <location href="repodata/other.xml.gz"/>
+    <checksum type="sha">a81ef39eaa70e56048f8351055119d8c82af2491</checksum>
+    <timestamp>1215708447</timestamp>
+    <open-checksum type="sha">4d1ee867c8864025575a2fb8fde3b85371d51978</open-checksum>
+  </data>
+  <data type="deltainfo">
+    <location href="repodata/deltainfo.xml.gz"/>
+    <checksum type="sha">5880cfa5187026a24a552d3c0650904a44908c28</checksum>
+    <timestamp>1215708447</timestamp>
+    <open-checksum type="sha">7c964a2c3b17df5bfdd962c3be952c9ca6978d8b</open-checksum>
+  </data>
+  <data type="updateinfo">
+    <location href="repodata/updateinfo.xml.gz"/>
+    <checksum type="sha">4097f7e25c7bb0770ae31b2471a9c8c077ee904b</checksum>
+    <timestamp>1215708447</timestamp>
+    <open-checksum type="sha">24f8252f3dd041e37e7c3feb2d57e02b4422d316</open-checksum>
+  </data>
+  <data type="diskusage">
+    <location href="repodata/diskusage.xml.gz"/>
+    <checksum type="sha">4097f7e25c7bb0770ae31b2471a9c8c077ee904b</checksum>
+    <timestamp>1215708447</timestamp>
+    <open-checksum type="sha">24f8252f3dd041e37e7c3feb2d57e02b4422d316</open-checksum>
+  </data>
+</repomd>
+
+support also extension suseinfo format
+<suseinfo>
+  <expire>timestamp</expire>
+  <products>
+    <id>...</id>
+  </products>
+  <kewwords>
+    <k>...</k>
+  </keywords>
+</suseinfo>
+
+*/
+
+enum state {
+  STATE_START,
+  /* extension tags */
+  STATE_SUSEINFO,
+  STATE_EXPIRE,
+  STATE_KEYWORDS,
+  STATE_KEYWORD,
+
+  /* normal repomd.xml */
+  STATE_REPOMD,
+  STATE_REVISION,
+  STATE_TAGS,
+  STATE_REPO,
+  STATE_CONTENT,
+  STATE_DISTRO,
+  STATE_UPDATES,
+  STATE_DATA,
+  STATE_LOCATION,
+  STATE_CHECKSUM,
+  STATE_TIMESTAMP,
+  STATE_OPENCHECKSUM,
+  STATE_SIZE,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  /* suseinfo tags */
+  { STATE_START,       "repomd",          STATE_REPOMD, 0 },
+  { STATE_START,       "suseinfo",        STATE_SUSEINFO, 0 },
+  /* we support the tags element in suseinfo in case
+     createrepo version does not support it yet */
+  { STATE_SUSEINFO,    "tags",            STATE_TAGS, 0 },
+  { STATE_SUSEINFO,    "expire",          STATE_EXPIRE, 1 },
+  { STATE_SUSEINFO,    "keywords",        STATE_KEYWORDS, 0 },
+  /* keywords is the suse extension equivalent of
+     tags/content when this one was not yet available.
+     therefore we parse both */
+  { STATE_KEYWORDS,    "k",               STATE_KEYWORD, 1 },
+  /* standard tags */
+  { STATE_REPOMD,      "revision",        STATE_REVISION, 1 },
+  { STATE_REPOMD,      "tags",            STATE_TAGS,  0 },
+  { STATE_REPOMD,      "data",            STATE_DATA,  0 },
+
+  { STATE_TAGS,        "repo",            STATE_REPO,    1 },
+  { STATE_TAGS,        "content",         STATE_CONTENT, 1 },
+  { STATE_TAGS,        "distro",          STATE_DISTRO,  1 },
+  /* this tag is only valid in suseinfo.xml for now */
+  { STATE_TAGS,        "updates",         STATE_UPDATES,  1 },
+
+  { STATE_DATA,        "location",        STATE_LOCATION, 0 },
+  { STATE_DATA,        "checksum",        STATE_CHECKSUM, 1 },
+  { STATE_DATA,        "timestamp",       STATE_TIMESTAMP, 1 },
+  { STATE_DATA,        "open-checksum",   STATE_OPENCHECKSUM, 1 },
+  { STATE_DATA,        "size",            STATE_SIZE, 1 },
+  { NUMSTATES }
+};
+
+
+struct parsedata {
+  int ret;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+
+  struct solv_xmlparser xmlp;
+
+  int timestamp;
+  /* handles for collection
+     structures */
+  /* repo updates */
+  Id ruhandle;
+  /* repo products */
+  Id rphandle;
+  /* repo data handle */
+  Id rdhandle;
+
+  Id chksumtype;
+};
+
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+
+  switch(state)
+    {
+    case STATE_REPOMD:
+      {
+        const char *updstr;
+
+        /* this should be OBSOLETE soon */
+        updstr = solv_xmlparser_find_attr("updates", atts);
+        if (updstr)
+          {
+            char *value = solv_strdup(updstr);
+            char *fvalue = value; /* save the first */
+            while (value)
+             {
+               char *p = strchr(value, ',');
+               if (*p)
+                 *p++ = 0;
+               if (*value)
+                 repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value);
+               value = p;
+             }
+           solv_free(fvalue);
+          }
+        break;
+      }
+    case STATE_DISTRO:
+      {
+        /* this is extra metadata about the product this repository
+           was designed for */
+        const char *cpeid = solv_xmlparser_find_attr("cpeid", atts);
+        pd->rphandle = repodata_new_handle(pd->data);
+        /* set the cpeid for the product
+           the label is set in the content of the tag */
+        if (cpeid)
+          repodata_set_poolstr(pd->data, pd->rphandle, REPOSITORY_PRODUCT_CPEID, cpeid);
+        break;
+      }
+    case STATE_UPDATES:
+      {
+        /* this is extra metadata about the product this repository
+           was designed for */
+        const char *cpeid = solv_xmlparser_find_attr("cpeid", atts);
+        pd->ruhandle = repodata_new_handle(pd->data);
+        /* set the cpeid for the product
+           the label is set in the content of the tag */
+        if (cpeid)
+          repodata_set_poolstr(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_CPEID, cpeid);
+        break;
+      }
+    case STATE_DATA:
+      {
+        const char *type= solv_xmlparser_find_attr("type", atts);
+        pd->rdhandle = repodata_new_handle(pd->data);
+       if (type)
+          repodata_set_poolstr(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TYPE, type);
+        break;
+      }
+    case STATE_LOCATION:
+      {
+        const char *href = solv_xmlparser_find_attr("href", atts);
+       if (href)
+          repodata_set_str(pd->data, pd->rdhandle, REPOSITORY_REPOMD_LOCATION, href);
+        break;
+      }
+    case STATE_CHECKSUM:
+    case STATE_OPENCHECKSUM:
+      {
+        const char *type= solv_xmlparser_find_attr("type", atts);
+        pd->chksumtype = type && *type ? solv_chksum_str2type(type) : 0;
+       if (!pd->chksumtype)
+          pd->ret = pool_error(pd->pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), type ? type : "NULL");
+        break;
+      }
+    default:
+      break;
+    }
+  return;
+}
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  switch (state)
+    {
+    case STATE_REPOMD:
+      if (pd->timestamp > 0)
+        repodata_set_num(pd->data, SOLVID_META, REPOSITORY_TIMESTAMP, pd->timestamp);
+      break;
+    case STATE_DATA:
+      if (pd->rdhandle)
+        repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_REPOMD, pd->rdhandle);
+      pd->rdhandle = 0;
+      break;
+
+    case STATE_CHECKSUM:
+    case STATE_OPENCHECKSUM:
+      if (!pd->chksumtype)
+       break;
+      if (strlen(content) != 2 * solv_chksum_len(pd->chksumtype))
+        pd->ret = pool_error(pd->pool, -1, "line %d: invalid checksum length for %s", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype));
+      else
+        repodata_set_checksum(pd->data, pd->rdhandle, state == STATE_CHECKSUM ? REPOSITORY_REPOMD_CHECKSUM : REPOSITORY_REPOMD_OPENCHECKSUM, pd->chksumtype, content);
+      break;
+
+    case STATE_TIMESTAMP:
+      {
+        /**
+         * we want to look for the newest timestamp
+         * of all resources to save it as the time
+         * the metadata was generated
+         */
+        int timestamp = atoi(content);
+       if (timestamp)
+          repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_TIMESTAMP, timestamp);
+        if (timestamp > pd->timestamp)
+          pd->timestamp = timestamp;
+        break;
+      }
+    case STATE_EXPIRE:
+      {
+        int expire = atoi(content);
+       if (expire > 0)
+         repodata_set_num(pd->data, SOLVID_META, REPOSITORY_EXPIRE, expire);
+        break;
+      }
+      /* repomd.xml content and suseinfo.xml keywords are equivalent */
+    case STATE_CONTENT:
+    case STATE_KEYWORD:
+      if (*content)
+       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_KEYWORDS, content);
+      break;
+    case STATE_REVISION:
+      if (*content)
+       repodata_set_str(pd->data, SOLVID_META, REPOSITORY_REVISION, content);
+      break;
+    case STATE_DISTRO:
+      /* distro tag is used in repomd.xml to say the product this repo is
+         made for */
+      if (*content)
+        repodata_set_str(pd->data, pd->rphandle, REPOSITORY_PRODUCT_LABEL, content);
+      repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_DISTROS, pd->rphandle);
+      break;
+    case STATE_UPDATES:
+      /* updates tag is used in suseinfo.xml to say the repo updates a product
+         however it s not yet a tag standarized for repomd.xml */
+      if (*content)
+        repodata_set_str(pd->data, pd->ruhandle, REPOSITORY_PRODUCT_LABEL, content);
+      repodata_add_flexarray(pd->data, SOLVID_META, REPOSITORY_UPDATES, pd->ruhandle);
+      break;
+    case STATE_REPO:
+      if (*content)
+       repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_REPOID, content);
+      break;
+    case STATE_SIZE:
+      if (*content)
+       repodata_set_num(pd->data, pd->rdhandle, REPOSITORY_REPOMD_SIZE, strtoull(content, 0, 10));
+      break;
+    default:
+      break;
+    }
+}
+
+int
+repo_add_repomdxml(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  struct parsedata pd;
+  Repodata *data;
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.timestamp = 0;
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pd.pool, -1, "repo_repomdxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+
+  return pd.ret;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/ext/repo_repomdxml.h b/libsolv-0.7.2/ext/repo_repomdxml.h
new file mode 100644 (file)
index 0000000..90d9d69
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_repomdxml(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.7.2/ext/repo_rpmdb.c b/libsolv-0.7.2/ext/repo_rpmdb.c
new file mode 100644 (file)
index 0000000..9acb400
--- /dev/null
@@ -0,0 +1,2486 @@
+/*
+ * Copyright (c) 2007-2018, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_rpmdb
+ *
+ * convert rpm db to repo
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#ifdef ENABLE_RPMDB
+
+#include <rpm/rpmio.h>
+#include <rpm/rpmpgp.h>
+#ifndef RPM5
+#include <rpm/header.h>
+#endif
+#include <rpm/rpmdb.h>
+
+#endif
+
+#include "pool.h"
+#include "repo.h"
+#include "hash.h"
+#include "util.h"
+#include "queue.h"
+#include "chksum.h"
+#include "repo_rpmdb.h"
+#include "repo_solv.h"
+#ifdef ENABLE_COMPLEX_DEPS
+#include "pool_parserpmrichdep.h"
+#endif
+
+/* 3: added triggers */
+/* 4: fixed triggers */
+/* 5: fixed checksum copying */
+/* 6: add SOLVABLE_PREREQ_IGNOREINST support */
+/* 7: fix bug in ignoreinst logic */
+#define RPMDB_COOKIE_VERSION 7
+
+#define TAG_NAME               1000
+#define TAG_VERSION            1001
+#define TAG_RELEASE            1002
+#define TAG_EPOCH              1003
+#define TAG_SUMMARY            1004
+#define TAG_DESCRIPTION                1005
+#define TAG_BUILDTIME          1006
+#define TAG_BUILDHOST          1007
+#define TAG_INSTALLTIME                1008
+#define TAG_SIZE               1009
+#define TAG_DISTRIBUTION       1010
+#define TAG_VENDOR             1011
+#define TAG_LICENSE            1014
+#define TAG_PACKAGER           1015
+#define TAG_GROUP              1016
+#define TAG_URL                        1020
+#define TAG_ARCH               1022
+#define TAG_FILESIZES          1028
+#define TAG_FILEMODES          1030
+#define TAG_FILEMD5S           1035
+#define TAG_FILELINKTOS                1036
+#define TAG_FILEFLAGS          1037
+#define TAG_SOURCERPM          1044
+#define TAG_PROVIDENAME                1047
+#define TAG_REQUIREFLAGS       1048
+#define TAG_REQUIRENAME                1049
+#define TAG_REQUIREVERSION     1050
+#define TAG_NOSOURCE           1051
+#define TAG_NOPATCH            1052
+#define TAG_CONFLICTFLAGS      1053
+#define TAG_CONFLICTNAME       1054
+#define TAG_CONFLICTVERSION    1055
+#define TAG_TRIGGERNAME                1066
+#define TAG_TRIGGERVERSION     1067
+#define TAG_TRIGGERFLAGS       1068
+#define TAG_CHANGELOGTIME      1080
+#define TAG_CHANGELOGNAME      1081
+#define TAG_CHANGELOGTEXT      1082
+#define TAG_OBSOLETENAME       1090
+#define TAG_FILEDEVICES                1095
+#define TAG_FILEINODES         1096
+#define TAG_SOURCEPACKAGE      1106
+#define TAG_PROVIDEFLAGS       1112
+#define TAG_PROVIDEVERSION     1113
+#define TAG_OBSOLETEFLAGS      1114
+#define TAG_OBSOLETEVERSION    1115
+#define TAG_DIRINDEXES         1116
+#define TAG_BASENAMES          1117
+#define TAG_DIRNAMES           1118
+#define TAG_PAYLOADFORMAT      1124
+#define TAG_PATCHESNAME                1133
+#define TAG_FILECOLORS         1140
+#define TAG_OLDSUGGESTSNAME    1156
+#define TAG_OLDSUGGESTSVERSION 1157
+#define TAG_OLDSUGGESTSFLAGS   1158
+#define TAG_OLDENHANCESNAME    1159
+#define TAG_OLDENHANCESVERSION 1160
+#define TAG_OLDENHANCESFLAGS   1161
+
+/* rpm5 tags */
+#define TAG_DISTEPOCH          1218
+
+/* rpm4 tags */
+#define TAG_LONGFILESIZES      5008
+#define TAG_LONGSIZE           5009
+#define TAG_RECOMMENDNAME      5046
+#define TAG_RECOMMENDVERSION   5047
+#define TAG_RECOMMENDFLAGS     5048
+#define TAG_SUGGESTNAME                5049
+#define TAG_SUGGESTVERSION     5050
+#define TAG_SUGGESTFLAGS       5051
+#define TAG_SUPPLEMENTNAME     5052
+#define TAG_SUPPLEMENTVERSION  5053
+#define TAG_SUPPLEMENTFLAGS    5054
+#define TAG_ENHANCENAME                5055
+#define TAG_ENHANCEVERSION     5056
+#define TAG_ENHANCEFLAGS       5057
+
+/* signature tags */
+#define        TAG_SIGBASE             256
+#define TAG_SIGMD5             (TAG_SIGBASE + 5)
+#define TAG_SHA1HEADER         (TAG_SIGBASE + 13)
+#define TAG_SHA256HEADER       (TAG_SIGBASE + 17)
+
+#define SIGTAG_SIZE            1000
+#define SIGTAG_PGP             1002    /* RSA signature */
+#define SIGTAG_MD5             1004    /* header+payload md5 checksum */
+#define SIGTAG_GPG             1005    /* DSA signature */
+
+#define DEP_LESS               (1 << 1)
+#define DEP_GREATER            (1 << 2)
+#define DEP_EQUAL              (1 << 3)
+#define DEP_STRONG             (1 << 27)
+#define DEP_PRE_IN             ((1 << 6) | (1 << 9) | (1 << 10))
+#define DEP_PRE_UN             ((1 << 6) | (1 << 11) | (1 << 12))
+
+#define FILEFLAG_GHOST         (1 << 6)
+
+
+/* some limits to guard against corrupt rpms */
+/* dsize limits taken from rpm's lib/header.c */
+#define MAX_SIG_CNT            0x10000
+#define MAX_SIG_DSIZE          0x4000000
+
+#define MAX_HDR_CNT            0x10000
+#define MAX_HDR_DSIZE          0x10000000
+
+
+#ifndef ENABLE_RPMPKG_LIBRPM
+
+typedef struct rpmhead {
+  int cnt;
+  unsigned int dcnt;
+  unsigned char *dp;
+  unsigned char data[1];
+} RpmHead;
+
+
+static inline unsigned char *
+headfindtag(RpmHead *h, int tag)
+{
+  unsigned int i;
+  unsigned char *d, taga[4];
+  d = h->dp - 16;
+  taga[0] = tag >> 24;
+  taga[1] = tag >> 16;
+  taga[2] = tag >> 8;
+  taga[3] = tag;
+  for (i = 0; i < h->cnt; i++, d -= 16)
+    if (d[3] == taga[3] && d[2] == taga[2] && d[1] == taga[1] && d[0] == taga[0])
+      return d;
+  return 0;
+}
+
+static int
+headexists(RpmHead *h, int tag)
+{
+  return headfindtag(h, tag) ? 1 : 0;
+}
+
+static uint32_t *
+headint32array(RpmHead *h, int tag, int *cnt)
+{
+  uint32_t *r;
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
+    return 0;
+  d = h->dp + o;
+  r = solv_calloc(i ? i : 1, sizeof(uint32_t));
+  if (cnt)
+    *cnt = i;
+  for (o = 0; o < i; o++, d += 4)
+    r[o] = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+  return r;
+}
+
+/* returns the first entry of an integer array */
+static uint32_t
+headint32(RpmHead *h, int tag)
+{
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (i == 0 || o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
+    return 0;
+  d = h->dp + o;
+  return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+}
+
+static uint64_t *
+headint64array(RpmHead *h, int tag, int *cnt)
+{
+  uint64_t *r;
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
+    return 0;
+  d = h->dp + o;
+  r = solv_calloc(i ? i : 1, sizeof(uint64_t));
+  if (cnt)
+    *cnt = i;
+  for (o = 0; o < i; o++, d += 8)
+    {
+      uint32_t x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+      r[o] = (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+    }
+  return r;
+}
+
+/* returns the first entry of an 64bit integer array */
+static uint64_t
+headint64(RpmHead *h, int tag)
+{
+  uint32_t x;
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
+    return 0;
+  d = h->dp + o;
+  x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+  return (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+}
+
+static uint16_t *
+headint16array(RpmHead *h, int tag, int *cnt)
+{
+  uint16_t *r;
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt)
+    return 0;
+  d = h->dp + o;
+  r = solv_calloc(i ? i : 1, sizeof(uint16_t));
+  if (cnt)
+    *cnt = i;
+  for (o = 0; o < i; o++, d += 2)
+    r[o] = d[0] << 8 | d[1];
+  return r;
+}
+
+static char *
+headstring(RpmHead *h, int tag)
+{
+  unsigned int o;
+  unsigned char *d = headfindtag(h, tag);
+  /* 6: STRING, 9: I18NSTRING */
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || (d[7] != 6 && d[7] != 9))
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  if (o >= h->dcnt)
+    return 0;
+  return (char *)h->dp + o;
+}
+
+static char **
+headstringarray(RpmHead *h, int tag, int *cnt)
+{
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+  char **r;
+
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o > h->dcnt || i > h->dcnt)
+    return 0;
+  r = solv_calloc(i ? i : 1, sizeof(char *));
+  if (cnt)
+    *cnt = i;
+  d = h->dp + o;
+  for (o = 0; o < i; o++)
+    {
+      r[o] = (char *)d;
+      if (o + 1 < i)
+        d += strlen((char *)d) + 1;
+      if (d >= h->dp + h->dcnt)
+        {
+          solv_free(r);
+          return 0;
+        }
+    }
+  return r;
+}
+
+static unsigned char *
+headbinary(RpmHead *h, int tag, unsigned int *sizep)
+{
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, tag);
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 7)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  if (o > h->dcnt || i > h->dcnt || o + i > h->dcnt)
+    return 0;
+  if (sizep)
+    *sizep = i;
+  return h->dp + o;
+}
+
+static int
+headissourceheuristic(RpmHead *h)
+{
+  unsigned int i, o;
+  unsigned char *d = headfindtag(h, TAG_DIRNAMES);
+  if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8)
+    return 0;
+  o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
+  i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+  return i == 1 && o < h->dcnt && !h->dp[o] ? 1 : 0;
+}
+
+static inline void
+headfree(RpmHead *h)
+{
+  solv_free(h);
+}
+
+#else
+
+typedef struct headerToken_s RpmHead;
+
+static int
+headexists(RpmHead *h, int tag)
+{
+  return headerIsEntry(h, tag);
+}
+
+static void *headget(RpmHead *h, int tag, int *cnt, int alloc)
+{
+  struct rpmtd_s td;
+  if (!headerGet(h, tag, &td, alloc ? HEADERGET_ALLOC : HEADERGET_MINMEM))
+    return 0;
+  if (cnt)
+    *cnt = td.count;
+  return td.data;
+}
+
+static uint32_t *
+headint32array(RpmHead *h, int tag, int *cnt)
+{
+  return headget(h, tag, cnt, 1);
+}
+
+static uint32_t
+headint32(RpmHead *h, int tag)
+{
+  uint32_t *arr = headget(h, tag, 0, 0);
+  return arr ? arr[0] : 0;
+}
+
+static uint64_t *
+headint64array(RpmHead *h, int tag, int *cnt)
+{
+  return headget(h, tag, cnt, 1);
+}
+
+/* returns the first entry of an 64bit integer array */
+static uint64_t
+headint64(RpmHead *h, int tag)
+{
+  uint64_t *arr = headget(h, tag, 0, 0);
+  return arr ? arr[0] : 0;
+}
+
+static uint16_t *
+headint16array(RpmHead *h, int tag, int *cnt)
+{
+  return headget(h, tag, cnt, 1);
+}
+
+static char *
+headstring(RpmHead *h, int tag)
+{
+  return headget(h, tag, 0, 0);
+}
+
+static char **
+headstringarray(RpmHead *h, int tag, int *cnt)
+{
+  return headget(h, tag, cnt, 1);
+}
+
+static unsigned char *
+headbinary(RpmHead *h, int tag, unsigned int *sizep)
+{
+  unsigned char *b = headget(h, tag, (int *)sizep, 0);
+  if (b && sizep && (tag == TAG_SIGMD5 || tag == SIGTAG_MD5) && *sizep > 16) {
+    /* due to a bug in rpm the count may be bigger if HEADERIMPORT_FAST is used */
+    *sizep = 16;
+  }
+  return b;
+}
+
+static int
+headissourceheuristic(RpmHead *h)
+{
+  struct rpmtd_s td;
+  int issource;
+  if (!headerGet(h, TAG_DIRNAMES, &td, HEADERGET_MINMEM))
+    return 0;
+  issource = td.count == 1 && td.data && ((char **)td.data)[0] && !((char **)td.data)[0][0];
+  rpmtdFreeData(&td);
+  return issource;
+}
+
+static inline void
+headfree(RpmHead *h)
+{
+  headerFree(h);
+}
+
+#endif
+
+static char *headtoevr(RpmHead *h)
+{
+  unsigned int epoch;
+  char *version, *v;
+  char *release;
+  char *evr;
+  char *distepoch;
+
+  version  = headstring(h, TAG_VERSION);
+  release  = headstring(h, TAG_RELEASE);
+  epoch = headint32(h, TAG_EPOCH);
+  if (!version || !release)
+    return 0;
+  for (v = version; *v >= '0' && *v <= '9'; v++)
+    ;
+  if (epoch || (v != version && *v == ':'))
+    {
+      char epochbuf[11];        /* 32bit decimal will fit in */
+      sprintf(epochbuf, "%u", epoch);
+      evr = solv_malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1);
+      sprintf(evr, "%s:%s-%s", epochbuf, version, release);
+    }
+  else
+    {
+      evr = solv_malloc(strlen(version) + 1 + strlen(release) + 1);
+      sprintf(evr, "%s-%s", version, release);
+    }
+  distepoch = headstring(h, TAG_DISTEPOCH);
+  if (distepoch && *distepoch)
+    {
+      int l = strlen(evr);
+      evr = solv_realloc(evr, l + strlen(distepoch) + 2);
+      evr[l++] = ':';
+      strcpy(evr + l, distepoch);
+    }
+  return evr;
+}
+
+
+static void
+setutf8string(Repodata *repodata, Id handle, Id tag, const char *str)
+{
+  if (str[solv_validutf8(str)])
+    {
+      char *ustr = solv_latin1toutf8(str);     /* not utf8, assume latin1 */
+      repodata_set_str(repodata, handle, tag, ustr);
+      solv_free(ustr);
+    }
+  else
+    repodata_set_str(repodata, handle, tag, str);
+}
+
+static int
+ignq_sortcmp(const void *va, const void *vb, void *dp)
+{
+  int r = *(Id *)va - *(Id *)vb;
+  if (!r)
+    r = ((Id *)va)[1] - ((Id *)vb)[1];
+  return r;
+}
+
+/*
+ * strong: 0: ignore strongness
+ *         1: filter to strong
+ *         2: filter to weak
+ */
+static unsigned int
+makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq)
+{
+  char **n, **v;
+  uint32_t *f;
+  int i, cc, nc, vc, fc;
+  int haspre, premask, has_ign;
+  unsigned int olddeps;
+  Id *ida;
+  int strong = 0;
+
+  n = headstringarray(rpmhead, tagn, &nc);
+  if (!n)
+    {
+      switch (tagn)
+       {
+       case TAG_SUGGESTNAME:
+         tagn = TAG_OLDSUGGESTSNAME;
+         tagv = TAG_OLDSUGGESTSVERSION;
+         tagf = TAG_OLDSUGGESTSFLAGS;
+         strong = -1;
+         break;
+       case TAG_ENHANCENAME:
+         tagn = TAG_OLDENHANCESNAME;
+         tagv = TAG_OLDENHANCESVERSION;
+         tagf = TAG_OLDENHANCESFLAGS;
+         strong = -1;
+         break;
+       case TAG_RECOMMENDNAME:
+         tagn = TAG_OLDSUGGESTSNAME;
+         tagv = TAG_OLDSUGGESTSVERSION;
+         tagf = TAG_OLDSUGGESTSFLAGS;
+         strong = 1;
+         break;
+       case TAG_SUPPLEMENTNAME:
+         tagn = TAG_OLDENHANCESNAME;
+         tagv = TAG_OLDENHANCESVERSION;
+         tagf = TAG_OLDENHANCESFLAGS;
+         strong = 1;
+         break;
+       default:
+         return 0;
+       }
+      n = headstringarray(rpmhead, tagn, &nc);
+    }
+  if (!n || !nc)
+    return 0;
+  vc = fc = 0;
+  v = headstringarray(rpmhead, tagv, &vc);
+  f = headint32array(rpmhead, tagf, &fc);
+  if (!v || !f || nc != vc || nc != fc)
+    {
+      char *pkgname = rpm_query(rpmhead, 0);
+      pool_error(pool, 0, "bad dependency entries for %s: %d %d %d", pkgname ? pkgname : "<NULL>", nc, vc, fc);
+      solv_free(pkgname);
+      solv_free(n);
+      solv_free(v);
+      solv_free(f);
+      return 0;
+    }
+
+  cc = nc;
+  haspre = 0;  /* add no prereq marker */
+  premask = tagn == TAG_REQUIRENAME ? DEP_PRE_IN | DEP_PRE_UN : 0;
+  if ((flags & RPM_ADD_NO_RPMLIBREQS) || strong)
+    {
+      /* we do filtering */
+      cc = 0;
+      for (i = 0; i < nc; i++)
+       {
+         if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
+           continue;
+         if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
+           if (!strncmp(n[i], "rpmlib(", 7))
+             continue;
+         if ((f[i] & premask) != 0)
+           haspre = 1;
+         cc++;
+       }
+    }
+  else if (premask)
+    {
+      /* no filtering, just look for the first prereq */
+      for (i = 0; i < nc; i++)
+       if ((f[i] & premask) != 0)
+         {
+           haspre = 1;
+           break;
+         }
+    }
+  if (cc == 0)
+    {
+      solv_free(n);
+      solv_free(v);
+      solv_free(f);
+      return 0;
+    }
+  cc += haspre;                /* add slot for the prereq marker */
+  olddeps = repo_reserve_ids(repo, 0, cc);
+  ida = repo->idarraydata + olddeps;
+
+  has_ign = 0;
+  for (i = 0; ; i++)
+    {
+      Id id;
+      if (i == nc)
+       {
+         if (haspre != 1)
+           break;
+         haspre = 2;   /* pass two: prereqs */
+         i = 0;
+         *ida++ = SOLVABLE_PREREQMARKER;
+       }
+      if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
+       continue;
+      if (haspre)
+       {
+         if (haspre == 1 && (f[i] & premask) != 0)
+           continue;
+         if (haspre == 2 && (f[i] & premask) == 0)
+           continue;
+       }
+      if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
+       if (!strncmp(n[i], "rpmlib(", 7))
+         continue;
+#ifdef ENABLE_COMPLEX_DEPS
+      if ((f[i] & (DEP_LESS|DEP_EQUAL|DEP_GREATER)) == 0 && n[i][0] == '(')
+       {
+         id = pool_parserpmrichdep(pool, n[i]);
+         if (id)
+           *ida++ = id;
+         else
+           cc--;
+         continue;
+       }
+#endif
+      id = pool_str2id(pool, n[i], 1);
+      if (f[i] & (DEP_LESS|DEP_GREATER|DEP_EQUAL))
+       {
+         Id evr;
+         int fl = 0;
+         if ((f[i] & DEP_LESS) != 0)
+           fl |= REL_LT;
+         if ((f[i] & DEP_EQUAL) != 0)
+           fl |= REL_EQ;
+         if ((f[i] & DEP_GREATER) != 0)
+           fl |= REL_GT;
+         if (v[i][0] == '0' && v[i][1] == ':' && v[i][2])
+           evr = pool_str2id(pool, v[i] + 2, 1);
+         else
+           evr = pool_str2id(pool, v[i], 1);
+         id = pool_rel2id(pool, id, evr, fl, 1);
+       }
+      *ida++ = id;
+      if (haspre == 2 && ignq)
+       {
+         int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0;
+         has_ign |= is_ign;
+         queue_push2(ignq, id, is_ign);
+       }
+    }
+  *ida++ = 0;
+  repo->idarraysize += cc + 1;
+  solv_free(n);
+  solv_free(v);
+  solv_free(f);
+  if (ignq && ignq->count)
+    {
+      int j = 0;
+      if (has_ign && ignq->count == 2)
+       j = 1;
+      else if (has_ign)
+       {
+         Id id, lastid = 0;
+
+         solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0);
+         for (i = j = 0; i < ignq->count; i += 2)
+           {
+             id = ignq->elements[i];
+             if (id != lastid && ignq->elements[i + 1] > 0)
+               ignq->elements[j++] = id;
+             lastid = id;
+           }
+       }
+      queue_truncate(ignq, j);
+    }
+  return olddeps;
+}
+
+static Id
+repodata_str2dir_rooted(Repodata *data, char *str, int create)
+{
+  char buf[256], *bp;
+  int l = strlen(str);
+  Id id;
+
+  if (l + 2 <= sizeof(buf))
+    bp = buf;
+  else
+    bp = solv_malloc(l + 2);
+  bp[0] = '/';
+  strcpy(bp + 1, str);
+  id = repodata_str2dir(data, bp, create);
+  if (bp != buf)
+    solv_free(bp);
+  return id;
+}
+
+static void
+adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, uint32_t *di, int fc, int dc)
+{
+  Id did;
+  int i, fszc;
+  unsigned int *fkb, *fn;
+  uint64_t *fsz64;
+  uint32_t *fsz, *fino;
+  uint16_t *fm;
+  unsigned int inotest[256], inotestok;
+
+  if (!fc)
+    return;
+  if ((fsz64 = headint64array(rpmhead, TAG_LONGFILESIZES, &fszc)) != 0)
+    {
+      /* convert to kbyte */
+      fsz = solv_malloc2(fszc, sizeof(*fsz));
+      for (i = 0; i < fszc; i++)
+        fsz[i] = fsz64[i] ? fsz64[i] / 1024 + 1 : 0;
+      solv_free(fsz64);
+    }
+  else if ((fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc)) != 0)
+    {
+      /* convert to kbyte */
+      for (i = 0; i < fszc; i++)
+        if (fsz[i])
+         fsz[i] = fsz[i] / 1024 + 1;
+    }
+  else
+    return;
+  if (fc != fszc)
+    {
+      solv_free(fsz);
+      return;
+    }
+
+  /* stupid rpm records sizes of directories, so we have to check the mode */
+  fm = headint16array(rpmhead, TAG_FILEMODES, &fszc);
+  if (!fm || fc != fszc)
+    {
+      solv_free(fsz);
+      solv_free(fm);
+      return;
+    }
+  fino = headint32array(rpmhead, TAG_FILEINODES, &fszc);
+  if (!fino || fc != fszc)
+    {
+      solv_free(fsz);
+      solv_free(fm);
+      solv_free(fino);
+      return;
+    }
+
+  /* kill hardlinked entries */
+  inotestok = 0;
+  if (fc < sizeof(inotest))
+    {
+      /* quick test just hashing the inode numbers */
+      memset(inotest, 0, sizeof(inotest));
+      for (i = 0; i < fc; i++)
+       {
+         int off, bit;
+         if (fsz[i] == 0 || !S_ISREG(fm[i]))
+           continue;   /* does not matter */
+         off = (fino[i] >> 5) & (sizeof(inotest)/sizeof(*inotest) - 1);
+         bit = 1 << (fino[i] & 31);
+         if ((inotest[off] & bit) != 0)
+           break;
+         inotest[off] |= bit;
+       }
+      if (i == fc)
+       inotestok = 1;  /* no conflict found */
+    }
+  if (!inotestok)
+    {
+      /* hardlinked files are possible, check ino/dev pairs */
+      unsigned int *fdev = headint32array(rpmhead, TAG_FILEDEVICES, &fszc);
+      unsigned int *fx, j;
+      unsigned int mask, hash, hh;
+      if (!fdev || fc != fszc)
+       {
+         solv_free(fsz);
+         solv_free(fm);
+         solv_free(fdev);
+         solv_free(fino);
+         return;
+       }
+      mask = fc;
+      while ((mask & (mask - 1)) != 0)
+       mask = mask & (mask - 1);
+      mask <<= 2;
+      if (mask > sizeof(inotest)/sizeof(*inotest))
+        fx = solv_calloc(mask, sizeof(unsigned int));
+      else
+       {
+         fx = inotest;
+         memset(fx, 0, mask * sizeof(unsigned int));
+       }
+      mask--;
+      for (i = 0; i < fc; i++)
+       {
+         if (fsz[i] == 0 || !S_ISREG(fm[i]))
+           continue;
+         hash = (fino[i] + fdev[i] * 31) & mask;
+          hh = 7;
+         while ((j = fx[hash]) != 0)
+           {
+             if (fino[j - 1] == fino[i] && fdev[j - 1] == fdev[i])
+               {
+                 fsz[i] = 0;   /* kill entry */
+                 break;
+               }
+             hash = (hash + hh++) & mask;
+           }
+         if (!j)
+           fx[hash] = i + 1;
+       }
+      if (fx != inotest)
+        solv_free(fx);
+      solv_free(fdev);
+    }
+  solv_free(fino);
+
+  /* sum up inode count and kbytes for each directory */
+  fn = solv_calloc(dc, sizeof(unsigned int));
+  fkb = solv_calloc(dc, sizeof(unsigned int));
+  for (i = 0; i < fc; i++)
+    {
+      if (di[i] >= dc)
+       continue;       /* corrupt entry */
+      fn[di[i]]++;
+      if (fsz[i] == 0 || !S_ISREG(fm[i]))
+       continue;
+      fkb[di[i]] += fsz[i];
+    }
+  solv_free(fsz);
+  solv_free(fm);
+  /* commit */
+  for (i = 0; i < dc; i++)
+    {
+      if (!fn[i])
+       continue;
+      if (dn[i][0] != '/')
+       {
+          Solvable *s = data->repo->pool->solvables + handle;
+          if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+           did = repodata_str2dir(data, "/usr/src", 1);
+         else
+           did = repodata_str2dir_rooted(data, dn[i], 1);
+       }
+      else
+        did = repodata_str2dir(data, dn[i], 1);
+      repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, did, fkb[i], fn[i]);
+    }
+  solv_free(fn);
+  solv_free(fkb);
+}
+
+static int
+is_filtered(const char *dir)
+{
+  if (!dir)
+    return 1;
+  /* the dirs always have a trailing / in rpm */
+  if (strstr(dir, "bin/"))
+    return 0;
+  if (!strncmp(dir, "/etc/", 5))
+    return 0;
+  if (!strcmp(dir, "/usr/lib/"))
+    return 2;
+  return 1;
+}
+
+static void
+addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
+{
+  char **bn;
+  char **dn;
+  uint32_t *di;
+  int bnc, dnc, dic;
+  int i;
+  Id did;
+  uint32_t lastdii = -1;
+  int lastfiltered = 0;
+
+  if (!data)
+    return;
+  bn = headstringarray(rpmhead, TAG_BASENAMES, &bnc);
+  if (!bn)
+    return;
+  dn = headstringarray(rpmhead, TAG_DIRNAMES, &dnc);
+  if (!dn)
+    {
+      solv_free(bn);
+      return;
+    }
+  di = headint32array(rpmhead, TAG_DIRINDEXES, &dic);
+  if (!di)
+    {
+      solv_free(bn);
+      solv_free(dn);
+      return;
+    }
+  if (bnc != dic)
+    {
+      pool_error(data->repo->pool, 0, "bad filelist");
+      return;
+    }
+
+  adddudata(data, handle, rpmhead, dn, di, bnc, dnc);
+
+  did = -1;
+  for (i = 0; i < bnc; i++)
+    {
+      char *b = bn[i];
+
+      if (did < 0 || di[i] != lastdii)
+       {
+         if (di[i] >= dnc)
+           continue;   /* corrupt entry */
+         did = 0;
+         lastdii = di[i];
+         if ((flags & RPM_ADD_FILTERED_FILELIST) != 0)
+           {
+             lastfiltered = is_filtered(dn[di[i]]);
+             if (lastfiltered == 1)
+               continue;
+           }
+         if (dn[lastdii][0] != '/')
+           did = repodata_str2dir_rooted(data, dn[lastdii], 1);
+         else
+           did = repodata_str2dir(data, dn[lastdii], 1);
+       }
+      if (!b)
+       continue;
+      if (*b == '/')   /* work around rpm bug */
+       b++;
+      if (lastfiltered && (lastfiltered != 2 || strcmp(b, "sendmail")))
+        continue;
+      repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b);
+    }
+  solv_free(bn);
+  solv_free(dn);
+  solv_free(di);
+}
+
+static void
+addchangelog(Repodata *data, Id handle, RpmHead *rpmhead)
+{
+  char **cn;
+  char **cx;
+  uint32_t *ct;
+  int i, cnc, cxc, ctc = 0;
+  Queue hq;
+
+  ct = headint32array(rpmhead, TAG_CHANGELOGTIME, &ctc);
+  cx = headstringarray(rpmhead, TAG_CHANGELOGTEXT, &cxc);
+  cn = headstringarray(rpmhead, TAG_CHANGELOGNAME, &cnc);
+  if (!ct || !cx || !cn || !ctc || ctc != cxc || ctc != cnc)
+    {
+      solv_free(ct);
+      solv_free(cx);
+      solv_free(cn);
+      return;
+    }
+  queue_init(&hq);
+  for (i = 0; i < ctc; i++)
+    {
+      Id h = repodata_new_handle(data);
+      if (ct[i])
+        repodata_set_num(data, h, SOLVABLE_CHANGELOG_TIME, ct[i]);
+      if (cn[i])
+        setutf8string(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]);
+      if (cx[i])
+        setutf8string(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]);
+      queue_push(&hq, h);
+    }
+  for (i = 0; i < hq.count; i++)
+    repodata_add_flexarray(data, handle, SOLVABLE_CHANGELOG, hq.elements[i]);
+  queue_free(&hq);
+  solv_free(ct);
+  solv_free(cx);
+  solv_free(cn);
+}
+
+static void
+set_description_author(Repodata *data, Id handle, char *str)
+{
+  char *aut, *p;
+  for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
+    if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
+      break;
+  if (aut)
+    {
+      /* oh my, found SUSE special author section */
+      int l = aut - str;
+      str = solv_strdup(str);
+      aut = str + l;
+      str[l] = 0;
+      while (l > 0 && str[l - 1] == '\n')
+       str[--l] = 0;
+      if (l)
+       setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
+      p = aut + 19;
+      aut = str;       /* copy over */
+      while (*p == ' ' || *p == '\n')
+       p++;
+      while (*p)
+       {
+         if (*p == '\n')
+           {
+             *aut++ = *p++;
+             while (*p == ' ')
+               p++;
+             continue;
+           }
+         *aut++ = *p++;
+       }
+      while (aut != str && aut[-1] == '\n')
+       aut--;
+      *aut = 0;
+      if (*str)
+       setutf8string(data, handle, SOLVABLE_AUTHORS, str);
+      free(str);
+    }
+  else if (*str)
+    setutf8string(data, handle, SOLVABLE_DESCRIPTION, str);
+}
+
+static int
+rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
+{
+  char *name;
+  char *evr;
+  char *sourcerpm;
+  Queue ignq;
+  Id ignqbuf[64];
+
+  name = headstring(rpmhead, TAG_NAME);
+  if (!name)
+    {
+      pool_error(pool, 0, "package has no name");
+      return 0;
+    }
+  if (!(flags & RPMDB_KEEP_GPG_PUBKEY) && !strcmp(name, "gpg-pubkey"))
+    return 0;
+  s->name = pool_str2id(pool, name, 1);
+  sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
+  if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead)))
+    s->arch = pool_str2id(pool, headstring(rpmhead, TAG_ARCH), 1);
+  else
+    {
+      if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
+        s->arch = ARCH_NOSRC;
+      else
+        s->arch = ARCH_SRC;
+    }
+  if (!s->arch)
+    s->arch = ARCH_NOARCH;
+  evr = headtoevr(rpmhead);
+  s->evr = pool_str2id(pool, evr, 1);
+  solv_free(evr);
+  s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
+
+  queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf));
+
+  s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0);
+  if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+  s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq);
+  s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0);
+  s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0);
+
+  s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0);
+  s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0);
+  s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0);
+  s->enhances  = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0);
+
+  repo_rewrite_suse_deps(s, 0);
+
+  if (data && ignq.count)
+    repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq);
+  queue_free(&ignq);
+
+  if (data)
+    {
+      Id handle;
+      char *str;
+      unsigned int u32;
+      unsigned long long u64;
+
+      handle = s - pool->solvables;
+      str = headstring(rpmhead, TAG_SUMMARY);
+      if (str)
+        setutf8string(data, handle, SOLVABLE_SUMMARY, str);
+      str = headstring(rpmhead, TAG_DESCRIPTION);
+      if (str)
+       set_description_author(data, handle, str);
+      str = headstring(rpmhead, TAG_GROUP);
+      if (str)
+        repodata_set_poolstr(data, handle, SOLVABLE_GROUP, str);
+      str = headstring(rpmhead, TAG_LICENSE);
+      if (str)
+        repodata_set_poolstr(data, handle, SOLVABLE_LICENSE, str);
+      str = headstring(rpmhead, TAG_URL);
+      if (str)
+       repodata_set_str(data, handle, SOLVABLE_URL, str);
+      str = headstring(rpmhead, TAG_DISTRIBUTION);
+      if (str)
+       repodata_set_poolstr(data, handle, SOLVABLE_DISTRIBUTION, str);
+      str = headstring(rpmhead, TAG_PACKAGER);
+      if (str)
+       repodata_set_poolstr(data, handle, SOLVABLE_PACKAGER, str);
+      if ((flags & RPM_ADD_WITH_PKGID) != 0)
+       {
+         unsigned char *chksum;
+         unsigned int chksumsize;
+         chksum = headbinary(rpmhead, TAG_SIGMD5, &chksumsize);
+         if (chksum && chksumsize == 16)
+           repodata_set_bin_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, chksum);
+       }
+      if ((flags & RPM_ADD_WITH_HDRID) != 0)
+       {
+         str = headstring(rpmhead, TAG_SHA1HEADER);
+         if (str && strlen(str) == 40)
+           repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA1, str);
+         else if (str && strlen(str) == 64)
+           repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA256, str);
+       }
+      u32 = headint32(rpmhead, TAG_BUILDTIME);
+      if (u32)
+        repodata_set_num(data, handle, SOLVABLE_BUILDTIME, u32);
+      u32 = headint32(rpmhead, TAG_INSTALLTIME);
+      if (u32)
+        repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, u32);
+      u64 = headint64(rpmhead, TAG_LONGSIZE);
+      if (u64)
+        repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u64);
+      else
+       {
+         u32 = headint32(rpmhead, TAG_SIZE);
+         if (u32)
+           repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u32);
+       }
+      if (sourcerpm)
+       repodata_set_sourcepkg(data, handle, sourcerpm);
+      if ((flags & RPM_ADD_TRIGGERS) != 0)
+       {
+         unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0);
+         Id id, lastid = 0;
+         for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id)
+           if (id != lastid)
+             repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id);
+       }
+      if ((flags & RPM_ADD_NO_FILELIST) == 0)
+       addfilelist(data, handle, rpmhead, flags);
+      if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
+       addchangelog(data, handle, rpmhead);
+    }
+  return 1;
+}
+
+static inline unsigned int
+getu32(const unsigned char *dp)
+{
+  return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
+}
+
+#ifdef ENABLE_RPMDB
+
+struct rpmdbentry {
+  Id rpmdbid;
+  Id nameoff;
+};
+
+#define ENTRIES_BLOCK 255
+#define NAMEDATA_BLOCK 1023
+
+# ifdef ENABLE_RPMDB_LIBRPM
+#  include "repo_rpmdb_librpm.h"
+# else
+#  include "repo_rpmdb_bdb.h"
+# endif
+
+#else
+
+/* dummy state just to store pool/rootdir and header data */
+struct rpmdbstate {
+  Pool *pool;
+  char *rootdir;
+
+  RpmHead *rpmhead;    /* header storage space */
+  int rpmheadsize;
+};
+
+#endif
+
+
+#ifndef ENABLE_RPMPKG_LIBRPM
+
+static int
+headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
+{
+  RpmHead *rpmhead;
+  unsigned int len = 16 * cnt + dsize + pad;
+  if (len + 1 > state->rpmheadsize)
+    {
+      state->rpmheadsize = len + 128;
+      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
+    }
+  rpmhead = state->rpmhead;
+  if (fread(rpmhead->data, len, 1, fp) != 1)
+    return pool_error(state->pool, 0, "%s: unexpected EOF", name);
+  if (chk1)
+    solv_chksum_add(chk1, rpmhead->data, len);
+  if (chk2)
+    solv_chksum_add(chk2, rpmhead->data, len);
+  rpmhead->data[len] = 0;
+  rpmhead->cnt = cnt;
+  rpmhead->dcnt = dsize;
+  rpmhead->dp = rpmhead->data + cnt * 16;
+  return 1;
+}
+
+#if defined(ENABLE_RPMDB_BYRPMHEADER)
+static void
+headfromblob(struct rpmdbstate *state, const unsigned char *blob, unsigned int cnt, unsigned int dsize)
+{
+  RpmHead *rpmhead;
+  unsigned int len = 16 * cnt + dsize;
+  if (len + 1 > state->rpmheadsize)
+    {
+      state->rpmheadsize = len + 128;
+      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
+    }
+  rpmhead = state->rpmhead;
+  memcpy(rpmhead->data, blob, len);
+  rpmhead->data[len] = 0;
+  rpmhead->cnt = cnt;
+  rpmhead->dcnt = dsize;
+  rpmhead->dp = rpmhead->data + cnt * 16;
+}
+#endif
+
+#else
+
+static int
+headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
+{
+  unsigned int len = 16 * cnt + dsize + pad;
+  char *buf = solv_malloc(8 + len);
+  Header h;
+  memcpy(buf, lead + 8, 8);
+  if (fread(buf + 8, len, 1, fp) != 1)
+    {
+      solv_free(buf);
+      return pool_error(state->pool, 0, "%s: unexpected EOF", name);
+    }
+  if (chk1)
+    solv_chksum_add(chk1, buf + 8, len);
+  if (chk2)
+    solv_chksum_add(chk2, buf + 8, len);
+  h = headerImport(buf, 8 + len - pad, HEADERIMPORT_FAST);
+  if (!h)
+    {
+      solv_free(buf);
+      return pool_error(state->pool, 0, "%s: headerImport error", name);
+    }
+  if (state->rpmhead)
+    headfree(state->rpmhead);
+  state->rpmhead = h;
+  return 1;
+}
+
+#endif
+
+static void
+freestate(struct rpmdbstate *state)
+{
+  /* close down */
+#ifdef ENABLE_RPMDB
+  if (state->pkgdbopened)
+    closepkgdb(state);
+  if (state->dbenvopened)
+    closedbenv(state);
+#endif
+  if (state->rootdir)
+    solv_free(state->rootdir);
+  headfree(state->rpmhead);
+}
+
+void *
+rpm_state_create(Pool *pool, const char *rootdir)
+{
+  struct rpmdbstate *state;
+  state = solv_calloc(1, sizeof(*state));
+  state->pool = pool;
+  if (rootdir)
+    state->rootdir = solv_strdup(rootdir);
+  return state;
+}
+
+void *
+rpm_state_free(void *state)
+{
+  if (state)
+    freestate(state);
+  return solv_free(state);
+}
+
+
+#ifdef ENABLE_RPMDB
+
+
+/******************************************************************/
+
+static Offset
+copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
+{
+  int cc;
+  Id *ida, *from;
+  Offset ido;
+
+  if (!fromoff)
+    return 0;
+  from = fromrepo->idarraydata + fromoff;
+  for (ida = from, cc = 0; *ida; ida++, cc++)
+    ;
+  if (cc == 0)
+    return 0;
+  ido = repo_reserve_ids(repo, 0, cc);
+  ida = repo->idarraydata + ido;
+  memcpy(ida, from, (cc + 1) * sizeof(Id));
+  repo->idarraysize += cc + 1;
+  return ido;
+}
+
+struct solvable_copy_cbdata {
+  Repodata *data;
+  Id handle;
+  Id subhandle;
+  Id *dircache;
+};
+
+static int
+solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv)
+{
+  struct solvable_copy_cbdata *cbdata = vcbdata;
+  Repodata *data = cbdata->data;
+  Id handle = cbdata->handle;
+
+  switch (key->type)
+    {
+    case REPOKEY_TYPE_ID:
+    case REPOKEY_TYPE_CONSTANTID:
+    case REPOKEY_TYPE_IDARRAY: /* used for triggers */
+      if (data->localpool || fromdata->localpool)
+       kv->id = repodata_translate_id(data, fromdata, kv->id, 1);
+      break;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
+      break;
+    case REPOKEY_TYPE_FIXARRAY:
+      cbdata->handle = repodata_new_handle(data);
+      repodata_add_fixarray(data, handle, key->name, cbdata->handle);
+      repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata);
+      cbdata->handle = handle;
+      return 0;
+    case REPOKEY_TYPE_FLEXARRAY:
+      cbdata->handle = repodata_new_handle(data);
+      repodata_add_flexarray(data, handle, key->name, cbdata->handle);
+      repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata);
+      cbdata->handle = handle;
+      return 0;
+    default:
+      break;
+    }
+  repodata_set_kv(data, handle, key->name, key->type, kv);
+  return 0;
+}
+
+static void
+solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip)
+{
+  int p, i;
+  Repo *repo = s->repo;
+  Pool *pool = repo->pool;
+  Repo *fromrepo = r->repo;
+  struct solvable_copy_cbdata cbdata;
+  Id *keyskip;
+
+  /* copy solvable data */
+  s->name = r->name;
+  s->evr = r->evr;
+  s->arch = r->arch;
+  s->vendor = r->vendor;
+  s->provides = copydeps(pool, repo, r->provides, fromrepo);
+  s->requires = copydeps(pool, repo, r->requires, fromrepo);
+  s->conflicts = copydeps(pool, repo, r->conflicts, fromrepo);
+  s->obsoletes = copydeps(pool, repo, r->obsoletes, fromrepo);
+  s->recommends = copydeps(pool, repo, r->recommends, fromrepo);
+  s->suggests = copydeps(pool, repo, r->suggests, fromrepo);
+  s->supplements = copydeps(pool, repo, r->supplements, fromrepo);
+  s->enhances  = copydeps(pool, repo, r->enhances, fromrepo);
+
+  /* copy all attributes */
+  if (!data || fromrepo->nrepodata < 2)
+    return;
+  cbdata.data = data;
+  cbdata.handle = s - pool->solvables;
+  cbdata.subhandle = 0;
+  cbdata.dircache = dircache;
+  p = r - fromrepo->pool->solvables;
+  if (fromrepo->nrepodata == 2)
+    {
+      Repodata *fromdata = repo_id2repodata(fromrepo, 1);
+      if (p >= fromdata->start && p < fromdata->end)
+        repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata);
+      return;
+    }
+  keyskip = repo_create_keyskip(repo, p, oldkeyskip);
+  FOR_REPODATAS(fromrepo, i, data)
+    {
+      if (p >= data->start && p < data->end)
+        repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+    }
+}
+
+/* used to sort entries by package name that got returned in some database order */
+static int
+rpmids_sort_cmp(const void *va, const void *vb, void *dp)
+{
+  struct rpmdbentry const *a = va, *b = vb;
+  char *namedata = dp;
+  int r;
+  r = strcmp(namedata + a->nameoff, namedata + b->nameoff);
+  if (r)
+    return r;
+  return a->rpmdbid - b->rpmdbid;
+}
+
+static int
+pkgids_sort_cmp(const void *va, const void *vb, void *dp)
+{
+  Repo *repo = dp;
+  Pool *pool = repo->pool;
+  Solvable *a = pool->solvables + *(Id *)va;
+  Solvable *b = pool->solvables + *(Id *)vb;
+  Id *rpmdbid;
+
+  if (a->name != b->name)
+    return strcmp(pool_id2str(pool, a->name), pool_id2str(pool, b->name));
+  rpmdbid = repo->rpmdbid;
+  return rpmdbid[(a - pool->solvables) - repo->start] - rpmdbid[(b - pool->solvables) - repo->start];
+}
+
+static void
+swap_solvables(Repo *repo, Repodata *data, Id pa, Id pb)
+{
+  Pool *pool = repo->pool;
+  Solvable tmp;
+
+  tmp = pool->solvables[pa];
+  pool->solvables[pa] = pool->solvables[pb];
+  pool->solvables[pb] = tmp;
+  if (repo->rpmdbid)
+    {
+      Id tmpid = repo->rpmdbid[pa - repo->start];
+      repo->rpmdbid[pa - repo->start] = repo->rpmdbid[pb - repo->start];
+      repo->rpmdbid[pb - repo->start] = tmpid;
+    }
+  /* only works if nothing is already internalized! */
+  if (data)
+    repodata_swap_attrs(data, pa, pb);
+}
+
+static void
+mkrpmdbcookie(struct stat *st, unsigned char *cookie, int flags)
+{
+  int f = 0;
+  memset(cookie, 0, 32);
+  cookie[3] = RPMDB_COOKIE_VERSION;
+  memcpy(cookie + 16, &st->st_ino, sizeof(st->st_ino));
+  memcpy(cookie + 24, &st->st_dev, sizeof(st->st_dev));
+  if ((flags & RPM_ADD_WITH_PKGID) != 0)
+    f |= 1;
+  if ((flags & RPM_ADD_WITH_HDRID) != 0)
+    f |= 2;
+  if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
+    f |= 4;
+  if ((flags & RPM_ADD_NO_FILELIST) == 0)
+    f |= 8;
+  if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0)
+    cookie[1] = 1;
+  cookie[0] = f;
+}
+
+/*
+ * read rpm db as repo
+ *
+ */
+
+int
+repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
+{
+  Pool *pool = repo->pool;
+  struct stat packagesstat;
+  unsigned char newcookie[32];
+  const unsigned char *oldcookie = 0;
+  Id oldcookietype = 0;
+  Repodata *data;
+  int count = 0, done = 0;
+  struct rpmdbstate state;
+  int i;
+  Solvable *s;
+  unsigned int now;
+
+  now = solv_timems(0);
+  memset(&state, 0, sizeof(state));
+  state.pool = pool;
+  if (flags & REPO_USE_ROOTDIR)
+    state.rootdir = solv_strdup(pool_get_rootdir(pool));
+
+  data = repo_add_repodata(repo, flags);
+
+  if (ref && !(ref->nsolvables && ref->rpmdbid && ref->pool == repo->pool))
+    {
+      if ((flags & RPMDB_EMPTY_REFREPO) != 0)
+       repo_empty(ref, 1);
+      ref = 0;
+    }
+
+  if (!opendbenv(&state))
+    {
+      solv_free(state.rootdir);
+      return -1;
+    }
+
+  /* XXX: should get ro lock of Packages database! */
+  if (stat_database(&state, "Packages", &packagesstat, 1))
+    {
+      freestate(&state);
+      return -1;
+    }
+  mkrpmdbcookie(&packagesstat, newcookie, flags);
+  repodata_set_bin_checksum(data, SOLVID_META, REPOSITORY_RPMDBCOOKIE, REPOKEY_TYPE_SHA256, newcookie);
+
+  if (ref)
+    oldcookie = repo_lookup_bin_checksum(ref, SOLVID_META, REPOSITORY_RPMDBCOOKIE, &oldcookietype);
+  if (!ref || !oldcookie || oldcookietype != REPOKEY_TYPE_SHA256 || memcmp(oldcookie, newcookie, 32) != 0)
+    {
+      int solvstart = 0, solvend = 0;
+      Id dbid;
+
+      if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
+       repo_empty(ref, 1);     /* get it out of the way */
+      if ((flags & RPMDB_REPORT_PROGRESS) != 0)
+       count = count_headers(&state);
+      if (!openpkgdb(&state))
+       {
+         freestate(&state);
+         return -1;
+       }
+      if (pkgdb_cursor_open(&state))
+       {
+         freestate(&state);
+         return -1;
+       }
+      i = 0;
+      s = 0;
+      while ((dbid = pkgdb_cursor_getrpm(&state)) != 0)
+       {
+         if (dbid == -1)
+           {
+             pkgdb_cursor_close(&state);
+             freestate(&state);
+             return -1;
+           }
+         if (!s)
+           {
+             s = pool_id2solvable(pool, repo_add_solvable(repo));
+             if (!solvstart)
+               solvstart = s - pool->solvables;
+             solvend = s - pool->solvables + 1;
+           }
+         if (!repo->rpmdbid)
+           repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
+         repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
+         if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
+           {
+             i++;
+             s = 0;
+           }
+         else
+           {
+             /* We can reuse this solvable, but make sure it's still
+                associated with this repo.  */
+             memset(s, 0, sizeof(*s));
+             s->repo = repo;
+           }
+         if ((flags & RPMDB_REPORT_PROGRESS) != 0)
+           {
+             if (done < count)
+               done++;
+             if (done < count && (done - 1) * 100 / count != done * 100 / count)
+               pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
+           }
+       }
+      pkgdb_cursor_close(&state);
+      if (s)
+       {
+         /* oops, could not reuse. free it instead */
+          s = solvable_free(s, 1);
+         solvend--;
+       }
+      /* now sort all solvables in the new solvstart..solvend block */
+      if (solvend - solvstart > 1)
+       {
+         Id *pkgids = solv_malloc2(solvend - solvstart, sizeof(Id));
+         for (i = solvstart; i < solvend; i++)
+           pkgids[i - solvstart] = i;
+         solv_sort(pkgids, solvend - solvstart, sizeof(Id), pkgids_sort_cmp, repo);
+         /* adapt order */
+         for (i = solvstart; i < solvend; i++)
+           {
+             int j = pkgids[i - solvstart];
+             while (j < i)
+               j = pkgids[i - solvstart] = pkgids[j - solvstart];
+             if (j != i)
+               swap_solvables(repo, data, i, j);
+           }
+         solv_free(pkgids);
+       }
+    }
+  else
+    {
+      Id *dircache;
+      Id *oldkeyskip = 0;
+      struct rpmdbentry *entries = 0, *rp;
+      int nentries = 0;
+      char *namedata = 0;
+      unsigned int refmask, h;
+      Id id, *refhash;
+      int res;
+
+      /* get ids of installed rpms */
+      entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata, flags & RPMDB_KEEP_GPG_PUBKEY);
+      if (!entries)
+       {
+         freestate(&state);
+         return -1;
+       }
+
+      /* sort by name */
+      if (nentries > 1)
+        solv_sort(entries, nentries, sizeof(*entries), rpmids_sort_cmp, namedata);
+
+      /* create hash from dbid to ref */
+      refmask = mkmask(ref->nsolvables);
+      refhash = solv_calloc(refmask + 1, sizeof(Id));
+      for (i = 0; i < ref->end - ref->start; i++)
+       {
+         if (!ref->rpmdbid[i])
+           continue;
+         h = ref->rpmdbid[i] & refmask;
+         while (refhash[h])
+           h = (h + 317) & refmask;
+         refhash[h] = i + 1;   /* make it non-zero */
+       }
+
+      /* count the misses, they will cost us time */
+      if ((flags & RPMDB_REPORT_PROGRESS) != 0)
+        {
+         for (i = 0, rp = entries; i < nentries; i++, rp++)
+           {
+             if (refhash)
+               {
+                 Id dbid = rp->rpmdbid;
+                 h = dbid & refmask;
+                 while ((id = refhash[h]))
+                   {
+                     if (ref->rpmdbid[id - 1] == dbid)
+                       break;
+                     h = (h + 317) & refmask;
+                   }
+                 if (id)
+                   continue;
+               }
+             count++;
+           }
+        }
+
+      if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
+        s = pool_id2solvable(pool, repo_add_solvable_block_before(repo, nentries, ref));
+      else
+        s = pool_id2solvable(pool, repo_add_solvable_block(repo, nentries));
+      if (!repo->rpmdbid)
+        repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
+
+      dircache = repodata_create_dirtranscache(data);
+      for (i = 0, rp = entries; i < nentries; i++, rp++, s++)
+       {
+         Id dbid = rp->rpmdbid;
+         repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
+         if (refhash)
+           {
+             h = dbid & refmask;
+             while ((id = refhash[h]))
+               {
+                 if (ref->rpmdbid[id - 1] == dbid)
+                   break;
+                 h = (h + 317) & refmask;
+               }
+             if (id)
+               {
+                 Solvable *r = ref->pool->solvables + ref->start + (id - 1);
+                 if (r->repo == ref)
+                   {
+                     solvable_copy(s, r, data, dircache, &oldkeyskip);
+                     continue;
+                   }
+               }
+           }
+         res = getrpm_dbid(&state, dbid);
+         if (res <= 0)
+           {
+             if (!res)
+               pool_error(pool, -1, "inconsistent rpm database, key %d not found. run 'rpm --rebuilddb' to fix.", dbid);
+             freestate(&state);
+             solv_free(entries);
+             solv_free(namedata);
+             solv_free(refhash);
+             dircache = repodata_free_dirtranscache(dircache);
+             return -1;
+           }
+         rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
+         if ((flags & RPMDB_REPORT_PROGRESS) != 0)
+           {
+             if (done < count)
+               done++;
+             if (done < count && (done - 1) * 100 / count != done * 100 / count)
+               pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
+           }
+       }
+      dircache = repodata_free_dirtranscache(dircache);
+
+      solv_free(oldkeyskip);
+      solv_free(entries);
+      solv_free(namedata);
+      solv_free(refhash);
+      if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
+       repo_empty(ref, 1);
+    }
+
+  freestate(&state);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  if ((flags & RPMDB_REPORT_PROGRESS) != 0)
+    pool_debug(pool, SOLV_ERROR, "%%%% 100\n");
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmdb took %d ms\n", solv_timems(now));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
+  return 0;
+}
+
+int
+repo_add_rpmdb_reffp(Repo *repo, FILE *fp, int flags)
+{
+  int res;
+  Repo *ref = 0;
+
+  if (!fp)
+    return repo_add_rpmdb(repo, 0, flags);
+  ref = repo_create(repo->pool, "add_rpmdb_reffp");
+  if (repo_add_solv(ref, fp, 0) != 0)
+    {
+      repo_free(ref, 1);
+      ref = 0;
+    }
+  if (ref && ref->start == ref->end)
+    {
+      repo_free(ref, 1);
+      ref = 0;
+    }
+  if (ref)
+    repo_disable_paging(ref);
+  res = repo_add_rpmdb(repo, ref, flags | RPMDB_EMPTY_REFREPO);
+  if (ref)
+    repo_free(ref, 1);
+  return res;
+}
+
+#endif /* ENABLE_RPMDB */
+
+Id
+repo_add_rpm(Repo *repo, const char *rpm, int flags)
+{
+  unsigned int sigdsize, sigcnt, sigpad, l;
+  Pool *pool = repo->pool;
+  Solvable *s;
+  struct rpmdbstate state;
+  char *payloadformat;
+  FILE *fp;
+  unsigned char lead[4096];
+  int headerstart, headerend;
+  struct stat stb;
+  Repodata *data;
+  unsigned char pkgid[16];
+  unsigned char leadsigid[16];
+  unsigned char hdrid[32];
+  int pkgidtype, leadsigidtype, hdridtype;
+  Id chksumtype = 0;
+  Chksum *chksumh = 0;
+  Chksum *leadsigchksumh = 0;
+
+  data = repo_add_repodata(repo, flags);
+
+  if ((flags & RPM_ADD_WITH_SHA256SUM) != 0)
+    chksumtype = REPOKEY_TYPE_SHA256;
+  else if ((flags & RPM_ADD_WITH_SHA1SUM) != 0)
+    chksumtype = REPOKEY_TYPE_SHA1;
+
+  /* open rpm */
+  if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, rpm) : rpm, "r")) == 0)
+    {
+      pool_error(pool, -1, "%s: %s", rpm, strerror(errno));
+      return 0;
+    }
+  if (fstat(fileno(fp), &stb))
+    {
+      pool_error(pool, -1, "fstat: %s", strerror(errno));
+      fclose(fp);
+      return 0;
+    }
+
+  /* setup state */
+  memset(&state, 0, sizeof(state));
+  state.pool = pool;
+
+  /* process lead */
+  if (chksumtype)
+    chksumh = solv_chksum_create(chksumtype);
+  if ((flags & RPM_ADD_WITH_LEADSIGID) != 0)
+    leadsigchksumh = solv_chksum_create(REPOKEY_TYPE_MD5);
+  if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
+    {
+      pool_error(pool, -1, "%s: not a rpm", rpm);
+      fclose(fp);
+      return 0;
+    }
+  if (chksumh)
+    solv_chksum_add(chksumh, lead, 96 + 16);
+  if (leadsigchksumh)
+    solv_chksum_add(leadsigchksumh, lead, 96 + 16);
+
+  /* process signature header */
+  if (lead[78] != 0 || lead[79] != 5)
+    {
+      pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
+      fclose(fp);
+      return 0;
+    }
+  if (getu32(lead + 96) != 0x8eade801)
+    {
+      pool_error(pool, -1, "%s: bad signature header", rpm);
+      fclose(fp);
+      return 0;
+    }
+  sigcnt = getu32(lead + 96 + 8);
+  sigdsize = getu32(lead + 96 + 12);
+  if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
+    {
+      pool_error(pool, -1, "%s: bad signature header", rpm);
+      fclose(fp);
+      return 0;
+    }
+  sigpad = sigdsize & 7 ? 8 - (sigdsize & 7) : 0;
+  headerstart = 96 + 16 + sigcnt * 16 + sigdsize + sigpad;
+  pkgidtype = leadsigidtype = hdridtype = 0;
+  if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0)
+    {
+      if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh))
+       {
+         fclose(fp);
+         return 0;
+       }
+      if ((flags & RPM_ADD_WITH_PKGID) != 0)
+       {
+         unsigned char *chksum;
+         unsigned int chksumsize;
+         chksum = headbinary(state.rpmhead, SIGTAG_MD5, &chksumsize);
+         if (chksum && chksumsize == 16)
+           {
+             pkgidtype = REPOKEY_TYPE_MD5;
+             memcpy(pkgid, chksum, 16);
+           }
+       }
+      if ((flags & RPM_ADD_WITH_HDRID) != 0)
+       {
+         const char *str = headstring(state.rpmhead, TAG_SHA1HEADER);
+         if (str && strlen(str) == 40)
+           {
+             if (solv_hex2bin(&str, hdrid, 20) == 20)
+               hdridtype = REPOKEY_TYPE_SHA1;
+           }
+         else if (str && strlen(str) == 64)
+           {
+             if (solv_hex2bin(&str, hdrid, 32) == 32)
+               hdridtype = REPOKEY_TYPE_SHA256;
+           }
+       }
+    }
+  else
+    {
+      /* just skip the signature header */
+      unsigned int len = sigcnt * 16 + sigdsize + sigpad;
+      while (len)
+       {
+         l = len > 4096 ? 4096 : len;
+         if (fread(lead, l, 1, fp) != 1)
+           {
+             pool_error(pool, -1, "%s: unexpected EOF", rpm);
+             fclose(fp);
+             return 0;
+           }
+         if (chksumh)
+           solv_chksum_add(chksumh, lead, l);
+         if (leadsigchksumh)
+           solv_chksum_add(leadsigchksumh, lead, l);
+         len -= l;
+       }
+    }
+  if (leadsigchksumh)
+    {
+      leadsigchksumh = solv_chksum_free(leadsigchksumh, leadsigid);
+      leadsigidtype = REPOKEY_TYPE_MD5;
+    }
+
+  /* process main header */
+  if (fread(lead, 16, 1, fp) != 1)
+    {
+      pool_error(pool, -1, "%s: unexpected EOF", rpm);
+      fclose(fp);
+      return 0;
+    }
+  if (chksumh)
+    solv_chksum_add(chksumh, lead, 16);
+  if (getu32(lead) != 0x8eade801)
+    {
+      pool_error(pool, -1, "%s: bad header", rpm);
+      fclose(fp);
+      return 0;
+    }
+  sigcnt = getu32(lead + 8);
+  sigdsize = getu32(lead + 12);
+  if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
+    {
+      pool_error(pool, -1, "%s: bad header", rpm);
+      fclose(fp);
+      return 0;
+    }
+  headerend = headerstart + 16 + sigdsize + sigcnt * 16;
+
+  if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0))
+    {
+      fclose(fp);
+      return 0;
+    }
+  if (headexists(state.rpmhead, TAG_PATCHESNAME))
+    {
+      /* this is a patch rpm, ignore */
+      pool_error(pool, -1, "%s: is patch rpm", rpm);
+      fclose(fp);
+      solv_chksum_free(chksumh, 0);
+      headfree(state.rpmhead);
+      return 0;
+    }
+  payloadformat = headstring(state.rpmhead, TAG_PAYLOADFORMAT);
+  if (payloadformat && !strcmp(payloadformat, "drpm"))
+    {
+      /* this is a delta rpm */
+      pool_error(pool, -1, "%s: is delta rpm", rpm);
+      fclose(fp);
+      solv_chksum_free(chksumh, 0);
+      headfree(state.rpmhead);
+      return 0;
+    }
+  if (chksumh)
+    while ((l = fread(lead, 1, sizeof(lead), fp)) > 0)
+      solv_chksum_add(chksumh, lead, l);
+  fclose(fp);
+  s = pool_id2solvable(pool, repo_add_solvable(repo));
+  if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
+    {
+      s = solvable_free(s, 1);
+      solv_chksum_free(chksumh, 0);
+      headfree(state.rpmhead);
+      return 0;
+    }
+  if (!(flags & REPO_NO_LOCATION))
+    repodata_set_location(data, s - pool->solvables, 0, 0, rpm);
+  if (S_ISREG(stb.st_mode))
+    repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
+  repodata_set_num(data, s - pool->solvables, SOLVABLE_HEADEREND, headerend);
+  if (pkgidtype)
+    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, pkgidtype, pkgid);
+  if (hdridtype)
+    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_HDRID, hdridtype, hdrid);
+  if (leadsigidtype)
+    repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_LEADSIGID, leadsigidtype, leadsigid);
+  if (chksumh)
+    {
+      repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0));
+      chksumh = solv_chksum_free(chksumh, 0);
+    }
+  headfree(state.rpmhead);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return s - pool->solvables;
+}
+
+Id
+repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  RpmHead *rpmhead = rpmhandle;
+  Solvable *s;
+  char *payloadformat;
+
+  data = repo_add_repodata(repo, flags);
+  if (headexists(rpmhead, TAG_PATCHESNAME))
+    {
+      pool_error(pool, -1, "is a patch rpm");
+      return 0;
+    }
+  payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT);
+  if (payloadformat && !strcmp(payloadformat, "drpm"))
+    {
+      /* this is a delta rpm */
+      pool_error(pool, -1, "is a delta rpm");
+      return 0;
+    }
+  s = pool_id2solvable(pool, repo_add_solvable(repo));
+  if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags))
+    {
+      s = solvable_free(s, 1);
+      return 0;
+    }
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return s - pool->solvables;
+}
+
+static inline void
+linkhash(const char *lt, char *hash)
+{
+  unsigned int r = 0;
+  const unsigned char *str = (const unsigned char *)lt;
+  int l, c;
+
+  l = strlen(lt);
+  while ((c = *str++) != 0)
+    r += (r << 3) + c;
+  sprintf(hash, "%08x%08x%08x%08x", r, l, 0, 0);
+}
+
+void
+rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata)
+{
+  RpmHead *rpmhead = rpmhandle;
+  char **bn;
+  char **dn;
+  char **md = 0;
+  char **lt = 0;
+  uint32_t *di, diidx;
+  uint32_t *co = 0;
+  uint32_t *ff = 0;
+  uint16_t *fm;
+  unsigned int lastdir;
+  int lastdirl;
+  int cnt, dcnt, cnt2;
+  int i, l1, l;
+  char *space = 0;
+  int spacen = 0;
+  char md5[33];
+  struct filelistinfo info;
+
+  dn = headstringarray(rpmhead, TAG_DIRNAMES, &dcnt);
+  if (!dn)
+    return;
+  if ((flags & RPM_ITERATE_FILELIST_ONLYDIRS) != 0)
+    {
+      for (i = 0; i < dcnt; i++)
+       (*cb)(cbdata, dn[i], 0);
+      solv_free(dn);
+      return;
+    }
+  bn = headstringarray(rpmhead, TAG_BASENAMES, &cnt);
+  if (!bn)
+    {
+      solv_free(dn);
+      return;
+    }
+  di = headint32array(rpmhead, TAG_DIRINDEXES, &cnt2);
+  if (!di || cnt != cnt2)
+    {
+      solv_free(di);
+      solv_free(bn);
+      solv_free(dn);
+      return;
+    }
+  fm = headint16array(rpmhead, TAG_FILEMODES, &cnt2);
+  if (!fm || cnt != cnt2)
+    {
+      solv_free(fm);
+      solv_free(di);
+      solv_free(bn);
+      solv_free(dn);
+      return;
+    }
+  if ((flags & RPM_ITERATE_FILELIST_WITHMD5) != 0)
+    {
+      md = headstringarray(rpmhead, TAG_FILEMD5S, &cnt2);
+      if (!md || cnt != cnt2)
+       {
+         solv_free(md);
+         solv_free(fm);
+         solv_free(di);
+         solv_free(bn);
+         solv_free(dn);
+         return;
+       }
+    }
+  if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0)
+    {
+      co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2);
+      if (co && cnt != cnt2)
+       {
+         solv_free(co);
+         solv_free(md);
+         solv_free(fm);
+         solv_free(di);
+         solv_free(bn);
+         solv_free(dn);
+         return;
+       }
+    }
+  if ((flags & RPM_ITERATE_FILELIST_NOGHOSTS) != 0)
+    {
+      ff = headint32array(rpmhead, TAG_FILEFLAGS, &cnt2);
+      if (!ff || cnt != cnt2)
+       {
+         solv_free(ff);
+         solv_free(co);
+         solv_free(md);
+         solv_free(fm);
+         solv_free(di);
+         solv_free(bn);
+         solv_free(dn);
+         return;
+       }
+    }
+  lastdir = dcnt;
+  lastdirl = 0;
+  memset(&info, 0, sizeof(info));
+  for (i = 0; i < cnt; i++)
+    {
+      if (ff && (ff[i] & FILEFLAG_GHOST) != 0)
+       continue;
+      diidx = di[i];
+      if (diidx >= dcnt)
+       continue;
+      l1 = lastdir == diidx ? lastdirl : strlen(dn[diidx]);
+      l = l1 + strlen(bn[i]) + 1;
+      if (l > spacen)
+       {
+         spacen = l + 16;
+         space = solv_realloc(space, spacen);
+       }
+      if (lastdir != diidx)
+       {
+          strcpy(space, dn[diidx]);
+         lastdir = diidx;
+         lastdirl = l1;
+       }
+      strcpy(space + l1, bn[i]);
+      info.diridx = diidx;
+      info.dirlen = l1;
+      if (fm)
+        info.mode = fm[i];
+      if (md)
+       {
+         info.digest = md[i];
+         if (fm && S_ISLNK(fm[i]))
+           {
+             info.digest = 0;
+             if (!lt)
+               {
+                 lt = headstringarray(rpmhead, TAG_FILELINKTOS, &cnt2);
+                 if (cnt != cnt2)
+                   lt = solv_free(lt);
+               }
+             if (lt)
+               {
+                 linkhash(lt[i], md5);
+                 info.digest = md5;
+               }
+           }
+         if (!info.digest)
+           {
+             sprintf(md5, "%08x%08x%08x%08x", (fm[i] >> 12) & 65535, 0, 0, 0);
+             info.digest = md5;
+           }
+       }
+      info.color = co ? co[i] : 0;
+      (*cb)(cbdata, space, &info);
+    }
+  solv_free(space);
+  solv_free(lt);
+  solv_free(md);
+  solv_free(fm);
+  solv_free(di);
+  solv_free(bn);
+  solv_free(dn);
+  solv_free(co);
+  solv_free(ff);
+}
+
+char *
+rpm_query(void *rpmhandle, Id what)
+{
+  const char *name, *arch, *sourcerpm;
+  char *evr, *r;
+  int l;
+
+  RpmHead *rpmhead = rpmhandle;
+  r = 0;
+  switch (what)
+    {
+    case 0:    /* return canonical name of rpm */
+      name = headstring(rpmhead, TAG_NAME);
+      if (!name)
+       name = "";
+      sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
+      if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead)))
+       arch = headstring(rpmhead, TAG_ARCH);
+      else
+       {
+         if (headexists(rpmhead, TAG_NOSOURCE) || headexists(rpmhead, TAG_NOPATCH))
+           arch = "nosrc";
+         else
+           arch = "src";
+       }
+      if (!arch)
+       arch = "noarch";
+      evr = headtoevr(rpmhead);
+      l = strlen(name) + 1 + strlen(evr ? evr : "") + 1 + strlen(arch) + 1;
+      r = solv_malloc(l);
+      sprintf(r, "%s-%s.%s", name, evr ? evr : "", arch);
+      solv_free(evr);
+      break;
+    case SOLVABLE_NAME:
+      name = headstring(rpmhead, TAG_NAME);
+      r = solv_strdup(name);
+      break;
+    case SOLVABLE_SUMMARY:
+      name = headstring(rpmhead, TAG_SUMMARY);
+      r = solv_strdup(name);
+      break;
+    case SOLVABLE_DESCRIPTION:
+      name = headstring(rpmhead, TAG_DESCRIPTION);
+      r = solv_strdup(name);
+      break;
+    case SOLVABLE_EVR:
+      r = headtoevr(rpmhead);
+      break;
+    }
+  return r;
+}
+
+unsigned long long
+rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound)
+{
+  RpmHead *rpmhead = rpmhandle;
+  unsigned int u32;
+
+  switch (what)
+    {
+    case SOLVABLE_INSTALLTIME:
+      u32 = headint32(rpmhead, TAG_INSTALLTIME);
+      return u32 ? u32 : notfound;
+    }
+  return notfound;
+}
+
+#ifdef ENABLE_RPMDB
+
+int
+rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq)
+{
+  struct rpmdbentry *entries;
+  int nentries, i;
+
+  entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0, 0);
+  if (rpmdbidq)
+    {
+      queue_empty(rpmdbidq);
+      for (i = 0; i < nentries; i++)
+        queue_push(rpmdbidq, entries[i].rpmdbid);
+    }
+  solv_free(entries);
+  return nentries;
+}
+
+void *
+rpm_byrpmdbid(void *rpmstate, Id rpmdbid)
+{
+  struct rpmdbstate *state = rpmstate;
+  int r;
+
+  r = getrpm_dbid(state, rpmdbid);
+  if (!r)
+    pool_error(state->pool, 0, "header #%d not in database", rpmdbid);
+  return r <= 0 ? 0 : state->rpmhead;
+}
+
+#endif /* ENABLE_RPMDB */
+
+void *
+rpm_byfp(void *rpmstate, FILE *fp, const char *name)
+{
+  struct rpmdbstate *state = rpmstate;
+  unsigned int sigdsize, sigcnt, l;
+  unsigned char lead[4096];
+
+  if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
+    {
+      pool_error(state->pool, 0, "%s: not a rpm", name);
+      return 0;
+    }
+  if (lead[78] != 0 || lead[79] != 5)
+    {
+      pool_error(state->pool, 0, "%s: not a V5 header", name);
+      return 0;
+    }
+
+  /* skip signature header */
+  if (getu32(lead + 96) != 0x8eade801)
+    {
+      pool_error(state->pool, 0, "%s: bad signature header", name);
+      return 0;
+    }
+  sigcnt = getu32(lead + 96 + 8);
+  sigdsize = getu32(lead + 96 + 12);
+  if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
+    {
+      pool_error(state->pool, 0, "%s: bad signature header", name);
+      return 0;
+    }
+  sigdsize += sigcnt * 16;
+  sigdsize = (sigdsize + 7) & ~7;
+  while (sigdsize)
+    {
+      l = sigdsize > 4096 ? 4096 : sigdsize;
+      if (fread(lead, l, 1, fp) != 1)
+       {
+         pool_error(state->pool, 0, "%s: unexpected EOF", name);
+         return 0;
+       }
+      sigdsize -= l;
+    }
+
+  if (fread(lead, 16, 1, fp) != 1)
+    {
+      pool_error(state->pool, 0, "%s: unexpected EOF", name);
+      return 0;
+    }
+  if (getu32(lead) != 0x8eade801)
+    {
+      pool_error(state->pool, 0, "%s: bad header", name);
+      return 0;
+    }
+  sigcnt = getu32(lead + 8);
+  sigdsize = getu32(lead + 12);
+  if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
+    {
+      pool_error(state->pool, 0, "%s: bad header", name);
+      return 0;
+    }
+  if (!headfromfp(state, name, fp, lead, sigcnt, sigdsize, 0, 0, 0))
+    return 0;
+  return state->rpmhead;
+}
+
+#if defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM)
+
+void *
+rpm_byrpmh(void *rpmstate, Header h)
+{
+  struct rpmdbstate *state = rpmstate;
+#ifndef ENABLE_RPMPKG_LIBRPM
+  const unsigned char *uh;
+  unsigned int dsize, cnt;
+
+  if (!h)
+    return 0;
+#ifndef RPM5
+  uh = headerUnload(h);
+#else
+  uh = headerUnload(h, NULL);
+#endif
+  if (!uh)
+    return 0;
+  cnt = getu32(uh);
+  dsize = getu32(uh + 4);
+  if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
+    {
+      free((void *)uh);
+      return 0;
+    }
+  headfromblob(state, uh + 8, cnt, dsize);
+  free((void *)uh);
+#else
+  if (!h)
+    return 0;
+  if (state->rpmhead)
+    headfree(state->rpmhead);
+  state->rpmhead = headerLink(h);
+#endif
+  return state->rpmhead;
+}
+
+#endif /* defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) */
+
diff --git a/libsolv-0.7.2/ext/repo_rpmdb.h b/libsolv-0.7.2/ext/repo_rpmdb.h
new file mode 100644 (file)
index 0000000..554d48a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007-2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include "queue.h"
+#include "repo.h"
+
+struct headerToken_s;
+
+extern int repo_add_rpmdb(Repo *repo, Repo *ref, int flags);
+extern int repo_add_rpmdb_reffp(Repo *repo, FILE *reffp, int flags);
+extern Id repo_add_rpm(Repo *repo, const char *rpm, int flags);
+
+#define RPMDB_REPORT_PROGRESS  (1 << 8)
+#define RPM_ADD_WITH_PKGID     (1 << 9)
+#define RPM_ADD_NO_FILELIST    (1 << 10)
+#define RPM_ADD_NO_RPMLIBREQS  (1 << 11)
+#define RPM_ADD_WITH_SHA1SUM   (1 << 12)
+#define RPM_ADD_WITH_SHA256SUM (1 << 13)
+#define RPM_ADD_TRIGGERS       (1 << 14)
+#define RPM_ADD_WITH_HDRID     (1 << 15)
+#define RPM_ADD_WITH_LEADSIGID (1 << 16)
+#define RPM_ADD_WITH_CHANGELOG (1 << 17)
+#define RPM_ADD_FILTERED_FILELIST (1 << 18)
+#define RPMDB_KEEP_GPG_PUBKEY   (1 << 19)
+
+#define RPMDB_EMPTY_REFREPO    (1 << 30)       /* internal */
+
+#define RPM_ITERATE_FILELIST_ONLYDIRS  (1 << 0)
+#define RPM_ITERATE_FILELIST_WITHMD5   (1 << 1)
+#define RPM_ITERATE_FILELIST_WITHCOL   (1 << 2)
+#define RPM_ITERATE_FILELIST_NOGHOSTS  (1 << 3)
+
+/* create and free internal state, rootdir is the rootdir of the rpm database */
+extern void *rpm_state_create(Pool *pool, const char *rootdir);
+extern void *rpm_state_free(void *rpmstate);
+
+/* return all matching rpmdbids */
+extern int  rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq);
+
+/* return handles to a rpm header */
+extern void *rpm_byrpmdbid(void *rpmstate, Id rpmdbid);
+extern void *rpm_byfp(void *rpmstate, FILE *fp, const char *name);
+extern void *rpm_byrpmh(void *rpmstate, struct headerToken_s *h);
+
+/* operations on a rpm header handle */
+
+struct filelistinfo {
+  unsigned int dirlen;
+  unsigned int diridx;
+  const char *digest;
+  unsigned int mode;
+  unsigned int color;
+};
+
+extern char *rpm_query(void *rpmhandle, Id what);
+extern unsigned long long rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound);
+extern void rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata);
+extern Id   repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags);
diff --git a/libsolv-0.7.2/ext/repo_rpmdb_bdb.h b/libsolv-0.7.2/ext/repo_rpmdb_bdb.h
new file mode 100644 (file)
index 0000000..ed82a69
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2018 SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_rpmdb_bdb.h
+ *
+ * Use BerkeleyDB to access the rpm database
+ *
+ */
+
+
+#if !defined(DB_CREATE) && !defined(ENABLE_RPMDB_LIBRPM)
+# if defined(SUSE) || defined(HAVE_RPM_DB_H)
+#  include <rpm/db.h>
+# else
+#  include <db.h>
+# endif
+#endif
+
+#ifdef RPM5
+# define RPM_INDEX_SIZE 4      /* just the rpmdbid */
+#else
+# define RPM_INDEX_SIZE 8      /* rpmdbid + array index */
+#endif
+
+
+/******************************************************************/
+/*  Rpm Database stuff
+ */
+
+struct rpmdbstate {
+  Pool *pool;
+  char *rootdir;
+
+  RpmHead *rpmhead;    /* header storage space */
+  int rpmheadsize;
+
+  int dbenvopened;     /* database environment opened */
+  int pkgdbopened;     /* package database openend */
+  int is_ostree;       /* read-only db that lives in /usr/share/rpm */
+
+  DB_ENV *dbenv;       /* database environment */
+  DB *db;              /* packages database */
+  int byteswapped;     /* endianess of packages database */
+  DBC *dbc;            /* iterator over packages database */
+};
+
+
+static int
+stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+{
+  char *dbpath;
+  dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
+  if (stat(dbpath, statbuf))
+    {
+      if (seterror)
+        pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
+      free(dbpath);
+      return -1;
+    }
+  free(dbpath);
+  return 0;
+}
+
+
+static inline Id
+db2rpmdbid(unsigned char *db, int byteswapped)
+{
+#ifdef RPM5
+  return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
+#else
+# if defined(WORDS_BIGENDIAN)
+  if (!byteswapped)
+# else
+  if (byteswapped)
+# endif
+    return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
+  else
+    return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0];
+#endif
+}
+
+static inline void
+rpmdbid2db(unsigned char *db, Id id, int byteswapped)
+{
+#ifdef RPM5
+  db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
+#else
+# if defined(WORDS_BIGENDIAN)
+  if (!byteswapped)
+# else
+  if (byteswapped)
+# endif
+    db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
+  else
+    db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id;
+#endif
+}
+
+#if defined(FEDORA) || defined(MAGEIA)
+static int
+serialize_dbenv_ops(struct rpmdbstate *state)
+{
+  char *lpath;
+  mode_t oldmask;
+  int fd;
+  struct flock fl;
+
+  lpath = solv_dupjoin(state->rootdir, "/var/lib/rpm/.dbenv.lock", 0);
+  oldmask = umask(022);
+  fd = open(lpath, (O_RDWR|O_CREAT), 0644);
+  free(lpath);
+  umask(oldmask);
+  if (fd < 0)
+    return -1;
+  memset(&fl, 0, sizeof(fl));
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  for (;;)
+    {
+      if (fcntl(fd, F_SETLKW, &fl) != -1)
+       return fd;
+      if (errno != EINTR)
+       break;
+    }
+  close(fd);
+  return -1;
+}
+
+#endif
+
+/* should look in /usr/lib/rpm/macros instead, but we want speed... */
+static int
+opendbenv(struct rpmdbstate *state)
+{
+  const char *rootdir = state->rootdir;
+  char *dbpath;
+  DB_ENV *dbenv = 0;
+  int r;
+
+  if (db_env_create(&dbenv, 0))
+    return pool_error(state->pool, 0, "db_env_create: %s", strerror(errno));
+#if (defined(FEDORA) || defined(MAGEIA)) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5))
+  dbenv->set_thread_count(dbenv, 8);
+#endif
+  dbpath = solv_dupjoin(rootdir, "/var/lib/rpm", 0);
+  if (access(dbpath, W_OK) == -1)
+    {
+      free(dbpath);
+      dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0);
+      if (access(dbpath, R_OK) == 0)
+       state->is_ostree = 1;
+      free(dbpath);
+      dbpath = solv_dupjoin(rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm", 0);
+      r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
+    }
+  else
+    {
+#if defined(FEDORA) || defined(MAGEIA)
+      int serialize_fd = serialize_dbenv_ops(state);
+      int eflags = DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL;
+      r = dbenv->open(dbenv, dbpath, eflags, 0644);
+      /* see rpm commit 2822ccbcdf3e898b960fafb23c4d571e26cef0a4 */
+      if (r == DB_VERSION_MISMATCH)
+       {
+         eflags |= DB_PRIVATE;
+         dbenv->errx(dbenv, "warning: DB_VERSION_MISMATCH, retrying with DB_PRIVATE");
+         r = dbenv->open(dbenv, dbpath, eflags, 0644);
+       }
+      if (serialize_fd >= 0)
+       close(serialize_fd);
+#else
+      r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
+#endif
+    }
+  if (r)
+    {
+      pool_error(state->pool, 0, "dbenv->open: %s", strerror(errno));
+      free(dbpath);
+      dbenv->close(dbenv, 0);
+      return 0;
+    }
+  free(dbpath);
+  state->dbenv = dbenv;
+  state->dbenvopened = 1;
+  return 1;
+}
+
+static void
+closedbenv(struct rpmdbstate *state)
+{
+#if defined(FEDORA) || defined(MAGEIA)
+  uint32_t eflags = 0;
+#endif
+
+  if (!state->dbenv)
+    return;
+#if defined(FEDORA) || defined(MAGEIA)
+  (void)state->dbenv->get_open_flags(state->dbenv, &eflags);
+  if (!(eflags & DB_PRIVATE))
+    {
+      int serialize_fd = serialize_dbenv_ops(state);
+      state->dbenv->close(state->dbenv, 0);
+      if (serialize_fd >= 0)
+       close(serialize_fd);
+    }
+  else
+    state->dbenv->close(state->dbenv, 0);
+#else
+  state->dbenv->close(state->dbenv, 0);
+#endif
+  state->dbenv = 0;
+  state->dbenvopened = 0;
+}
+
+static int
+openpkgdb(struct rpmdbstate *state)
+{
+  if (state->pkgdbopened)
+    return state->pkgdbopened > 0 ? 1 : 0;
+  state->pkgdbopened = -1;
+  if (state->dbenvopened != 1 && !opendbenv(state))
+    return 0;
+  if (db_create(&state->db, state->dbenv, 0))
+    {
+      pool_error(state->pool, 0, "db_create: %s", strerror(errno));
+      state->db = 0;
+      closedbenv(state);
+      return 0;
+    }
+  if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664))
+    {
+      pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno));
+      state->db->close(state->db, 0);
+      state->db = 0;
+      closedbenv(state);
+      return 0;
+    }
+  if (state->db->get_byteswapped(state->db, &state->byteswapped))
+    {
+      pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
+      state->db->close(state->db, 0);
+      state->db = 0;
+      closedbenv(state);
+      return 0;
+    }
+  state->pkgdbopened = 1;
+  return 1;
+}
+
+static void
+closepkgdb(struct rpmdbstate *state)
+{
+  if (!state->db)
+    return;
+  state->db->close(state->db, 0);
+  state->db = 0;
+  state->pkgdbopened = 0;
+}
+
+/* get the rpmdbids of all installed packages from the Name index database.
+ * This is much faster then querying the big Packages database */
+static struct rpmdbentry *
+getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
+{
+  DB_ENV *dbenv = 0;
+  DB *db = 0;
+  DBC *dbc = 0;
+  int byteswapped;
+  DBT dbkey;
+  DBT dbdata;
+  unsigned char *dp;
+  int dl;
+  Id nameoff;
+
+  char *namedata = 0;
+  int namedatal = 0;
+  struct rpmdbentry *entries = 0;
+  int nentries = 0;
+
+  *nentriesp = 0;
+  if (namedatap)
+    *namedatap = 0;
+
+  if (state->dbenvopened != 1 && !opendbenv(state))
+    return 0;
+  dbenv = state->dbenv;
+  if (db_create(&db, dbenv, 0))
+    {
+      pool_error(state->pool, 0, "db_create: %s", strerror(errno));
+      return 0;
+    }
+  if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664))
+    {
+      pool_error(state->pool, 0, "db->open %s: %s", index, strerror(errno));
+      db->close(db, 0);
+      return 0;
+    }
+  if (db->get_byteswapped(db, &byteswapped))
+    {
+      pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
+      db->close(db, 0);
+      return 0;
+    }
+  if (db->cursor(db, NULL, &dbc, 0))
+    {
+      pool_error(state->pool, 0, "db->cursor: %s", strerror(errno));
+      db->close(db, 0);
+      return 0;
+    }
+  memset(&dbkey, 0, sizeof(dbkey));
+  memset(&dbdata, 0, sizeof(dbdata));
+  if (match)
+    {
+      dbkey.data = (void *)match;
+      dbkey.size = strlen(match);
+    }
+  while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0)
+    {
+      if (!match && !keep_gpg_pubkey && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10))
+       continue;
+      dl = dbdata.size;
+      dp = dbdata.data;
+      nameoff = namedatal;
+      if (namedatap)
+       {
+         namedata = solv_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK);
+         memcpy(namedata + namedatal, dbkey.data, dbkey.size);
+         namedata[namedatal + dbkey.size] = 0;
+         namedatal += dbkey.size + 1;
+       }
+      while(dl >= RPM_INDEX_SIZE)
+       {
+         entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
+         entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped);
+         entries[nentries].nameoff = nameoff;
+         nentries++;
+         dp += RPM_INDEX_SIZE;
+         dl -= RPM_INDEX_SIZE;
+       }
+      if (match)
+       break;
+    }
+  dbc->c_close(dbc);
+  db->close(db, 0);
+  /* make sure that enteries is != 0 if there was no error */
+  if (!entries)
+    entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
+  *nentriesp = nentries;
+  if (namedatap)
+    *namedatap = namedata;
+  return entries;
+}
+
+/* common code, return dbid on success, -1 on error */
+static int
+getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid)
+{
+  unsigned int dsize, cnt, l;
+  RpmHead *rpmhead;
+
+  if (dbdata->size < 8)
+    return pool_error(state->pool, -1, "corrupt rpm database (size)");
+  cnt = getu32((const unsigned char *)dbdata->data);
+  dsize = getu32((const unsigned char *)dbdata->data + 4);
+  if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
+    return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)");
+  l = cnt * 16 + dsize;
+  if (8 + l > dbdata->size)
+    return pool_error(state->pool, -1, "corrupt rpm database (data size)");
+  if (l + 1 > state->rpmheadsize)
+    {
+      state->rpmheadsize = l + 128;
+      state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
+    }
+  rpmhead = state->rpmhead;
+  rpmhead->cnt = cnt;
+  rpmhead->dcnt = dsize;
+  memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l);
+  rpmhead->data[l] = 0;
+  rpmhead->dp = rpmhead->data + cnt * 16;
+  return dbid;
+}
+
+/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
+static int
+getrpm_dbid(struct rpmdbstate *state, Id dbid)
+{
+  unsigned char buf[4];
+  DBT dbkey;
+  DBT dbdata;
+
+  if (dbid <= 0)
+    return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid);
+  if (state->pkgdbopened != 1 && !openpkgdb(state))
+    return -1;
+  rpmdbid2db(buf, dbid, state->byteswapped);
+  memset(&dbkey, 0, sizeof(dbkey));
+  memset(&dbdata, 0, sizeof(dbdata));
+  dbkey.data = buf;
+  dbkey.size = 4;
+  dbdata.data = 0;
+  dbdata.size = 0;
+  if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
+    return 0;
+  return getrpm_dbdata(state, &dbdata, dbid);
+}
+
+static int
+count_headers(struct rpmdbstate *state)
+{
+  Pool *pool = state->pool;
+  struct stat statbuf;
+  DB *db = 0;
+  DBC *dbc = 0;
+  int count = 0;
+  DBT dbkey;
+  DBT dbdata;
+
+  if (stat_database(state, "Name", &statbuf, 0))
+    return 0;
+  memset(&dbkey, 0, sizeof(dbkey));
+  memset(&dbdata, 0, sizeof(dbdata));
+  if (db_create(&db, state->dbenv, 0))
+    {
+      pool_error(pool, 0, "db_create: %s", strerror(errno));
+      return 0;
+    }
+  if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664))
+    {
+      pool_error(pool, 0, "db->open Name: %s", strerror(errno));
+      db->close(db, 0);
+      return 0;
+    }
+  if (db->cursor(db, NULL, &dbc, 0))
+    {
+      db->close(db, 0);
+      pool_error(pool, 0, "db->cursor: %s", strerror(errno));
+      return 0;
+    }
+  while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0)
+    count += dbdata.size / RPM_INDEX_SIZE;
+  dbc->c_close(dbc);
+  db->close(db, 0);
+  return count;
+}
+
+static int
+pkgdb_cursor_open(struct rpmdbstate *state)
+{
+  if (state->db->cursor(state->db, NULL, &state->dbc, 0))
+    return pool_error(state->pool, -1, "db->cursor failed");
+  return 0;
+}
+
+static void
+pkgdb_cursor_close(struct rpmdbstate *state)
+{
+  state->dbc->c_close(state->dbc);
+  state->dbc = 0;
+}
+
+/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */
+static Id
+pkgdb_cursor_getrpm(struct rpmdbstate *state)
+{
+  DBT dbkey;
+  DBT dbdata;
+  Id dbid;
+
+  memset(&dbkey, 0, sizeof(dbkey));
+  memset(&dbdata, 0, sizeof(dbdata));
+  while (state->dbc->c_get(state->dbc, &dbkey, &dbdata, DB_NEXT) == 0)
+    {
+      if (dbkey.size != 4)
+       return pool_error(state->pool, -1, "corrupt Packages database (key size)");
+      dbid = db2rpmdbid(dbkey.data, state->byteswapped);
+      if (dbid)                /* ignore join key */
+        return getrpm_dbdata(state, &dbdata, dbid);
+    }
+  return 0;    /* no more entries */
+}
+
diff --git a/libsolv-0.7.2/ext/repo_rpmdb_librpm.h b/libsolv-0.7.2/ext/repo_rpmdb_librpm.h
new file mode 100644 (file)
index 0000000..79983d3
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_rpmdb_librpm.h
+ *
+ * Use librpm to access the rpm database
+ *
+ */
+
+#include <rpm/rpmts.h>
+#include <rpm/rpmmacro.h>
+
+struct rpmdbstate {
+  Pool *pool;
+  char *rootdir;
+
+  RpmHead *rpmhead;    /* header storage space */
+  int rpmheadsize;
+
+  int dbenvopened;     /* database environment opened */
+  int pkgdbopened;     /* package database openend */
+  int is_ostree;       /* read-only db that lives in /usr/share/rpm */
+
+  rpmts ts;
+  rpmdbMatchIterator mi;       /* iterator over packages database */
+};
+
+static int
+stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+{
+  char *dbpath;
+  dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
+  if (stat(dbpath, statbuf))
+    {
+      if (seterror)
+        pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
+      free(dbpath);
+      return -1;
+    }
+  free(dbpath);
+  return 0;
+}
+
+static int
+opendbenv(struct rpmdbstate *state)
+{
+  const char *rootdir = state->rootdir;
+  rpmts ts;
+  char *dbpath;
+  dbpath = solv_dupjoin("_dbpath ", rootdir, "/var/lib/rpm");
+  if (access(dbpath + 8, W_OK) == -1)
+    {
+      free(dbpath);
+      dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0);
+      if (access(dbpath, R_OK) == 0)
+       state->is_ostree = 1;
+      free(dbpath);
+      dbpath = solv_dupjoin("_dbpath ", rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
+    }
+  rpmDefineMacro(NULL, dbpath, 0);
+  solv_free(dbpath);
+  ts = rpmtsCreate();
+  if (!ts)
+    {
+      pool_error(state->pool, 0, "rpmtsCreate failed");
+      delMacro(NULL, "_dbpath");
+      return 0;
+    }
+  if (rpmtsOpenDB(ts, O_RDONLY))
+    {
+      pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
+      rpmtsFree(ts);
+      delMacro(NULL, "_dbpath");
+      return 0;
+    }
+  delMacro(NULL, "_dbpath");
+  rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
+  state->ts = ts;
+  state->dbenvopened = 1;
+  state->pkgdbopened = 1;
+  return 1;
+}
+
+static void
+closedbenv(struct rpmdbstate *state)
+{
+  if (state->ts)
+    rpmtsFree(state->ts);
+  state->ts = 0;
+  state->pkgdbopened = 0;
+  state->dbenvopened = 0;
+}
+
+static int
+openpkgdb(struct rpmdbstate *state)
+{
+  /* already done in opendbenv */
+  return 1;
+}
+
+static void
+closepkgdb(struct rpmdbstate *state)
+{
+}
+
+/* get the rpmdbids of all installed packages from the Name index database.
+ * This is much faster then querying the big Packages database */
+static struct rpmdbentry *
+getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
+{
+  const void * key;
+  size_t keylen, matchl = 0;
+  Id nameoff;
+
+  char *namedata = 0;
+  int namedatal = 0;
+  struct rpmdbentry *entries = 0;
+  int nentries = 0;
+
+  rpmdbIndexIterator ii;
+  int i;
+
+  *nentriesp = 0;
+  if (namedatap)
+    *namedatap = 0;
+
+  if (state->dbenvopened != 1 && !opendbenv(state))
+    return 0;
+
+  if (match)
+    matchl = strlen(match);
+  ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
+
+  while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
+    {
+      if (match)
+       {
+         if (keylen != matchl || memcmp(key, match, keylen) != 0)
+           continue;
+       }
+      else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
+        continue;
+      nameoff = namedatal;
+      if (namedatap)
+       {
+         namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
+         memcpy(namedata + namedatal, key, keylen);
+         namedata[namedatal + keylen] = 0;
+         namedatal += keylen + 1;
+       }
+      for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++)
+       {
+         entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
+         entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
+         entries[nentries].nameoff = nameoff;
+         nentries++;
+       }
+    }
+  rpmdbIndexIteratorFree(ii);
+  /* make sure that enteries is != 0 if there was no error */
+  if (!entries)
+    entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
+  *nentriesp = nentries;
+  if (namedatap)
+    *namedatap = namedata;
+  return entries;
+}
+
+/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
+static int
+getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
+{
+  Header h;
+  rpmdbMatchIterator mi;
+  unsigned int offset = rpmdbid;
+
+  if (state->dbenvopened != 1 && !opendbenv(state))
+    return -1;
+  mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, &offset, sizeof(offset));
+  h = rpmdbNextIterator(mi);
+  if (!h)
+    {
+      rpmdbFreeIterator(mi);
+      return 0;
+    }
+  if (!rpm_byrpmh(state, h))
+    {
+      rpmdbFreeIterator(mi);
+      return -1;
+    }
+  mi = rpmdbFreeIterator(mi);
+  return 1;
+}
+
+static int
+count_headers(struct rpmdbstate *state)
+{
+  int count;
+  rpmdbMatchIterator mi;
+
+  if (state->dbenvopened != 1 && !opendbenv(state))
+    return 0;
+  mi = rpmtsInitIterator(state->ts, RPMDBI_NAME, NULL, 0);
+  count = rpmdbGetIteratorCount(mi);
+  rpmdbFreeIterator(mi);
+  return count;
+}
+
+static int
+pkgdb_cursor_open(struct rpmdbstate *state)
+{
+  state->mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, NULL, 0);
+  return 0;
+}
+
+static void
+pkgdb_cursor_close(struct rpmdbstate *state)
+{
+  rpmdbFreeIterator(state->mi);
+  state->mi = 0;
+}
+
+static Id
+pkgdb_cursor_getrpm(struct rpmdbstate *state)
+{
+  Header h;
+  while ((h = rpmdbNextIterator(state->mi)))
+    {
+      Id dbid = rpmdbGetIteratorOffset(state->mi);
+      if (!rpm_byrpmh(state, h))
+       continue;
+      return dbid;
+    }
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/ext/repo_rpmmd.c b/libsolv-0.7.2/ext/repo_rpmmd.c
new file mode 100644 (file)
index 0000000..9bb50a0
--- /dev/null
@@ -0,0 +1,1164 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#define DISABLE_SPLIT
+#include "tools_util.h"
+#include "repo_rpmmd.h"
+#include "chksum.h"
+#include "solv_xmlparser.h"
+#ifdef ENABLE_COMPLEX_DEPS
+#include "pool_parserpmrichdep.h"
+#endif
+#include "repodata_diskusage.h"
+
+enum state {
+  STATE_START,
+
+  STATE_SOLVABLE,
+
+  STATE_NAME,
+  STATE_ARCH,
+  STATE_VERSION,
+
+  /* package rpm-md */
+  STATE_LOCATION,
+  STATE_CHECKSUM,
+  STATE_RPM_GROUP,
+  STATE_RPM_LICENSE,
+
+  /* resobject attributes */
+  STATE_SUMMARY,
+  STATE_DESCRIPTION,
+  STATE_DISTRIBUTION,
+  STATE_PACKAGER,
+  STATE_URL,
+  STATE_INSNOTIFY,
+  STATE_DELNOTIFY,
+  STATE_VENDOR,
+  STATE_SIZE,
+  STATE_TIME,
+  STATE_DOWNLOADSIZE,
+  STATE_INSTALLTIME,
+  STATE_INSTALLONLY,
+
+  /* Novell/SUSE extended attributes */
+  STATE_EULA,
+  STATE_KEYWORD,
+  STATE_DISKUSAGE,
+  STATE_DIRS,
+  STATE_DIR,
+
+  /* patch */
+  STATE_ID,
+  STATE_TIMESTAMP,
+  STATE_AFFECTSPKG,
+  STATE_REBOOTNEEDED,
+
+  /* pattern attributes */
+  STATE_CATEGORY, /* pattern and patches */
+  STATE_ORDER,
+  STATE_INCLUDES,
+  STATE_INCLUDESENTRY,
+  STATE_EXTENDS,
+  STATE_EXTENDSENTRY,
+  STATE_SCRIPT,
+  STATE_ICON,
+  STATE_USERVISIBLE,
+  STATE_DEFAULT,
+  STATE_INSTALL_TIME,
+
+  /* product */
+  STATE_RELNOTESURL,
+  STATE_UPDATEURL,
+  STATE_OPTIONALURL,
+  STATE_FLAG,
+
+  /* rpm-md dependencies inside the format tag */
+  STATE_PROVIDES,
+  STATE_REQUIRES,
+  STATE_OBSOLETES,
+  STATE_CONFLICTS,
+  STATE_RECOMMENDS,
+  STATE_SUPPLEMENTS,
+  STATE_SUGGESTS,
+  STATE_ENHANCES,
+  STATE_FRESHENS,
+  STATE_SOURCERPM,
+  STATE_HEADERRANGE,
+
+  STATE_PROVIDESENTRY,
+  STATE_REQUIRESENTRY,
+  STATE_OBSOLETESENTRY,
+  STATE_CONFLICTSENTRY,
+  STATE_RECOMMENDSENTRY,
+  STATE_SUPPLEMENTSENTRY,
+  STATE_SUGGESTSENTRY,
+  STATE_ENHANCESENTRY,
+  STATE_FRESHENSENTRY,
+
+  STATE_FILE,
+
+  STATE_CHANGELOG,
+
+  /* general */
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  /** fake tag used to enclose multiple xml files in one **/
+  { STATE_START,       "rpmmd",           STATE_START,    0 },
+
+  /** tags for different package data, just ignore them **/
+  { STATE_START,       "patterns",        STATE_START,    0 },
+  { STATE_START,       "products",        STATE_START,    0 },
+  { STATE_START,       "metadata",        STATE_START,    0 },
+  { STATE_START,       "otherdata",       STATE_START,    0 },
+  { STATE_START,       "filelists",       STATE_START,    0 },
+  { STATE_START,       "diskusagedata",   STATE_START,    0 },
+  { STATE_START,       "susedata",        STATE_START,    0 },
+
+  { STATE_START,       "product",         STATE_SOLVABLE, 0 },
+  { STATE_START,       "pattern",         STATE_SOLVABLE, 0 },
+  { STATE_START,       "patch",           STATE_SOLVABLE, 0 },
+  { STATE_START,       "package",         STATE_SOLVABLE, 0 },
+
+  { STATE_SOLVABLE,    "format",          STATE_SOLVABLE, 0 },
+
+  { STATE_SOLVABLE,    "name",            STATE_NAME, 1 },
+  { STATE_SOLVABLE,    "arch",            STATE_ARCH, 1 },
+  { STATE_SOLVABLE,    "version",         STATE_VERSION, 0 },
+
+  /* package attributes rpm-md */
+  { STATE_SOLVABLE,    "location",        STATE_LOCATION, 0 },
+  { STATE_SOLVABLE,    "checksum",        STATE_CHECKSUM, 1 },
+
+  /* resobject attributes */
+
+  { STATE_SOLVABLE,    "summary",         STATE_SUMMARY,      1 },
+  { STATE_SOLVABLE,    "description",     STATE_DESCRIPTION,  1 },
+  { STATE_SOLVABLE,    "distribution",    STATE_DISTRIBUTION, 1 },
+  { STATE_SOLVABLE,    "url",             STATE_URL,          1 },
+  { STATE_SOLVABLE,    "packager",        STATE_PACKAGER,     1 },
+  { STATE_SOLVABLE,    "vendor",          STATE_VENDOR,       1 },
+  { STATE_SOLVABLE,    "size",            STATE_SIZE,         0 },
+  { STATE_SOLVABLE,    "archive-size",    STATE_DOWNLOADSIZE, 1 },
+  { STATE_SOLVABLE,    "install-time",    STATE_INSTALLTIME,  1 },
+  { STATE_SOLVABLE,    "install-only",    STATE_INSTALLONLY,  1 },
+  { STATE_SOLVABLE,    "time",            STATE_TIME,         0 },
+
+  /* extended Novell/SUSE attributes (susedata.xml) */
+  { STATE_SOLVABLE,    "eula",            STATE_EULA,         1 },
+  { STATE_SOLVABLE,    "keyword",         STATE_KEYWORD,      1 },
+  { STATE_SOLVABLE,    "diskusage",       STATE_DISKUSAGE,    0 },
+
+  /* pattern attribute */
+  { STATE_SOLVABLE,    "script",          STATE_SCRIPT,        1 },
+  { STATE_SOLVABLE,    "icon",            STATE_ICON,          1 },
+  { STATE_SOLVABLE,    "uservisible",     STATE_USERVISIBLE,   1 },
+  { STATE_SOLVABLE,    "category",        STATE_CATEGORY,      1 },
+  { STATE_SOLVABLE,    "order",           STATE_ORDER,         1 },
+  { STATE_SOLVABLE,    "includes",        STATE_INCLUDES,      0 },
+  { STATE_SOLVABLE,    "extends",         STATE_EXTENDS,       0 },
+  { STATE_SOLVABLE,    "default",         STATE_DEFAULT,       1 },
+  { STATE_SOLVABLE,    "install-time",    STATE_INSTALL_TIME,  1 },
+
+  /* product attributes */
+  /* note the product type is an attribute */
+  { STATE_SOLVABLE,    "release-notes-url", STATE_RELNOTESURL, 1 },
+  { STATE_SOLVABLE,    "update-url",      STATE_UPDATEURL,   1 },
+  { STATE_SOLVABLE,    "optional-url",    STATE_OPTIONALURL, 1 },
+  { STATE_SOLVABLE,    "flag",            STATE_FLAG,        1 },
+
+  { STATE_SOLVABLE,    "rpm:vendor",      STATE_VENDOR,      1 },
+  { STATE_SOLVABLE,    "rpm:group",       STATE_RPM_GROUP,   1 },
+  { STATE_SOLVABLE,    "rpm:license",     STATE_RPM_LICENSE, 1 },
+
+  /* rpm-md dependencies */
+  { STATE_SOLVABLE,    "rpm:provides",    STATE_PROVIDES,     0 },
+  { STATE_SOLVABLE,    "rpm:requires",    STATE_REQUIRES,     0 },
+  { STATE_SOLVABLE,    "rpm:obsoletes",   STATE_OBSOLETES,    0 },
+  { STATE_SOLVABLE,    "rpm:conflicts",   STATE_CONFLICTS,    0 },
+  { STATE_SOLVABLE,    "rpm:recommends",  STATE_RECOMMENDS ,  0 },
+  { STATE_SOLVABLE,    "rpm:supplements", STATE_SUPPLEMENTS,  0 },
+  { STATE_SOLVABLE,    "rpm:suggests",    STATE_SUGGESTS,     0 },
+  { STATE_SOLVABLE,    "rpm:enhances",    STATE_ENHANCES,     0 },
+  { STATE_SOLVABLE,    "rpm:freshens",    STATE_FRESHENS,     0 },
+  { STATE_SOLVABLE,    "rpm:sourcerpm",   STATE_SOURCERPM,    1 },
+  { STATE_SOLVABLE,    "rpm:header-range", STATE_HEADERRANGE, 0 },
+  { STATE_SOLVABLE,    "file",            STATE_FILE, 1 },
+  { STATE_SOLVABLE,    "changelog",       STATE_CHANGELOG, 1 },
+
+   /* extended Novell/SUSE diskusage attributes (susedata.xml) */
+  { STATE_DISKUSAGE,   "dirs",            STATE_DIRS,         0 },
+  { STATE_DIRS,        "dir",             STATE_DIR,          0 },
+
+  { STATE_PROVIDES,    "rpm:entry",       STATE_PROVIDESENTRY, 0 },
+  { STATE_REQUIRES,    "rpm:entry",       STATE_REQUIRESENTRY, 0 },
+  { STATE_OBSOLETES,   "rpm:entry",       STATE_OBSOLETESENTRY, 0 },
+  { STATE_CONFLICTS,   "rpm:entry",       STATE_CONFLICTSENTRY, 0 },
+  { STATE_RECOMMENDS,  "rpm:entry",       STATE_RECOMMENDSENTRY, 0 },
+  { STATE_SUPPLEMENTS, "rpm:entry",       STATE_SUPPLEMENTSENTRY, 0 },
+  { STATE_SUGGESTS,    "rpm:entry",       STATE_SUGGESTSENTRY, 0 },
+  { STATE_ENHANCES,    "rpm:entry",       STATE_ENHANCESENTRY, 0 },
+  { STATE_FRESHENS,    "rpm:entry",       STATE_FRESHENSENTRY, 0 },
+
+  { STATE_INCLUDES,    "item",            STATE_INCLUDESENTRY, 0 },
+  { STATE_EXTENDS,     "item",            STATE_EXTENDSENTRY,  0 },
+
+  { NUMSTATES}
+};
+
+struct parsedata {
+  int ret;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  char *kind;
+  Solvable *solvable;
+  Offset freshens;
+
+  struct solv_xmlparser xmlp;
+  struct joindata jd;
+  /* temporal to store attribute tag language */
+  const char *tmplang;
+  Id chksumtype;
+  Id handle;
+  Queue diskusageq;
+  const char *language;                        /* default language */
+  Id langcache[ID_NUM_INTERNAL];       /* cache for the default language */
+
+  Id lastdir;
+  char *lastdirstr;
+  int lastdirstrl;
+
+  Id changelog_handle;
+
+  int extending;                       /* are we extending an existing solvable? */
+  int first;                           /* first solvable we added */
+  int cshash_filled;                   /* hash is filled with data */
+
+  Hashtable cshash;                    /* checksum hash -> offset into csdata */
+  Hashval cshashm;                     /* hash mask */
+  int ncshash;                         /* entries used */
+  unsigned char *csdata;               /* [len, checksum, id] */
+  int ncsdata;                         /* used bytes */
+};
+
+static Id
+langtag(struct parsedata *pd, Id tag, const char *language)
+{
+  if (language)
+    {
+      if (!language[0] || !strcmp(language, "en"))
+       return tag;
+      return pool_id2langid(pd->pool, tag, language, 1);
+    }
+  if (!pd->language)
+    return tag;
+  if (tag >= ID_NUM_INTERNAL)
+    return pool_id2langid(pd->pool, tag, pd->language, 1);
+  if (!pd->langcache[tag])
+    pd->langcache[tag] = pool_id2langid(pd->pool, tag, pd->language, 1);
+  return pd->langcache[tag];
+}
+
+/*
+ * makeevr_atts
+ * parse 'epoch', 'ver' and 'rel', return evr Id
+ *
+ */
+
+static Id
+makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
+{
+  const char *e, *v, *r, *v2;
+  char *c, *space;
+  int l;
+
+  e = v = r = 0;
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, "epoch"))
+       e = atts[1];
+      else if (!strcmp(*atts, "ver"))
+       v = atts[1];
+      else if (!strcmp(*atts, "rel"))
+       r = atts[1];
+    }
+  if (e && (!*e || !strcmp(e, "0")))
+    e = 0;
+  if (v && !e)
+    {
+      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
+        ;
+      if (v2 > v && *v2 == ':')
+       e = "0";
+    }
+  l = 1;
+  if (e)
+    l += strlen(e) + 1;
+  if (v)
+    l += strlen(v);
+  if (r)
+    l += strlen(r) + 1;
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
+  if (e)
+    {
+      strcpy(c, e);
+      c += strlen(c);
+      *c++ = ':';
+    }
+  if (v)
+    {
+      strcpy(c, v);
+      c += strlen(c);
+    }
+  if (r)
+    {
+      *c++ = '-';
+      strcpy(c, r);
+      c += strlen(c);
+    }
+  *c = 0;
+  if (!*space)
+    return 0;
+#if 0
+  fprintf(stderr, "evr: %s\n", space);
+#endif
+  return pool_str2id(pool, space, 1);
+}
+
+
+/*
+ * dependency relations
+ */
+
+static char *flagtab[] = {
+  "GT",
+  "EQ",
+  "GE",
+  "LT",
+  "NE",
+  "LE"
+};
+
+
+/*
+ * adddep
+ * parse attributes to reldep Id
+ *
+ */
+
+static unsigned int
+adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, const char **atts, int isreq)
+{
+  Id id, marker;
+  const char *n, *f, *k;
+  const char **a;
+
+  n = f = k = 0;
+  marker = isreq ? -SOLVABLE_PREREQMARKER : 0;
+  for (a = atts; *a; a += 2)
+    {
+      if (!strcmp(*a, "name"))
+       n = a[1];
+      else if (!strcmp(*a, "flags"))
+       f = a[1];
+      else if (!strcmp(*a, "kind"))
+       k = a[1];
+      else if (isreq && !strcmp(*a, "pre") && a[1][0] == '1')
+       marker = SOLVABLE_PREREQMARKER;
+    }
+  if (!n)
+    return olddeps;
+  if (k && !strcmp(k, "package"))
+    k = 0;
+  if (k)
+    {
+      int l = strlen(k) + 1 + strlen(n) + 1;
+      char *space = solv_xmlparser_contentspace(&pd->xmlp, l);
+      sprintf(space, "%s:%s", k, n);
+      id = pool_str2id(pool, space, 1);
+    }
+#ifdef ENABLE_COMPLEX_DEPS
+  else if (!f && n[0] == '(')
+    {
+      id = pool_parserpmrichdep(pool, n);
+      if (!id)
+       return olddeps;
+    }
+#endif
+  else
+    id = pool_str2id(pool, (char *)n, 1);
+  if (f)
+    {
+      Id evr = makeevr_atts(pool, pd, atts);
+      int flags;
+      for (flags = 0; flags < 6; flags++)
+       if (!strcmp(f, flagtab[flags]))
+         break;
+      flags = flags < 6 ? flags + 1 : 0;
+      id = pool_rel2id(pool, id, evr, flags, 1);
+    }
+#if 0
+  fprintf(stderr, "new dep %s\n", pool_dep2str(pool, id));
+#endif
+  return repo_addid_dep(pd->repo, olddeps, id, marker);
+}
+
+
+/*
+ * set_description_author
+ *
+ */
+static void
+set_description_author(Repodata *data, Id handle, char *str, struct parsedata *pd)
+{
+  char *aut, *p;
+
+  if (!str || !*str)
+    return;
+  for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++)
+    if (!strncmp(aut, "\nAuthors:\n--------\n", 19))
+      break;
+  if (aut)
+    {
+      /* oh my, found SUSE special author section */
+      int l = aut - str;
+      str[l] = 0;
+      while (l > 0 && str[l - 1] == '\n')
+       str[--l] = 0;
+      if (l)
+       repodata_set_str(data, handle, langtag(pd, SOLVABLE_DESCRIPTION, pd->tmplang), str);
+      p = aut + 19;
+      aut = str;        /* copy over */
+      while (*p == ' ' || *p == '\n')
+       p++;
+      while (*p)
+       {
+         if (*p == '\n')
+           {
+             *aut++ = *p++;
+             while (*p == ' ')
+               p++;
+             continue;
+           }
+         *aut++ = *p++;
+       }
+      while (aut != str && aut[-1] == '\n')
+       aut--;
+      *aut = 0;
+      if (*str)
+       repodata_set_str(data, handle, SOLVABLE_AUTHORS, str);
+    }
+  else if (*str)
+    repodata_set_str(data, handle, langtag(pd, SOLVABLE_DESCRIPTION, pd->tmplang), str);
+}
+
+
+/*-----------------------------------------------*/
+/* checksum hash functions
+ *
+ * used to look up a solvable with the checksum for solvable extension purposes.
+ *
+ */
+
+static void
+init_cshash(struct parsedata *pd)
+{
+}
+
+static void
+free_cshash(struct parsedata *pd)
+{
+  pd->cshash = solv_free(pd->cshash);
+  pd->ncshash = 0;
+  pd->cshashm = 0;
+  pd->csdata = solv_free(pd->csdata);
+  pd->ncsdata = 0;
+}
+
+static inline Hashval
+hashkey(const unsigned char *key, int keyl)
+{
+  return key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3];
+}
+
+static void
+rebuild_cshash(struct parsedata *pd)
+{
+  Hashval h, hh, hm;
+  Hashtable ht;
+  unsigned char *d, *de;
+
+  hm = pd->cshashm;
+#if 0
+  fprintf(stderr, "rebuild cshash with mask 0x%x\n", hm);
+#endif
+  solv_free(pd->cshash);
+  ht = pd->cshash = (Hashtable)solv_calloc(hm + 1, sizeof(Id));
+  d = pd->csdata;
+  de = d + pd->ncsdata;
+  while (d != de)
+    {
+      h = hashkey(d + 1, d[0] + 1) & hm;
+      hh = HASHCHAIN_START;
+      while (ht[h])
+       h = HASHCHAIN_NEXT(h, hh, hm);
+      ht[h] = d + 1 - pd->csdata;
+      d += 2 + d[0] + sizeof(Id);
+    }
+}
+
+static void
+put_in_cshash(struct parsedata *pd, const unsigned char *key, int keyl, Id id)
+{
+  Hashtable ht;
+  Hashval h, hh, hm;
+  unsigned char *d;
+
+  if (keyl < 4 || keyl > 256)
+    return;
+  ht = pd->cshash;
+  hm = pd->cshashm;
+  h = hashkey(key, keyl) & hm;
+  hh = HASHCHAIN_START;
+  if (ht)
+    {
+      while (ht[h])
+       {
+         unsigned char *d = pd->csdata + ht[h];
+         if (d[-1] == keyl - 1 && !memcmp(key, d, keyl))
+           return;             /* XXX: first id wins... */
+         h = HASHCHAIN_NEXT(h, hh, hm);
+       }
+    }
+  /* a new entry. put in csdata */
+  pd->csdata = solv_extend(pd->csdata, pd->ncsdata, 1 + keyl + sizeof(Id), 1, 4095);
+  d = pd->csdata + pd->ncsdata;
+  d[0] = keyl - 1;
+  memcpy(d + 1, key, keyl);
+  memcpy(d + 1 + keyl, &id, sizeof(Id));
+  pd->ncsdata += 1 + keyl + sizeof(Id);
+  if ((Hashval)++pd->ncshash * 2 > hm)
+    {
+      pd->cshashm = pd->cshashm ? (2 * pd->cshashm + 1) : 4095;
+      rebuild_cshash(pd);
+    }
+  else
+    ht[h] = pd->ncsdata - (keyl + sizeof(Id));
+}
+
+static Id
+lookup_cshash(struct parsedata *pd, const unsigned char *key, int keyl)
+{
+  Hashtable ht;
+  Hashval h, hh, hm;
+
+  if (keyl < 4 || keyl > 256)
+    return 0;
+  ht = pd->cshash;
+  if (!ht)
+    return 0;
+  hm = pd->cshashm;
+  h = hashkey(key, keyl) & hm;
+  hh = HASHCHAIN_START;
+  while (ht[h])
+    {
+      unsigned char *d = pd->csdata + ht[h];
+      if (d[-1] == keyl - 1 && !memcmp(key, d, keyl))
+       {
+         Id id;
+         memcpy(&id, d + keyl, sizeof(Id));
+         return id;
+       }
+      h = HASHCHAIN_NEXT(h, hh, hm);
+    }
+  return 0;
+}
+
+static void
+fill_cshash_from_repo(struct parsedata *pd)
+{
+  Dataiterator di;
+  /* setup join data */
+  dataiterator_init(&di, pd->pool, pd->repo, 0, SOLVABLE_CHECKSUM, 0, 0);
+  while (dataiterator_step(&di))
+    put_in_cshash(pd, (const unsigned char *)di.kv.str, solv_chksum_len(di.key->type), di.solvid);
+  dataiterator_free(&di);
+}
+
+static void
+fill_cshash_from_new_solvables(struct parsedata *pd)
+{
+  Pool *pool = pd->pool;
+  int i, l;
+  KeyValue kv;
+  Repokey *key;
+
+  for (i = pd->first; i < pool->nsolvables; i++)
+    {
+      if (pool->solvables[i].repo != pd->repo)
+       continue;
+      if ((key = repodata_lookup_kv_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &kv)) == 0)
+       continue;
+      if ((l = solv_chksum_len(key->type)) != 0)
+       put_in_cshash(pd, (const unsigned char *)kv.str, l, i);
+    }
+}
+
+/*-----------------------------------------------*/
+/* XML callbacks */
+
+/*
+ * startElement
+ */
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+  Id handle = pd->handle;
+  const char *str;
+  const char *pkgid;
+
+  if (!s && state != STATE_SOLVABLE)
+    return;
+
+  switch(state)
+    {
+    case STATE_SOLVABLE:
+      pd->kind = 0;
+      if (name[2] == 't' && name[3] == 't')
+        pd->kind = "pattern";
+      else if (name[1] == 'r')
+        pd->kind = "product";
+      else if (name[2] == 't' && name[3] == 'c')
+        pd->kind = "patch";
+
+      /* to support extension metadata files like others.xml which
+         have the following structure:
+
+         <otherdata xmlns="http://linux.duke.edu/metadata/other"
+                    packages="101">
+           <package pkgid="b78f8664cd90efe42e09a345e272997ef1b53c18"
+                    name="zaptel-kmp-default"
+                    arch="i586"><version epoch="0"
+                    ver="1.2.10_2.6.22_rc4_git6_2" rel="70"/>
+              ...
+
+         we need to check if the pkgid is there and if it matches
+         an already seen package, that means we don't need to create
+         a new solvable but just append the attributes to the existing
+         one.
+      */
+      pd->extending = 0;
+      if ((pkgid = solv_xmlparser_find_attr("pkgid", atts)) != NULL)
+        {
+         unsigned char chk[256];
+         int l;
+         const char *str = pkgid;
+         if (!pd->cshash_filled)
+           {
+             pd->cshash_filled = 1;
+             fill_cshash_from_new_solvables(pd);
+           }
+         handle = 0;
+         /* convert into bin checksum */
+         l = solv_hex2bin(&str, chk, sizeof(chk));
+          /* look at the checksum cache */
+         if (l >= 4 && !pkgid[2 * l])
+           handle = lookup_cshash(pd, chk, l);
+#if 0
+         fprintf(stderr, "Lookup %s -> %d\n", pkgid, handle);
+#endif
+         if (!handle)
+           {
+              pool_debug(pool, SOLV_WARN, "the repository specifies extra information about package with checksum '%s', which does not exist in the repository.\n", pkgid);
+             pd->handle = 0;
+             pd->solvable = 0;
+             break;
+           }
+         pd->extending = 1;
+        }
+      else
+        {
+          /* this is a new package */
+         handle = repo_add_solvable(pd->repo);
+         if (!pd->first)
+           pd->first = handle;
+          pd->freshens = 0;
+        }
+      pd->handle = handle;
+      pd->solvable = pool_id2solvable(pool, handle);
+      if (pd->kind && pd->kind[1] == 'r')
+       {
+         /* products can have a type */
+         const char *type = solv_xmlparser_find_attr("type", atts);
+         if (type && *type)
+           repodata_set_str(pd->data, handle, PRODUCT_TYPE, type);
+       }
+#if 0
+      fprintf(stderr, "package #%d\n", pd->solvable - pool->solvables);
+#endif
+
+      break;
+    case STATE_VERSION:
+      if (pd->extending && s->evr)
+       break;          /* ignore version tag repetition in extend data */
+      s->evr = makeevr_atts(pool, pd, atts);
+      break;
+    case STATE_PROVIDES:
+      s->provides = 0;
+      break;
+    case STATE_PROVIDESENTRY:
+      s->provides = adddep(pool, pd, s->provides, atts, 0);
+      break;
+    case STATE_REQUIRES:
+      s->requires = 0;
+      break;
+    case STATE_REQUIRESENTRY:
+      s->requires = adddep(pool, pd, s->requires, atts, 1);
+      break;
+    case STATE_OBSOLETES:
+      s->obsoletes = 0;
+      break;
+    case STATE_OBSOLETESENTRY:
+      s->obsoletes = adddep(pool, pd, s->obsoletes, atts, 0);
+      break;
+    case STATE_CONFLICTS:
+      s->conflicts = 0;
+      break;
+    case STATE_CONFLICTSENTRY:
+      s->conflicts = adddep(pool, pd, s->conflicts, atts, 0);
+      break;
+    case STATE_RECOMMENDS:
+      s->recommends = 0;
+      break;
+    case STATE_RECOMMENDSENTRY:
+      s->recommends = adddep(pool, pd, s->recommends, atts, 0);
+      break;
+    case STATE_SUPPLEMENTS:
+      s->supplements= 0;
+      break;
+    case STATE_SUPPLEMENTSENTRY:
+      s->supplements = adddep(pool, pd, s->supplements, atts, 0);
+      break;
+    case STATE_SUGGESTS:
+      s->suggests = 0;
+      break;
+    case STATE_SUGGESTSENTRY:
+      s->suggests = adddep(pool, pd, s->suggests, atts, 0);
+      break;
+    case STATE_ENHANCES:
+      s->enhances = 0;
+      break;
+    case STATE_ENHANCESENTRY:
+      s->enhances = adddep(pool, pd, s->enhances, atts, 0);
+      break;
+    case STATE_FRESHENS:
+      pd->freshens = 0;
+      break;
+    case STATE_FRESHENSENTRY:
+      pd->freshens = adddep(pool, pd, pd->freshens, atts, 0);
+      break;
+    case STATE_EULA:
+    case STATE_SUMMARY:
+    case STATE_CATEGORY:
+    case STATE_DESCRIPTION:
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
+      break;
+    case STATE_USERVISIBLE:
+      repodata_set_void(pd->data, handle, SOLVABLE_ISVISIBLE);
+      break;
+    case STATE_INCLUDESENTRY:
+      str = solv_xmlparser_find_attr("pattern", atts);
+      if (str)
+       repodata_add_poolstr_array(pd->data, handle, SOLVABLE_INCLUDES, join2(&pd->jd, "pattern", ":", str));
+      break;
+    case STATE_EXTENDSENTRY:
+      str = solv_xmlparser_find_attr("pattern", atts);
+      if (str)
+       repodata_add_poolstr_array(pd->data, handle, SOLVABLE_EXTENDS, join2(&pd->jd, "pattern", ":", str));
+      break;
+    case STATE_LOCATION:
+      str = solv_xmlparser_find_attr("href", atts);
+      if (str)
+       {
+         int medianr = 0;
+         const char *base = solv_xmlparser_find_attr("xml:base", atts);
+         if (base  && !strncmp(base, "media:", 6))
+           {
+             /* check for the media number in the fragment */
+             int l = strlen(base);
+             while (l && base[l - 1] >= '0' && base[l - 1] <= '9')
+               l--;
+             if (l && base[l - 1] == '#' && base[l])
+               medianr = atoi(base + l);
+           }
+         repodata_set_location(pd->data, handle, medianr, 0, str);
+         if (base)
+           repodata_set_poolstr(pd->data, handle, SOLVABLE_MEDIABASE, base);
+       }
+      break;
+    case STATE_CHECKSUM:
+      str = solv_xmlparser_find_attr("type", atts);
+      pd->chksumtype = str && *str ? solv_chksum_str2type(str) : 0;
+      if (!pd->chksumtype)
+       pd->ret = pool_error(pool, -1, "line %d: unknown checksum type: %s", solv_xmlparser_lineno(xmlp), str ? str : "NULL");
+      break;
+    case STATE_TIME:
+      {
+        unsigned int t;
+        str = solv_xmlparser_find_attr("build", atts);
+        if (str && (t = atoi(str)) != 0)
+          repodata_set_num(pd->data, handle, SOLVABLE_BUILDTIME, t);
+       break;
+      }
+    case STATE_SIZE:
+      if ((str = solv_xmlparser_find_attr("installed", atts)) != 0)
+       repodata_set_num(pd->data, handle, SOLVABLE_INSTALLSIZE, strtoull(str, 0, 10));
+      if ((str = solv_xmlparser_find_attr("package", atts)) != 0)
+       repodata_set_num(pd->data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(str, 0, 10));
+      break;
+    case STATE_HEADERRANGE:
+      {
+        unsigned int end;
+        str = solv_xmlparser_find_attr("end", atts);
+       if (str && (end = atoi(str)) != 0)
+         repodata_set_num(pd->data, handle, SOLVABLE_HEADEREND, end);
+       break;
+      }
+      /*
+        <diskusage>
+          <dirs>
+            <dir name="/" size="56" count="11"/>
+            <dir name="usr/" size="56" count="11"/>
+            <dir name="usr/bin/" size="38" count="10"/>
+            <dir name="usr/share/" size="18" count="1"/>
+            <dir name="usr/share/doc/" size="18" count="1"/>
+          </dirs>
+        </diskusage>
+      */
+    case STATE_DISKUSAGE:
+      {
+        /* Really, do nothing, wait for <dir> tag */
+        break;
+      }
+    case STATE_DIR:
+      {
+        long filesz = 0, filenum = 0;
+        Id did;
+
+        if ((str = solv_xmlparser_find_attr("name", atts)) == 0)
+         {
+           pd->ret = pool_error(pool, -1, "<dir .../> tag without 'name' attribute");
+            break;
+         }
+       if (*str != '/')
+         {
+           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+             str = "/usr/src";
+           else
+             {
+               int l = strlen(str) + 2;
+               char *space = solv_xmlparser_contentspace(xmlp, l);
+               space[0] = '/';
+               memcpy(space + 1, str, l - 1);
+               str = space;
+           }
+         }
+        did = repodata_str2dir(pd->data, str, 1);
+        if ((str = solv_xmlparser_find_attr("size", atts)) != 0)
+          filesz = strtol(str, 0, 0);
+        if ((str = solv_xmlparser_find_attr("count", atts)) != 0)
+          filenum = strtol(str, 0, 0);
+        if (filesz || filenum)
+          {
+            queue_push(&pd->diskusageq, did);
+            queue_push2(&pd->diskusageq, filesz, filenum);
+          }
+        break;
+      }
+    case STATE_CHANGELOG:
+      pd->changelog_handle = repodata_new_handle(pd->data);
+      if ((str = solv_xmlparser_find_attr("date", atts)) != 0)
+       repodata_set_num(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TIME, strtoull(str, 0, 10));
+      if ((str = solv_xmlparser_find_attr("author", atts)) != 0)
+       repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_AUTHOR, str);
+      break;
+    default:
+      break;
+    }
+}
+
+
+/*
+ * endElement
+ */
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+  Repo *repo = pd->repo;
+  Id handle = pd->handle;
+  Id id;
+  char *p;
+
+  if (!s)
+    return;
+
+  switch (state)
+    {
+    case STATE_SOLVABLE:
+      if (pd->extending)
+       {
+         pd->solvable = 0;
+         break;
+       }
+      if (pd->kind && !s->name) /* add namespace in case of NULL name */
+        s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", 0), 1);
+      if (!s->arch)
+        s->arch = ARCH_NOARCH;
+      if (!s->evr)
+        s->evr = ID_EMPTY;     /* some patterns have this */
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+        s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      repo_rewrite_suse_deps(s, pd->freshens);
+      pd->freshens = 0;
+      pd->kind = 0;
+      pd->solvable = 0;
+      break;
+    case STATE_NAME:
+      if (pd->kind)
+        s->name = pool_str2id(pool, join2(&pd->jd, pd->kind, ":", content), 1);
+      else
+        s->name = pool_str2id(pool, content, 1);
+      break;
+    case STATE_ARCH:
+      s->arch = pool_str2id(pool, content, 1);
+      break;
+    case STATE_VENDOR:
+      s->vendor = pool_str2id(pool, content, 1);
+      break;
+    case STATE_RPM_GROUP:
+      repodata_set_poolstr(pd->data, handle, SOLVABLE_GROUP, content);
+      break;
+    case STATE_RPM_LICENSE:
+      repodata_set_poolstr(pd->data, handle, SOLVABLE_LICENSE, content);
+      break;
+    case STATE_CHECKSUM:
+      {
+       unsigned char chk[256];
+       int l = solv_chksum_len(pd->chksumtype);
+       const char *str = content;
+       if (!l || l > sizeof(chk))
+         break;
+       if (solv_hex2bin(&str, chk, l) != l || content[2 * l])
+          {
+           pd->ret = pool_error(pool, -1, "line %u: invalid %s checksum", solv_xmlparser_lineno(xmlp), solv_chksum_type2str(pd->chksumtype));
+           break;
+          }
+        repodata_set_bin_checksum(pd->data, handle, SOLVABLE_CHECKSUM, pd->chksumtype, chk);
+       /* we save the checksum to solvable id relationship for extending metadata */
+       if (pd->cshash_filled)
+         put_in_cshash(pd, chk, l, s - pool->solvables);
+        break;
+      }
+    case STATE_FILE:
+      if ((p = strrchr(content, '/')) != 0)
+       {
+         *p++ = 0;
+         if (pd->lastdir && !strcmp(pd->lastdirstr, content))
+           {
+             id = pd->lastdir;
+           }
+         else
+           {
+             int l = p - content;
+             if (l + 1 > pd->lastdirstrl)      /* + 1 for the possible leading / we need to insert */
+               {
+                 pd->lastdirstrl = l + 128;
+                 pd->lastdirstr = solv_realloc(pd->lastdirstr, pd->lastdirstrl);
+               }
+             if (content[0] != '/')
+               {
+                 pd->lastdirstr[0] = '/';
+                 memcpy(pd->lastdirstr + 1, content, l);
+                 id = repodata_str2dir(pd->data, pd->lastdirstr, 1);
+               }
+             else
+               id = repodata_str2dir(pd->data, content, 1);
+             pd->lastdir = id;
+             memcpy(pd->lastdirstr, content, l);
+           }
+       }
+      else
+       {
+         p = content;
+         id = repodata_str2dir(pd->data, "/", 1);
+       }
+      repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, id, p);
+      break;
+    case STATE_SUMMARY:
+      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), content);
+      break;
+    case STATE_DESCRIPTION:
+      set_description_author(pd->data, handle, content, pd);
+      break;
+    case STATE_CATEGORY:
+      repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_CATEGORY, pd->tmplang), content);
+      break;
+    case STATE_DISTRIBUTION:
+        repodata_set_poolstr(pd->data, handle, SOLVABLE_DISTRIBUTION, content);
+        break;
+    case STATE_URL:
+      if (*content)
+       repodata_set_str(pd->data, handle, SOLVABLE_URL, content);
+      break;
+    case STATE_PACKAGER:
+      if (*content)
+       repodata_set_poolstr(pd->data, handle, SOLVABLE_PACKAGER, content);
+      break;
+    case STATE_SOURCERPM:
+      if (*content)
+       repodata_set_sourcepkg(pd->data, handle, content);
+      break;
+    case STATE_RELNOTESURL:
+      if (*content)
+        {
+          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
+          repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "releasenotes", 1));
+        }
+      break;
+    case STATE_UPDATEURL:
+      if (*content)
+        {
+          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
+          repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "update", 1));
+        }
+      break;
+    case STATE_OPTIONALURL:
+      if (*content)
+        {
+          repodata_add_poolstr_array(pd->data, handle, PRODUCT_URL, content);
+          repodata_add_idarray(pd->data, handle, PRODUCT_URL_TYPE, pool_str2id(pool, "optional", 1));
+        }
+      break;
+    case STATE_FLAG:
+      if (*content)
+        repodata_add_poolstr_array(pd->data, handle, PRODUCT_FLAGS, content);
+      break;
+    case STATE_EULA:
+      if (*content)
+       repodata_set_str(pd->data, handle, langtag(pd, SOLVABLE_EULA, pd->tmplang), content);
+      break;
+    case STATE_KEYWORD:
+      if (*content)
+        repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, content);
+      break;
+    case STATE_DISKUSAGE:
+      if (pd->diskusageq.count)
+        repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
+      break;
+    case STATE_ORDER:
+      if (*content)
+        repodata_set_str(pd->data, handle, SOLVABLE_ORDER, content);
+      break;
+    case STATE_CHANGELOG:
+      repodata_set_str(pd->data, pd->changelog_handle, SOLVABLE_CHANGELOG_TEXT, content);
+      repodata_add_flexarray(pd->data, handle, SOLVABLE_CHANGELOG, pd->changelog_handle);
+      pd->changelog_handle = 0;
+      break;
+    default:
+      break;
+    }
+}
+
+
+/*-----------------------------------------------*/
+
+/*
+ * repo_add_rpmmd
+ * parse rpm-md metadata (primary, others)
+ *
+ */
+
+int
+repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
+{
+  Pool *pool = repo->pool;
+  struct parsedata pd;
+  Repodata *data;
+  unsigned int now;
+
+  now = solv_timems(0);
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = data;
+
+  pd.kind = 0;
+  pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0;
+  queue_init(&pd.diskusageq);
+
+  init_cshash(&pd);
+  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {
+      /* setup join data */
+      pd.cshash_filled = 1;
+      fill_cshash_from_repo(&pd);
+    }
+
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+
+  solv_free(pd.lastdirstr);
+  join_freemem(&pd.jd);
+  free_cshash(&pd);
+  repodata_free_dircache(data);
+  queue_free(&pd.diskusageq);
+
+  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {
+      /* is this a filelist extension? */
+      if (repodata_has_keyname(data, SOLVABLE_FILELIST))
+       repodata_set_filelisttype(data, REPODATA_FILELIST_EXTENSION);
+    }
+  else
+    {
+      /* is this a primary with a filtered filelist? */
+      if (data->end > data->start)
+       {
+         repodata_set_filelisttype(data, REPODATA_FILELIST_FILTERED);
+         repodata_set_void(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST);
+       }
+    }
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmmd took %d ms\n", solv_timems(now));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
+  return pd.ret;
+}
diff --git a/libsolv-0.7.2/ext/repo_rpmmd.h b/libsolv-0.7.2/ext/repo_rpmmd.h
new file mode 100644 (file)
index 0000000..1e88df6
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags);
diff --git a/libsolv-0.7.2/ext/repo_susetags.c b/libsolv-0.7.2/ext/repo_susetags.c
new file mode 100644 (file)
index 0000000..561c789
--- /dev/null
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "hash.h"
+#include "chksum.h"
+#include "tools_util.h"
+#include "repo_susetags.h"
+#ifdef ENABLE_COMPLEX_DEPS
+#include "pool_parserpmrichdep.h"
+#endif
+#include "repodata_diskusage.h"
+
+struct datashare {
+  Id name;
+  Id evr;
+  Id arch;
+};
+
+struct parsedata {
+  int ret;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  char *kind;
+  int flags;
+  int last_found_source;
+  struct datashare *share_with;
+  int nshare;
+  Queue diskusageq;
+  struct joindata jd;
+  char *language;                      /* the default language */
+  Id langcache[ID_NUM_INTERNAL];       /* cache for the default language */
+  int lineno;
+  char *filelist;
+  int afilelist;                       /* allocated */
+  int nfilelist;                       /* used */
+};
+
+static char *flagtab[] = {
+  ">",
+  "=",
+  ">=",
+  "<",
+  "!=",
+  "<="
+};
+
+
+static Id
+langtag(struct parsedata *pd, Id tag, const char *language)
+{
+  if (language && *language)
+    return pool_id2langid(pd->repo->pool, tag, language, 1);
+  if (!pd->language)
+    return tag;
+  if (tag >= ID_NUM_INTERNAL)
+    return pool_id2langid(pd->repo->pool, tag, pd->language, 1);
+  if (!pd->langcache[tag])
+    pd->langcache[tag] = pool_id2langid(pd->repo->pool, tag, pd->language, 1);
+  return pd->langcache[tag];
+}
+
+/*
+ * adddep
+ * create and add dependency
+ */
+
+static unsigned int
+adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker, char *kind)
+{
+  int i, flags;
+  Id id, evrid;
+  char *sp[4];
+
+  if (line[6] == '/')
+    {
+      /* A file dependency. Do not try to parse it */
+      id = pool_str2id(pool, line + 6, 1);
+    }
+#ifdef ENABLE_COMPLEX_DEPS
+  else if (line[6] == '(')
+    {
+      id = pool_parserpmrichdep(pool, line + 6);
+      if (!id)
+       {
+         pd->ret = pool_error(pool, -1, "susetags: line %d: bad dependency: '%s'\n", pd->lineno, line);
+          return olddeps;
+       }
+    }
+#endif
+  else
+    {
+      i = split(line + 6, sp, 4); /* name, <op>, evr, ? */
+      if (i != 1 && i != 3) /* expect either 'name' or 'name' <op> 'evr' */
+        {
+         pd->ret = pool_error(pool, -1, "susetags: line %d: bad dependency: '%s'\n", pd->lineno, line);
+          return olddeps;
+        }
+      if (kind)
+        id = pool_str2id(pool, join2(&pd->jd, kind, ":", sp[0]), 1);
+      else
+        id = pool_str2id(pool, sp[0], 1);
+      if (i == 3)
+        {
+          evrid = makeevr(pool, sp[2]);
+          for (flags = 0; flags < 6; flags++)
+            if (!strcmp(sp[1], flagtab[flags]))
+              break;
+          if (flags == 6)
+            {
+             if (!strcmp(sp[1], "<>"))
+               flags = 4;
+             else
+               {
+                 pd->ret = pool_error(pool, -1, "susetags: line %d: unknown relation: '%s'\n", pd->lineno, sp[1]);
+                 return olddeps;
+               }
+            }
+          id = pool_rel2id(pool, id, evrid, flags + 1, 1);
+        }
+    }
+  return repo_addid_dep(pd->repo, olddeps, id, marker);
+}
+
+
+/*
+ * add_source
+ *
+ */
+
+static void
+add_source(struct parsedata *pd, char *line, Solvable *s, Id handle)
+{
+  Pool *pool = s->repo->pool;
+  char *sp[5];
+  Id name;
+  Id arch;
+  const char *evr, *sevr;
+
+  if (split(line, sp, 5) != 4)
+    {
+      pd->ret = pool_error(pool, -1, "susetags: line %d: bad source line '%s'\n", pd->lineno, line);
+      return;
+    }
+
+  name = pool_str2id(pool, sp[0], 1);
+  arch = pool_str2id(pool, sp[3], 1);  /* do this before id2str */
+  evr = join2(&pd->jd, sp[1], "-", sp[2]);
+  sevr = pool_id2str(pool, s->evr);
+  if (sevr)
+    {
+      /* strip epoch */
+      const char *p;
+      for (p = sevr; *p >= '0' && *p <= '9'; p++)
+       ;
+      if (p != sevr && *p == ':' && p[1])
+       sevr = p;
+    }
+  if (name == s->name)
+    repodata_set_void(pd->data, handle, SOLVABLE_SOURCENAME);
+  else
+    repodata_set_id(pd->data, handle, SOLVABLE_SOURCENAME, name);
+  if (sevr && !strcmp(sevr, evr))
+    repodata_set_void(pd->data, handle, SOLVABLE_SOURCEEVR);
+  else
+    repodata_set_id(pd->data, handle, SOLVABLE_SOURCEEVR, pool_str2id(pool, evr, 1));
+  repodata_set_constantid(pd->data, handle, SOLVABLE_SOURCEARCH, arch);
+}
+
+static void
+set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *line)
+{
+  char *sp[3];
+  Id type;
+  if (split(line, sp, 3) != 2)
+    {
+      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: bad checksum line '%s'\n", pd->lineno, line);
+      return;
+    }
+  type = solv_chksum_str2type(sp[0]);
+  if (!type)
+    {
+      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: unknown checksum type: '%s'\n", pd->lineno, sp[0]);
+      return;
+    }
+  if (strlen(sp[1]) != 2 * solv_chksum_len(type))
+    {
+      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: bad checksum length for type %s: '%s'\n", pd->lineno, sp[0], sp[1]);
+      return;
+    }
+  repodata_set_checksum(data, handle, keyname, type, sp[1]);
+}
+
+
+/* Unfortunately "a"[0] is no constant expression in the C languages,
+   so we need to pass the four characters individually :-/  */
+#define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \
+ | ((unsigned char)b << 16) \
+ | ((unsigned char)c << 8) \
+ | ((unsigned char)d))
+
+/*
+ * tag_from_string
+ *
+ */
+
+static inline unsigned int
+tag_from_string(char *cs)
+{
+  unsigned char *s = (unsigned char *)cs;
+  return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]);
+}
+
+
+/*
+ * repo_add_susetags
+ * Parse susetags file passed in fp, fill solvables into repo
+ *
+ * susetags is key,value based
+ *  for short values
+ *    =key: value
+ *  is used
+ *  for long (multi-line) values,
+ *    +key:
+ *    value
+ *    value
+ *    -key:
+ *  is used
+ *
+ * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata
+ * and http://en.opensuse.org/Standards/YaST2_Repository_Metadata/packages
+ * and http://en.opensuse.org/Standards/YaST2_Repository_Metadata/pattern
+ *
+ * Assumptions:
+ *   All keys have 3 characters and end in ':'
+ */
+
+static void
+finish_solvable(struct parsedata *pd, Solvable *s, Offset freshens)
+{
+  Pool *pool = pd->repo->pool;
+  Id handle = s - pool->solvables;
+
+  if (pd->nfilelist)
+    {
+      int l;
+      Id did;
+      for (l = 0; l < pd->nfilelist; l += strlen(pd->filelist + l) + 1)
+        {
+         char *p = strrchr(pd->filelist + l, '/');
+         if (!p)
+           continue;
+         *p++ = 0;
+         did = repodata_str2dir(pd->data, pd->filelist + l, 1);
+         p[-1] = '/';
+         if (!did)
+           did = repodata_str2dir(pd->data, "/", 1);
+         repodata_add_dirstr(pd->data, handle, SOLVABLE_FILELIST, did, p);
+       }
+      pd->nfilelist = 0;
+    }
+  /* Add self provide, except for source packages.  This is harmless
+     to do twice (in case we see the same package twice).  */
+  if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+    s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+  repo_rewrite_suse_deps(s, freshens);
+  if (pd->diskusageq.count)
+    repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
+}
+
+static Hashtable
+joinhash_init(Repo *repo, Hashval *hmp)
+{
+  Hashval hm = mkmask(repo->nsolvables);
+  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
+  Hashval h, hh;
+  Solvable *s;
+  int i;
+
+  FOR_REPO_SOLVABLES(repo, i, s)
+    {
+      hh = HASHCHAIN_START;
+      h = s->name & hm;
+      while (ht[h])
+        h = HASHCHAIN_NEXT(h, hh, hm);
+      ht[h] = i;
+    }
+  *hmp = hm;
+  return ht;
+}
+
+static Solvable *
+joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, Id name, Id evr, Id arch, Id start)
+{
+  Hashval h, hh;
+
+  if (!name || !arch || !evr)
+    return 0;
+  hh = HASHCHAIN_START;
+  h = name & hm;
+  while (ht[h])
+    {
+      Solvable *s = repo->pool->solvables + ht[h];
+      if (ht[h] >= start && s->name == name && s->evr == evr && s->arch == arch)
+       return s;
+      h = HASHCHAIN_NEXT(h, hh, hm);
+    }
+  return 0;
+}
+
+static Id
+lookup_shared_id(Repodata *data, Id p, Id keyname, Id voidid, int uninternalized)
+{
+  Id r;
+  r = repodata_lookup_type(data, p, keyname);
+  if (r)
+    {
+      if (r == REPOKEY_TYPE_VOID)
+       return voidid;
+      r = repodata_lookup_id(data, p, keyname);
+      if (r)
+       return r;
+    }
+  if (uninternalized)
+    {
+      KeyValue kv;
+      Repokey *key = repodata_lookup_kv_uninternalized(data, p, keyname, &kv);
+      if (!key)
+        return 0;
+      if (key->type == REPOKEY_TYPE_VOID)
+       return voidid;
+      if (key->type == REPOKEY_TYPE_ID)
+       return kv.id;
+    }
+  return 0;
+}
+
+static inline Id
+toevr(Pool *pool, struct parsedata *pd, const char *version, const char *release)
+{
+  return makeevr(pool, !release || (release[0] == '-' && !release[1]) ?
+       version : join2(&pd->jd, version, "-", release));
+}
+
+
+static inline void record_share(struct parsedata *pd, Id handle, Id name, Id evr, Id arch)
+{
+  Repo *repo = pd->repo;
+  int i = handle - repo->start;
+  if (i >= pd->nshare)
+    {
+      pd->share_with = solv_realloc2(pd->share_with, i + 256, sizeof(*pd->share_with));
+      memset(pd->share_with + pd->nshare, 0, (i + 256 - pd->nshare) * sizeof(*pd->share_with));
+      pd->nshare = i + 256;
+    }
+  pd->share_with[i].name = name;
+  pd->share_with[i].evr = evr;
+  pd->share_with[i].arch = arch;
+}
+
+static void process_shares(struct parsedata *pd)
+{
+  Pool *pool = pd->pool;
+  Repo *repo = pd->repo;
+  Repodata *data = pd->data;
+  int i, last_found;
+  Map keyidmap;
+
+  map_init(&keyidmap, data->nkeys);
+  for (i = 1; i < data->nkeys; i++)
+    {
+      Id keyname = data->keys[i].name;
+      if (keyname == SOLVABLE_INSTALLSIZE || keyname == SOLVABLE_DISKUSAGE || keyname == SOLVABLE_FILELIST)
+       continue;
+      if (keyname == SOLVABLE_MEDIADIR || keyname == SOLVABLE_MEDIAFILE || keyname == SOLVABLE_MEDIANR)
+       continue;
+      if (keyname == SOLVABLE_DOWNLOADSIZE || keyname == SOLVABLE_CHECKSUM)
+       continue;
+      if (keyname == SOLVABLE_SOURCENAME || keyname == SOLVABLE_SOURCEARCH || keyname == SOLVABLE_SOURCEEVR)
+       continue;
+      if (keyname == SOLVABLE_PKGID || keyname == SOLVABLE_HDRID || keyname == SOLVABLE_LEADSIGID)
+       continue;
+      if (keyname == SUSETAGS_SHARE_NAME || keyname == SUSETAGS_SHARE_EVR || keyname == SUSETAGS_SHARE_ARCH)
+       continue;
+      MAPSET(&keyidmap, i);
+    }
+  last_found = 0;
+  for (i = 0; i < pd->nshare; i++)
+    {
+      unsigned int n, nn;
+      Solvable *found = 0;
+      if (!pd->share_with[i].name)
+       continue;
+      for (n = repo->start, nn = repo->start + last_found; n < repo->end; n++, nn++)
+       {
+         if (nn >= repo->end)
+           nn = repo->start;
+         found = pool->solvables + nn;
+         if (found->repo == repo
+             && found->name == pd->share_with[i].name
+             && found->evr == pd->share_with[i].evr
+             && found->arch == pd->share_with[i].arch)
+           {
+             last_found = nn - repo->start;
+             break;
+           }
+       }
+      if (n != repo->end)
+       repodata_merge_some_attrs(data, repo->start + i, repo->start + last_found, &keyidmap, 0);
+    }
+  pd->share_with = solv_free(pd->share_with);
+  pd->nshare = 0;
+  map_free(&keyidmap);
+}
+
+
+/*
+ * parse susetags
+ *
+ * fp: file to read from
+ * defvendor: default vendor (0 if none)
+ * language: current language (0 if none)
+ * flags: flags
+ */
+
+int
+repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int flags)
+{
+  Pool *pool = repo->pool;
+  char *line, *linep;
+  int aline;
+  Solvable *s;
+  Offset freshens;
+  int intag = 0;
+  int intag_linestart = 0;
+  int cummulate = 0;
+  int notfound = 0;
+  int indelta = 0;
+  int last_found_pack = 0;
+  Id first_new_pkg = 0;
+  char *sp[6];
+  struct parsedata pd;
+  Repodata *data = 0;
+  Id handle = 0;
+  Hashtable joinhash = 0;
+  Hashval joinhashm = 0;
+  int createdpkgs = 0;
+
+  if ((flags & (SUSETAGS_EXTEND|REPO_EXTEND_SOLVABLES)) != 0 && repo->nrepodata)
+    {
+      joinhash = joinhash_init(repo, &joinhashm);
+    }
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  line = solv_malloc(1024);
+  aline = 1024;
+
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = data;
+  pd.flags = flags;
+  pd.language = language && *language ? solv_strdup(language) : 0;
+  queue_init(&pd.diskusageq);
+
+  linep = line;
+  s = 0;
+  freshens = 0;
+
+  /* if this is a join setup the recorded share data */
+  if (joinhash)
+    {
+      Repodata *sdata;
+      int i;
+
+      FOR_REPODATAS(repo, i, sdata)
+       {
+         int p;
+         if (!repodata_has_keyname(sdata, SUSETAGS_SHARE_NAME))
+           continue;
+         for (p = sdata->start; p < sdata->end; p++)
+           {
+             Id name, evr, arch;
+             name = lookup_shared_id(sdata, p, SUSETAGS_SHARE_NAME, pool->solvables[p].name, sdata == data);
+             if (!name)
+               continue;
+             evr = lookup_shared_id(sdata, p, SUSETAGS_SHARE_EVR, pool->solvables[p].evr, sdata == data);
+             if (!evr)
+               continue;
+             arch = lookup_shared_id(sdata, p, SUSETAGS_SHARE_ARCH, pool->solvables[p].arch, sdata == data);
+             if (!arch)
+               continue;
+             record_share(&pd, p, name, evr, arch);
+           }
+       }
+    }
+
+  /*
+   * read complete file
+   *
+   * collect values in 'struct parsedata pd'
+   * then build .solv (and .attr) file
+   */
+
+  for (;;)
+    {
+      unsigned int tag;
+      char line_lang[6];
+      int keylen;
+
+      if (pd.ret)
+       break;
+      if (linep - line + 16 > aline)              /* (re-)alloc buffer */
+       {
+         aline = linep - line;
+         line = solv_realloc(line, aline + 512);
+         linep = line + aline;
+         aline += 512;
+       }
+      if (!fgets(linep, aline - (linep - line), fp)) /* read line */
+       break;
+      linep += strlen(linep);
+      if (linep == line || linep[-1] != '\n')
+        continue;
+      pd.lineno++;
+      *--linep = 0;
+
+      if (intag)
+       {
+         /* in multi-line value tags (+Key:/-Key:), check for end, cummulate */
+         int is_end = line[intag_linestart] == '-' && linep[-1] == ':' && linep - line == intag_linestart + intag + 2;
+         if (is_end && strncmp(linep - 1 - intag, line + 1, intag))
+           {
+             pool_debug(pool, SOLV_ERROR, "susetags: Nonmatching multi-line tags: %d: '%s' '%.*s'\n", pd.lineno, linep - 1 - intag, intag, line + 1);
+           }
+         if (!is_end)
+           {
+             if (cummulate)
+               {
+                 *linep++ = '\n';
+                 intag_linestart = linep - line;
+                 continue;
+               }
+             intag_linestart = intag + 3;
+             linep = line + intag_linestart;
+             if (!*linep)
+               continue;               /* ignore empty lines, bnc#381828 */
+           }
+         else
+           {
+             intag = 0;
+             linep = line;
+             if (!cummulate)
+               continue;
+             line[intag_linestart] = 0;
+             if (line[intag_linestart - 1] == '\n')
+               line[intag_linestart - 1] = 0;          /* strip trailing newline */
+           }
+       }
+      else
+       linep = line;
+
+      /* ignore comments and empty lines */
+      if (!*line || *line == '#')
+       continue;
+
+      /* ignore malformed lines */
+      if (!(line[0] && line[1] && line[2] && line[3] && (line[4] == ':' || line[4] == '.')))
+        continue;
+
+      if (!intag && line[0] == '+' && line[1] != ':') /* start of +Key:/-Key: tag */
+       {
+         char *tagend = strchr(line, ':');
+         if (!tagend || tagend - line > 100)
+           {
+             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
+             break;
+           }
+         intag = tagend - (line + 1);          /* set to tagsize */
+         cummulate = 0;
+         switch (tag_from_string(line))        /* check if accumulation is needed */
+           {
+             case CTAG('+', 'D', 'e', 's'):
+             case CTAG('+', 'E', 'u', 'l'):
+             case CTAG('+', 'I', 'n', 's'):
+             case CTAG('+', 'D', 'e', 'l'):
+             case CTAG('+', 'A', 'u', 't'):
+               cummulate = 1;
+               break;
+             default:
+               break;
+           }
+         line[0] = '=';                        /* handle lines between +Key:/-Key: as =Key: */
+         line[intag + 2] = ' ';
+         intag_linestart = intag + 3;
+         linep = line + intag_linestart;
+         continue;
+       }
+
+      /* support language suffix */
+      keylen = 3;
+      line_lang[0] = 0;
+      if (line[4] == '.')
+        {
+          char *endlang;
+          endlang = strchr(line + 5, ':');
+          if (endlang)
+            {
+             int langsize = endlang - (line + 5);
+              keylen = endlang - line - 1;
+             if (langsize > 5)
+               langsize = 5;
+              strncpy(line_lang, line + 5, langsize);
+              line_lang[langsize] = 0;
+            }
+        }
+
+      tag = tag_from_string(line);
+
+      /* handle global tags and tags that start a new section */
+      switch (tag)
+        {
+        case CTAG('=', 'V', 'e', 'r'):
+         /* start of a new file */
+         if (s)
+           finish_solvable(&pd, s, freshens);
+         s = 0;
+         handle = 0;
+         freshens = 0;
+         indelta = 0;
+         notfound = 0;
+         last_found_pack = 0;
+         if (createdpkgs)
+           {
+             solv_free(joinhash);
+             joinhash = joinhash_init(repo, &joinhashm);
+             createdpkgs = 0;
+           }
+         continue;
+
+        case CTAG('=', 'L', 'a', 'n'):
+         /* define language of the following material */
+         pd.language = solv_free(pd.language);
+         memset(pd.langcache, 0, sizeof(pd.langcache));
+         if (line[6])
+           pd.language = solv_strdup(line + 6);
+         continue;
+
+       case CTAG('=', 'P', 'k', 'g'):          /* start of a package */
+       case CTAG('=', 'P', 'a', 't'):          /* start of a pattern */
+       case CTAG('=', 'D', 'l', 't'):          /* start of a delta */
+         /* =Pkg: <name> <version> <release> <architecture> */
+         /* If we have an old solvable, complete it by filling in some default stuff.  */
+         if (s)
+           finish_solvable(&pd, s, freshens);
+         s = 0;
+         handle = 0;
+         freshens = 0;
+         indelta = 0;
+         notfound = 0;
+
+         /* define kind */
+         pd.kind = 0;
+         if (tag == CTAG('=', 'P', 'a', 't'))
+           pd.kind = "pattern";
+
+         /* parse nevra */
+          if (split(line + 5, sp, 5) != 4)
+           {
+             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
+             break;
+           }
+
+         if (tag == CTAG('=', 'D', 'l', 't'))
+           {
+             /* start new delta */
+             handle = repodata_new_handle(data);
+             repodata_set_id(data, handle, DELTA_PACKAGE_NAME, pool_str2id(pool, sp[0], 1));
+             repodata_set_id(data, handle, DELTA_PACKAGE_EVR, toevr(pool, &pd, sp[1], sp[2]));
+             repodata_set_id(data, handle, DELTA_PACKAGE_ARCH, pool_str2id(pool, sp[3], 1));
+             repodata_add_flexarray(data, SOLVID_META, REPOSITORY_DELTAINFO, handle);
+             indelta = 1;
+             continue;
+           }
+
+         if (joinhash)
+           {
+             /* data join operation. find solvable matching name/arch/evr and
+               * add data to it */
+             Id name, arch;
+             /* we don't use the create flag here as a simple pre-check for existance */
+             if (pd.kind)
+               name = pool_str2id(pool, join2(&pd.jd, pd.kind, ":", sp[0]), 0);
+             else
+               name = pool_str2id(pool, sp[0], 0);
+             arch = pool_str2id(pool, sp[3], 0);
+             if (name && arch)
+               {
+                 Id start = (flags & REPO_EXTEND_SOLVABLES) ? 0 : first_new_pkg;
+                 Id evr = toevr(pool, &pd, sp[1], sp[2]);
+                 if (repo->start + last_found_pack + 1 >= start && repo->start + last_found_pack + 1 < repo->end)
+                   {
+                     s = pool->solvables + repo->start + last_found_pack + 1;
+                     if (s->repo != repo || s->name != name || s->evr != evr || s->arch != arch)
+                       s = 0;
+                   }
+                 if (!s)
+                   s = joinhash_lookup(repo, joinhash, joinhashm, name, evr, arch, start);
+               }
+             /* do not create new packages in EXTEND_SOLVABLES mode */
+             if (!s && (flags & REPO_EXTEND_SOLVABLES) != 0)
+               {
+                 notfound = 1;
+                 continue;
+               }
+             /* fallthrough to package creation */
+           }
+         if (!s)
+           {
+             /* normal operation. create a new solvable. */
+             s = pool_id2solvable(pool, repo_add_solvable(repo));
+             if (pd.kind)
+               s->name = pool_str2id(pool, join2(&pd.jd, pd.kind, ":", sp[0]), 1);
+             else
+               s->name = pool_str2id(pool, sp[0], 1);
+             s->evr = toevr(pool, &pd, sp[1], sp[2]);
+             s->arch = pool_str2id(pool, sp[3], 1);
+             s->vendor = defvendor;
+             if (!first_new_pkg)
+               first_new_pkg = s - pool->solvables;
+             createdpkgs = 1;
+           }
+         handle = s - pool->solvables;
+         last_found_pack = (s - pool->solvables) - repo->start;
+         continue;
+
+       default:
+         break;
+       }
+
+      /* handle delta tags */
+      if (indelta)
+       {
+         /* Example:
+           =Dlt: subversion 1.6.16 1.3.1 i586
+           =Dsq: subversion 1.6.15 4.2 i586 d57b3fc86e7a2f73796e8e35b96fa86212c910
+           =Cks: SHA1 14a8410cf741856a5d70d89dab62984dba6a1ca7
+           =Loc: 1 subversion-1.6.15_1.6.16-4.2_1.3.1.i586.delta.rpm
+           =Siz: 81558
+          */
+         switch (tag)
+           {
+           case CTAG('=', 'D', 's', 'q'):
+             {
+               Id evr;
+               if (split(line + 5, sp, 5) != 5)
+                 continue;
+               repodata_set_id(data, handle, DELTA_SEQ_NAME, pool_str2id(pool, sp[0], 1));
+               evr = toevr(pool, &pd, sp[1], sp[2]);
+               repodata_set_id(data, handle, DELTA_SEQ_EVR, evr);
+               /* repodata_set_id(data, handle, DELTA_SEQ_ARCH, pool_str2id(pool, sp[3], 1)); */
+               repodata_set_str(data, handle, DELTA_SEQ_NUM, sp[4]);
+               repodata_set_id(data, handle, DELTA_BASE_EVR, evr);
+               continue;
+             }
+           case CTAG('=', 'C', 'k', 's'):
+             set_checksum(&pd, data, handle, DELTA_CHECKSUM, line + 6);
+             continue;
+           case CTAG('=', 'L', 'o', 'c'):
+             {
+               int i = split(line + 6, sp, 3);
+               if (i != 2 && i != 3)
+                 {
+                   pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line);
+                   continue;
+                 }
+               repodata_set_deltalocation(data, handle, atoi(sp[0]), i == 3 ? sp[2] : 0, sp[1]);
+               continue;
+             }
+           case CTAG('=', 'S', 'i', 'z'):
+             if (split(line + 6, sp, 3) == 2)
+               repodata_set_num(data, handle, DELTA_DOWNLOADSIZE, strtoull(sp[0], 0, 10));
+             continue;
+           default:
+             pool_debug(pool, SOLV_WARN, "susetags: unknown line: %d: %s\n", pd.lineno, line);
+             continue;
+           }
+       }
+
+      /* we need a solvable for all other tags */
+      if (!s)
+       {
+         if (notfound)
+           continue;           /* did not find the solvable to extend */
+#if 0
+         pool_debug(pool, SOLV_WARN, "susetags: stray line: %d: %s\n", pd.lineno, line);
+#endif
+          continue;
+       }
+
+      switch (tag)
+        {
+         case CTAG('=', 'P', 'r', 'v'):                                        /* provides */
+           if (line[6] == '/')
+             {
+               /* probably a filelist entry. stash it away for now */
+               int l = strlen(line + 6) + 1;
+               if (pd.nfilelist + l > pd.afilelist)
+                 {
+                   pd.afilelist = pd.nfilelist + l + 512;
+                   pd.filelist = solv_realloc(pd.filelist, pd.afilelist);
+                 }
+               memcpy(pd.filelist + pd.nfilelist, line + 6, l);
+               pd.nfilelist += l;
+               break;
+             }
+           if (pd.nfilelist)
+             {
+               int l;
+               for (l = 0; l < pd.nfilelist; l += strlen(pd.filelist + l) + 1)
+                 s->provides = repo_addid_dep(pd.repo, s->provides, pool_str2id(pool, pd.filelist + l, 1), 0);
+               pd.nfilelist = 0;
+             }
+           s->provides = adddep(pool, &pd, s->provides, line, 0, pd.kind);
+           continue;
+         case CTAG('=', 'R', 'e', 'q'):                                        /* requires */
+           s->requires = adddep(pool, &pd, s->requires, line, -SOLVABLE_PREREQMARKER, pd.kind);
+           continue;
+          case CTAG('=', 'P', 'r', 'q'):                                        /* pre-requires / packages required */
+           if (pd.kind)
+             s->requires = adddep(pool, &pd, s->requires, line, 0, 0);         /* pattern: package requires */
+           else
+             s->requires = adddep(pool, &pd, s->requires, line, SOLVABLE_PREREQMARKER, 0); /* pre-requires */
+           continue;
+         case CTAG('=', 'O', 'b', 's'):                                        /* obsoletes */
+           s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'C', 'o', 'n'):                                        /* conflicts */
+           s->conflicts = adddep(pool, &pd, s->conflicts, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'R', 'e', 'c'):                                        /* recommends */
+           s->recommends = adddep(pool, &pd, s->recommends, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'S', 'u', 'p'):                                        /* supplements */
+           s->supplements = adddep(pool, &pd, s->supplements, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'E', 'n', 'h'):                                        /* enhances */
+           s->enhances = adddep(pool, &pd, s->enhances, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'S', 'u', 'g'):                                        /* suggests */
+           s->suggests = adddep(pool, &pd, s->suggests, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'F', 'r', 'e'):                                        /* freshens */
+           freshens = adddep(pool, &pd, freshens, line, 0, pd.kind);
+           continue;
+          case CTAG('=', 'P', 'r', 'c'):                                        /* packages recommended */
+           s->recommends = adddep(pool, &pd, s->recommends, line, 0, 0);
+           continue;
+          case CTAG('=', 'P', 's', 'g'):                                        /* packages suggested */
+           s->suggests = adddep(pool, &pd, s->suggests, line, 0, 0);
+           continue;
+          case CTAG('=', 'P', 'c', 'n'):                                        /* pattern: package conflicts */
+           s->conflicts = adddep(pool, &pd, s->conflicts, line, 0, 0);
+           continue;
+         case CTAG('=', 'P', 'o', 'b'):                                        /* pattern: package obsoletes */
+           s->obsoletes = adddep(pool, &pd, s->obsoletes, line, 0, 0);
+           continue;
+          case CTAG('=', 'P', 'f', 'r'):                                        /* pattern: package freshens */
+           freshens = adddep(pool, &pd, freshens, line, 0, 0);
+           continue;
+          case CTAG('=', 'P', 's', 'p'):                                        /* pattern: package supplements */
+           s->supplements = adddep(pool, &pd, s->supplements, line, 0, 0);
+           continue;
+          case CTAG('=', 'P', 'e', 'n'):                                        /* pattern: package enhances */
+           s->enhances = adddep(pool, &pd, s->enhances, line, 0, 0);
+           continue;
+          case CTAG('=', 'V', 'n', 'd'):                                        /* vendor */
+            s->vendor = pool_str2id(pool, line + 6, 1);
+            continue;
+
+        /* From here it's the attribute tags.  */
+          case CTAG('=', 'G', 'r', 'p'):
+           repodata_set_poolstr(data, handle, SOLVABLE_GROUP, line + 6);
+           continue;
+          case CTAG('=', 'L', 'i', 'c'):
+           repodata_set_poolstr(data, handle, SOLVABLE_LICENSE, line + 6);
+           continue;
+          case CTAG('=', 'L', 'o', 'c'):
+           {
+             int i = split(line + 6, sp, 3);
+             if (i != 2 && i != 3)
+               {
+                 pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line);
+                 continue;
+               }
+             repodata_set_location(data, handle, atoi(sp[0]), i == 3 ? sp[2] : pool_id2str(pool, s->arch), sp[1]);
+           }
+           continue;
+          case CTAG('=', 'S', 'r', 'c'):
+           add_source(&pd, line + 6, s, handle);
+           continue;
+          case CTAG('=', 'S', 'i', 'z'):
+           if (split(line + 6, sp, 3) == 2)
+             {
+               repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(sp[0], 0, 10));
+               repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, strtoull(sp[1], 0, 10));
+             }
+           continue;
+          case CTAG('=', 'T', 'i', 'm'):
+           {
+             unsigned int t = atoi(line + 6);
+             if (t)
+               repodata_set_num(data, handle, SOLVABLE_BUILDTIME, t);
+           }
+           continue;
+          case CTAG('=', 'K', 'w', 'd'):
+           repodata_add_poolstr_array(data, handle, SOLVABLE_KEYWORDS, line + 6);
+           continue;
+          case CTAG('=', 'A', 'u', 't'):
+           repodata_set_str(data, handle, SOLVABLE_AUTHORS, line + 6);
+           continue;
+          case CTAG('=', 'S', 'u', 'm'):
+            repodata_set_str(data, handle, langtag(&pd, SOLVABLE_SUMMARY, line_lang), line + 3 + keylen);
+            continue;
+          case CTAG('=', 'D', 'e', 's'):
+           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_DESCRIPTION, line_lang), line + 3 + keylen);
+           continue;
+          case CTAG('=', 'E', 'u', 'l'):
+           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_EULA, line_lang), line + 6);
+           continue;
+          case CTAG('=', 'I', 'n', 's'):
+           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_MESSAGEINS, line_lang), line + 6);
+           continue;
+          case CTAG('=', 'D', 'e', 'l'):
+           repodata_set_str(data, handle, langtag(&pd, SOLVABLE_MESSAGEDEL, line_lang), line + 6);
+           continue;
+          case CTAG('=', 'V', 'i', 's'):
+           {
+             /* Accept numbers and textual bools.  */
+             int k;
+             k = atoi(line + 6);
+             if (k || !strcasecmp(line + 6, "true"))
+               repodata_set_void(data, handle, SOLVABLE_ISVISIBLE);
+             continue;
+           }
+          case CTAG('=', 'S', 'h', 'r'):
+           {
+             Id name, evr, arch;
+             if (split(line + 6, sp, 5) != 4)
+               {
+                 pd.ret = pool_error(pool, -1, "susetags: line %d: bad =Shr line '%s'\n", pd.lineno, line);
+                 continue;
+               }
+             name = pool_str2id(pool, sp[0], 1);
+             evr = toevr(pool, &pd, sp[1], sp[2]);
+             arch = pool_str2id(pool, sp[3], 1);
+             record_share(&pd, handle, name, evr, arch);
+             if ((flags & SUSETAGS_RECORD_SHARES) != 0)
+               {
+                 if (s->name == name)
+                   repodata_set_void(data, handle, SUSETAGS_SHARE_NAME);
+                 else
+                   repodata_set_id(data, handle, SUSETAGS_SHARE_NAME, name);
+                 if (s->evr == evr)
+                   repodata_set_void(data, handle, SUSETAGS_SHARE_EVR);
+                 else
+                   repodata_set_id(data, handle, SUSETAGS_SHARE_EVR, evr);
+                 if (s->arch == arch)
+                   repodata_set_void(data, handle, SUSETAGS_SHARE_ARCH);
+                 else
+                   repodata_set_id(data, handle, SUSETAGS_SHARE_ARCH, arch);
+               }
+             continue;
+           }
+         case CTAG('=', 'D', 'i', 'r'):
+           if (split(line + 6, sp, 6) == 5)
+             {
+               long filesz, filenum;
+               Id did;
+
+               filesz = strtol(sp[1], 0, 0);
+               filesz += strtol(sp[2], 0, 0);
+               filenum = strtol(sp[3], 0, 0);
+               filenum += strtol(sp[4], 0, 0);
+               if (*sp[0] != '/')
+                 *--sp[0] = '/';       /* hack: we know that there's room for a / */
+               did = repodata_str2dir(data, sp[0], 1);
+               queue_push(&pd.diskusageq, did);
+               queue_push2(&pd.diskusageq, (Id)filesz, (Id)filenum);
+             }
+           break;
+         case CTAG('=', 'C', 'a', 't'):
+           repodata_set_poolstr(data, handle, langtag(&pd, SOLVABLE_CATEGORY, line_lang), line + 3 + keylen);
+           break;
+         case CTAG('=', 'O', 'r', 'd'):
+           /* Order is a string not a number, so we can retroactively insert
+              new patterns in the middle, i.e. 1 < 15 < 2.  */
+           repodata_set_str(data, handle, SOLVABLE_ORDER, line + 6);
+           break;
+         case CTAG('=', 'I', 'c', 'o'):
+           repodata_set_str(data, handle, SOLVABLE_ICON, line + 6);
+           break;
+         case CTAG('=', 'E', 'x', 't'):
+           repodata_add_poolstr_array(data, handle, SOLVABLE_EXTENDS, join2(&pd.jd, "pattern", ":", line + 6));
+           break;
+         case CTAG('=', 'I', 'n', 'c'):
+           repodata_add_poolstr_array(data, handle, SOLVABLE_INCLUDES, join2(&pd.jd, "pattern", ":", line + 6));
+           break;
+         case CTAG('=', 'C', 'k', 's'):
+           set_checksum(&pd, data, handle, SOLVABLE_CHECKSUM, line + 6);
+           break;
+
+         case CTAG('=', 'F', 'l', 's'):
+           {
+             char *p, *file = line + 6;
+             Id did;
+
+             if (*file != '/')
+               *--file = '/';          /* hack: we know there is room */
+             p  = strrchr(file, '/');
+             /* strip trailing slashes */
+             while (p != file && !p[1])
+               {
+                 *p = 0;
+                 p = strrchr(file, '/');
+               }
+             *p++ = 0;
+             did = repodata_str2dir(data, *file ? file : "/", 1);
+             repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, p);
+             line[5] = ' ';
+             break;
+           }
+         case CTAG('=', 'H', 'd', 'r'):
+           /* rpm header range */
+           if (split(line + 6, sp, 3) == 2)
+             {
+               /* we ignore the start value */
+               unsigned int end = (unsigned int)atoi(sp[1]);
+               if (end)
+                 repodata_set_num(data, handle, SOLVABLE_HEADEREND, end);
+             }
+           break;
+
+         default:
+#if 0
+           pool_debug(pool, SOLV_WARN, "susetags: unknown line: %d: %s\n", pd.lineno, line);
+#endif
+           break;
+       }
+    }
+
+  if (s)
+    finish_solvable(&pd, s, freshens);
+  solv_free(pd.filelist);
+
+  /* process shared attributes (e.g. multiple binaries built from same source) */
+  if (pd.nshare)
+    process_shares(&pd);
+
+  solv_free(joinhash);
+  repodata_free_dircache(data);
+
+    if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {    
+      /* is this a filelist extension? */
+      if (repodata_has_keyname(data, SOLVABLE_FILELIST))
+        repodata_set_filelisttype(data, REPODATA_FILELIST_EXTENSION);
+    }    
+  else 
+    {    
+      /* is this a primary with a filtered filelist? */
+      if (data->end > data->start)
+       {
+          repodata_set_filelisttype(data, REPODATA_FILELIST_FILTERED);
+         repodata_set_void(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST);
+       }
+    }  
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+
+  solv_free(pd.language);
+  solv_free(line);
+  join_freemem(&pd.jd);
+  queue_free(&pd.diskusageq);
+  return pd.ret;
+}
diff --git a/libsolv-0.7.2/ext/repo_susetags.h b/libsolv-0.7.2/ext/repo_susetags.h
new file mode 100644 (file)
index 0000000..de110c3
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* read susetags file <fp> into <repo>
+ * if <attrname> given, write attributes as '<attrname>.attr'
+ */
+
+#define SUSETAGS_EXTEND                        (1 << 9)
+#define SUSETAGS_RECORD_SHARES         (1 << 10)
+
+extern int repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int flags);
diff --git a/libsolv-0.7.2/ext/repo_updateinfoxml.c b/libsolv-0.7.2/ext/repo_updateinfoxml.c
new file mode 100644 (file)
index 0000000..ff84d32
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE /* glibc2 needs this */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "solv_xmlparser.h"
+#include "repo_updateinfoxml.h"
+#define DISABLE_SPLIT
+#include "tools_util.h"
+
+/*
+ * <updates>
+ *   <update from="rel-eng@fedoraproject.org" status="stable" type="security" version="1.4">
+ *     <id>FEDORA-2007-4594</id>
+ *     <title>imlib-1.9.15-6.fc8</title>
+ *     <severity>Important</severity>
+ *     <release>Fedora 8</release>
+ *     <rights>Copyright 2007 Company Inc</rights>
+ *     <issued date="2007-12-28 16:42:30"/>
+ *     <updated date="2008-03-14 12:00:00"/>
+ *     <references>
+ *       <reference href="https://bugzilla.redhat.com/show_bug.cgi?id=426091" id="426091" title="CVE-2007-3568 imlib: infinite loop DoS using crafted BMP image" type="bugzilla"/>
+ *     </references>
+ *     <description>This update includes a fix for a denial-of-service issue (CVE-2007-3568) whereby an attacker who could get an imlib-using user to view a  specially-crafted BMP image could cause the user's CPU to go into an infinite loop.</description>
+ *     <pkglist>
+ *       <collection short="F8">
+ *         <name>Fedora 8</name>
+ *         <package arch="ppc64" name="imlib-debuginfo" release="6.fc8" src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm" version="1.9.15">
+ *           <filename>imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm</filename>
+ *           <reboot_suggested>True</reboot_suggested>
+ *         </package>
+ *       </collection>
+ *     </pkglist>
+ *   </update>
+ * </updates>
+*/
+
+enum state {
+  STATE_START,
+  STATE_UPDATES,
+  STATE_UPDATE,
+  STATE_ID,
+  STATE_TITLE,
+  STATE_RELEASE,
+  STATE_ISSUED,
+  STATE_UPDATED,
+  STATE_MESSAGE,
+  STATE_REFERENCES,
+  STATE_REFERENCE,
+  STATE_DESCRIPTION,
+  STATE_PKGLIST,
+  STATE_COLLECTION,
+  STATE_NAME,
+  STATE_PACKAGE,
+  STATE_FILENAME,
+  STATE_REBOOT,
+  STATE_RESTART,
+  STATE_RELOGIN,
+  STATE_RIGHTS,
+  STATE_SEVERITY,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START,       "updates",         STATE_UPDATES,     0 },
+  { STATE_START,       "update",          STATE_UPDATE,      0 },
+  { STATE_UPDATES,     "update",          STATE_UPDATE,      0 },
+  { STATE_UPDATE,      "id",              STATE_ID,          1 },
+  { STATE_UPDATE,      "title",           STATE_TITLE,       1 },
+  { STATE_UPDATE,      "severity",        STATE_SEVERITY,    1 },
+  { STATE_UPDATE,      "rights",          STATE_RIGHTS,      1 },
+  { STATE_UPDATE,      "release",         STATE_RELEASE,     1 },
+  { STATE_UPDATE,      "issued",          STATE_ISSUED,      0 },
+  { STATE_UPDATE,      "updated",         STATE_UPDATED,     0 },
+  { STATE_UPDATE,      "description",     STATE_DESCRIPTION, 1 },
+  { STATE_UPDATE,      "message",         STATE_MESSAGE    , 1 },
+  { STATE_UPDATE,      "references",      STATE_REFERENCES,  0 },
+  { STATE_UPDATE,      "pkglist",         STATE_PKGLIST,     0 },
+  { STATE_REFERENCES,  "reference",       STATE_REFERENCE,   0 },
+  { STATE_PKGLIST,     "collection",      STATE_COLLECTION,  0 },
+  { STATE_COLLECTION,  "name",            STATE_NAME,        1 },
+  { STATE_COLLECTION,  "package",         STATE_PACKAGE,     0 },
+  { STATE_PACKAGE,     "filename",        STATE_FILENAME,    1 },
+  { STATE_PACKAGE,     "reboot_suggested",STATE_REBOOT,      1 },
+  { STATE_PACKAGE,     "restart_suggested",STATE_RESTART,    1 },
+  { STATE_PACKAGE,     "relogin_suggested",STATE_RELOGIN,    1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  int ret;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  Id handle;
+  Solvable *solvable;
+  time_t buildtime;
+  Id collhandle;
+  struct solv_xmlparser xmlp;
+  struct joindata jd;
+};
+
+/*
+ * Convert date strings ("1287746075" or "2010-10-22 13:14:35")
+ * to timestamp.
+ */
+static time_t
+datestr2timestamp(const char *date)
+{
+  const char *p;
+  struct tm tm;
+
+  if (!date || !*date)
+    return 0;
+  for (p = date; *p >= '0' && *p <= '9'; p++)
+    ;
+  if (!*p)
+    return atoi(date);
+  memset(&tm, 0, sizeof(tm));
+  if (!strptime(date, "%F%T", &tm))
+    return 0;
+  return timegm(&tm);
+}
+
+/*
+ * create evr (as Id) from 'epoch', 'version' and 'release' attributes
+ */
+static Id
+makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
+{
+  const char *e, *v, *r, *v2;
+  char *c, *space;
+  int l;
+
+  e = v = r = 0;
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, "epoch"))
+       e = atts[1];
+      else if (!strcmp(*atts, "version"))
+       v = atts[1];
+      else if (!strcmp(*atts, "release"))
+       r = atts[1];
+    }
+  if (e && (!*e || !strcmp(e, "0")))
+    e = 0;
+  if (v && !e)
+    {
+      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
+        ;
+      if (v2 > v && *v2 == ':')
+       e = "0";
+    }
+  l = 1;
+  if (e)
+    l += strlen(e) + 1;
+  if (v)
+    l += strlen(v);
+  if (r)
+    l += strlen(r) + 1;
+  
+  c = space = solv_xmlparser_contentspace(&pd->xmlp, l);
+  if (e)
+    {
+      strcpy(c, e);
+      c += strlen(c);
+      *c++ = ':';
+    }
+  if (v)
+    {
+      strcpy(c, v);
+      c += strlen(c);
+    }
+  if (r)
+    {
+      *c++ = '-';
+      strcpy(c, r);
+      c += strlen(c);
+    }
+  *c = 0;
+  if (!*space)
+    return 0;
+#if 0
+  fprintf(stderr, "evr: %s\n", space);
+#endif
+  return pool_str2id(pool, space, 1);
+}
+
+
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *solvable = pd->solvable;
+
+  switch(state)
+    {
+      /*
+       * <update from="rel-eng@fedoraproject.org"
+       *         status="stable"
+       *         type="bugfix" (enhancement, security)
+       *         version="1.4">
+       */
+    case STATE_UPDATE:
+      {
+       const char *from = 0, *type = 0, *version = 0;
+       for (; *atts; atts += 2)
+         {
+           if (!strcmp(*atts, "from"))
+             from = atts[1];
+           else if (!strcmp(*atts, "type"))
+             type = atts[1];
+           else if (!strcmp(*atts, "version"))
+             version = atts[1];
+         }
+       solvable = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+       pd->handle = pd->solvable - pool->solvables;
+
+       solvable->vendor = pool_str2id(pool, from, 1);
+       solvable->evr = pool_str2id(pool, version, 1);
+       solvable->arch = ARCH_NOARCH;
+       if (type)
+         repodata_set_str(pd->data, pd->handle, SOLVABLE_PATCHCATEGORY, type);
+        pd->buildtime = (time_t)0;
+      }
+      break;
+
+    case STATE_ISSUED:
+    case STATE_UPDATED:
+      {
+       const char *date = solv_xmlparser_find_attr("date", atts);
+       if (date)
+         {
+           time_t t = datestr2timestamp(date);
+           if (t && t > pd->buildtime)
+              pd->buildtime = t;
+         }
+      }
+      break;
+
+    case STATE_REFERENCE:
+      {
+        const char *href = 0, *id = 0, *title = 0, *type = 0;
+       Id refhandle;
+       for (; *atts; atts += 2)
+         {
+           if (!strcmp(*atts, "href"))
+             href = atts[1];
+           else if (!strcmp(*atts, "id"))
+             id = atts[1];
+           else if (!strcmp(*atts, "title"))
+             title = atts[1];
+           else if (!strcmp(*atts, "type"))
+             type = atts[1];
+         }
+       refhandle = repodata_new_handle(pd->data);
+       if (href)
+         repodata_set_str(pd->data, refhandle, UPDATE_REFERENCE_HREF, href);
+       if (id)
+         repodata_set_str(pd->data, refhandle, UPDATE_REFERENCE_ID, id);
+       if (title)
+         repodata_set_str(pd->data, refhandle, UPDATE_REFERENCE_TITLE, title);
+       if (type)
+         repodata_set_poolstr(pd->data, refhandle, UPDATE_REFERENCE_TYPE, type);
+       repodata_add_flexarray(pd->data, pd->handle, UPDATE_REFERENCE, refhandle);
+      }
+      break;
+
+      /*   <package arch="ppc64" name="imlib-debuginfo" release="6.fc8"
+       *            src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm"
+       *            version="1.9.15">
+       *
+       *
+       * -> patch.conflicts: {name} < {version}.{release}
+       */
+    case STATE_PACKAGE:
+      {
+       const char *arch = 0, *name = 0;
+       Id evr = makeevr_atts(pool, pd, atts); /* parse "epoch", "version", "release" */
+       Id n, a = 0;
+       Id rel_id;
+
+       for (; *atts; atts += 2)
+         {
+           if (!strcmp(*atts, "arch"))
+             arch = atts[1];
+           else if (!strcmp(*atts, "name"))
+             name = atts[1];
+         }
+       /* generated Id for name */
+       n = pool_str2id(pool, name, 1);
+       rel_id = n;
+       if (arch)
+         {
+           /*  generate Id for arch and combine with name */
+           a = pool_str2id(pool, arch, 1);
+           rel_id = pool_rel2id(pool, n, a, REL_ARCH, 1);
+         }
+       rel_id = pool_rel2id(pool, rel_id, evr, REL_LT, 1);
+       solvable->conflicts = repo_addid_dep(pd->repo, solvable->conflicts, rel_id, 0);
+
+        /* who needs the collection anyway? */
+        pd->collhandle = repodata_new_handle(pd->data);
+       repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_NAME, n);
+       repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_EVR, evr);
+       if (a)
+         repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
+        break;
+      }
+
+    default:
+      break;
+    }
+  return;
+}
+
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+  Repo *repo = pd->repo;
+
+  switch (state)
+    {
+    case STATE_UPDATE:
+      s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      if (pd->buildtime)
+       {
+         repodata_set_num(pd->data, pd->handle, SOLVABLE_BUILDTIME, pd->buildtime);
+         pd->buildtime = (time_t)0;
+       }
+      break;
+
+    case STATE_ID:
+      s->name = pool_str2id(pool, join2(&pd->jd, "patch", ":", content), 1);
+      break;
+
+      /* <title>imlib-1.9.15-6.fc8</title> */
+    case STATE_TITLE:
+      /* strip trailing newlines */
+      while (pd->xmlp.lcontent > 0 && content[pd->xmlp.lcontent - 1] == '\n')
+        content[--pd->xmlp.lcontent] = 0;
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_SUMMARY, content);
+      break;
+
+    case STATE_SEVERITY:
+      repodata_set_poolstr(pd->data, pd->handle, UPDATE_SEVERITY, content);
+      break;
+
+    case STATE_RIGHTS:
+      repodata_set_poolstr(pd->data, pd->handle, UPDATE_RIGHTS, content);
+      break;
+
+      /*
+       * <description>This update ...</description>
+       */
+    case STATE_DESCRIPTION:
+      repodata_set_str(pd->data, pd->handle, SOLVABLE_DESCRIPTION, content);
+      break;
+
+      /*
+       * <message>Warning! ...</message>
+       */
+    case STATE_MESSAGE:
+      repodata_set_str(pd->data, pd->handle, UPDATE_MESSAGE, content);
+      break;
+
+    case STATE_PACKAGE:
+      repodata_add_flexarray(pd->data, pd->handle, UPDATE_COLLECTION, pd->collhandle);
+      pd->collhandle = 0;
+      break;
+
+      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
+      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
+    case STATE_FILENAME:
+      repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, content);
+      break;
+
+      /* <reboot_suggested>True</reboot_suggested> */
+    case STATE_REBOOT:
+      if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
+       {
+         /* FIXME: this is per-package, the global flag should be computed at runtime */
+         repodata_set_void(pd->data, pd->handle, UPDATE_REBOOT);
+         repodata_set_void(pd->data, pd->collhandle, UPDATE_REBOOT);
+       }
+      break;
+
+      /* <restart_suggested>True</restart_suggested> */
+    case STATE_RESTART:
+      if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
+       {
+         /* FIXME: this is per-package, the global flag should be computed at runtime */
+         repodata_set_void(pd->data, pd->handle, UPDATE_RESTART);
+         repodata_set_void(pd->data, pd->collhandle, UPDATE_RESTART);
+       }
+      break;
+
+      /* <relogin_suggested>True</relogin_suggested> */
+    case STATE_RELOGIN:
+      if (content[0] == 'T' || content[0] == 't'|| content[0] == '1')
+       {
+         /* FIXME: this is per-package, the global flag should be computed at runtime */
+         repodata_set_void(pd->data, pd->handle, UPDATE_RELOGIN);
+         repodata_set_void(pd->data, pd->collhandle, UPDATE_RELOGIN);
+       }
+      break;
+    default:
+      break;
+    }
+}
+
+int
+repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  struct parsedata pd;
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+  solv_xmlparser_free(&pd.xmlp);
+  join_freemem(&pd.jd);
+
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return pd.ret;
+}
+
diff --git a/libsolv-0.7.2/ext/repo_updateinfoxml.h b/libsolv-0.7.2/ext/repo_updateinfoxml.h
new file mode 100644 (file)
index 0000000..bd0a61b
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags);
diff --git a/libsolv-0.7.2/ext/repo_zyppdb.c b/libsolv-0.7.2/ext/repo_zyppdb.c
new file mode 100644 (file)
index 0000000..f6e2bfa
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * repo_zyppdb.c
+ *
+ * Parses legacy /var/lib/zypp/db/products/... files.
+ * They are old (pre Code11) product descriptions. See bnc#429177
+ *
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "solv_xmlparser.h"
+#define DISABLE_SPLIT
+#include "tools_util.h"
+#include "repo_zyppdb.h"
+
+
+enum state {
+  STATE_START,
+  STATE_PRODUCT,
+  STATE_NAME,
+  STATE_VERSION,
+  STATE_ARCH,
+  STATE_SUMMARY,
+  STATE_VENDOR,
+  STATE_INSTALLTIME,
+  NUMSTATES
+};
+
+static struct solv_xmlparser_element stateswitches[] = {
+  { STATE_START,     "product",       STATE_PRODUCT,       0 },
+  { STATE_PRODUCT,   "name",          STATE_NAME,          1 },
+  { STATE_PRODUCT,   "version",       STATE_VERSION,       0 },
+  { STATE_PRODUCT,   "arch",          STATE_ARCH,          1 },
+  { STATE_PRODUCT,   "summary",       STATE_SUMMARY,       1 },
+  { STATE_PRODUCT,   "install-time",  STATE_INSTALLTIME,   1 },
+  { STATE_PRODUCT,   "vendor",        STATE_VENDOR,        1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  const char *filename;
+  const char *tmplang;
+  Solvable *solvable;
+  Id handle;
+  struct solv_xmlparser xmlp;
+  struct joindata jd;
+};
+
+
+
+static void
+startElement(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Pool *pool = pd->pool;
+  Solvable *s = pd->solvable;
+
+  switch(state)
+    {
+    case STATE_PRODUCT:
+      {
+       /* parse 'type' */
+       const char *type = solv_xmlparser_find_attr("type", atts);
+       s = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
+       pd->handle = s - pool->solvables;
+       if (type)
+         repodata_set_str(pd->data, pd->handle, PRODUCT_TYPE, type);
+      }
+      break;
+    case STATE_VERSION:
+      {
+       const char *ver = solv_xmlparser_find_attr("ver", atts);
+       const char *rel = solv_xmlparser_find_attr("rel", atts);
+       /* const char *epoch = solv_xmlparser_find_attr("epoch", atts); ignored */
+       s->evr = makeevr(pd->pool, join2(&pd->jd, ver, "-", rel));
+      }
+      break;
+    case STATE_SUMMARY:                /* <summary lang="xy">... */
+      pd->tmplang = join_dup(&pd->jd, solv_xmlparser_find_attr("lang", atts));
+      break;
+    default:
+      break;
+    }
+}
+
+
+static void
+endElement(struct solv_xmlparser *xmlp, int state, char *content)
+{
+  struct parsedata *pd = xmlp->userdata;
+  Solvable *s = pd->solvable;
+
+  switch (state)
+    {
+    case STATE_PRODUCT:
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pd->pool, s->name, s->evr, REL_EQ, 1), 0);
+      pd->solvable = 0;
+      break;
+    case STATE_NAME:
+      s->name = pool_str2id(pd->pool, join2(&pd->jd, "product", ":", content), 1);
+      break;
+    case STATE_ARCH:
+      s->arch = pool_str2id(pd->pool, content, 1);
+      break;
+    case STATE_SUMMARY:
+      repodata_set_str(pd->data, pd->handle, pool_id2langid(pd->pool, SOLVABLE_SUMMARY, pd->tmplang, 1), content);
+      break;
+    case STATE_VENDOR:
+      s->vendor = pool_str2id(pd->pool, content, 1);
+      break;
+    case STATE_INSTALLTIME:
+      repodata_set_num(pd->data, pd->handle, SOLVABLE_INSTALLTIME, atol(content));
+    default:
+      break;
+    }
+}
+
+
+/*
+ * read all installed products
+ *
+ * parse each one as a product
+ */
+
+int
+repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
+{
+  struct parsedata pd;
+  struct dirent *entry;
+  char *fullpath;
+  DIR *dir;
+  FILE *fp;
+  Repodata *data;
+
+  data = repo_add_repodata(repo, flags);
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+
+  if (flags & REPO_USE_ROOTDIR)
+    dirpath = pool_prepend_rootdir(repo->pool, dirpath);
+  dir = opendir(dirpath);
+  if (dir)
+    {
+      while ((entry = readdir(dir)))
+       {
+         if (entry->d_name[0] == '.')
+           continue;   /* skip dot files */
+         fullpath = join2(&pd.jd, dirpath, "/", entry->d_name);
+         if ((fp = fopen(fullpath, "r")) == 0)
+           {
+             pool_error(repo->pool, 0, "%s: %s", fullpath, strerror(errno));
+             continue;
+           }
+          pd.filename = entry->d_name;
+         if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+           {
+             pool_debug(pd.pool, SOLV_ERROR, "repo_zyppdb: %s: %s at line %u:%u\n", pd.filename, pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+             pd.solvable = solvable_free(pd.solvable, 1);
+           }
+         fclose(fp);
+       }
+    }
+  closedir(dir);
+
+  solv_xmlparser_free(&pd.xmlp);
+  join_freemem(&pd.jd);
+  if (flags & REPO_USE_ROOTDIR)
+    solv_free((char *)dirpath);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/ext/repo_zyppdb.h b/libsolv-0.7.2/ext/repo_zyppdb.h
new file mode 100644 (file)
index 0000000..c3c7f39
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags);
diff --git a/libsolv-0.7.2/ext/repodata_diskusage.c b/libsolv-0.7.2/ext/repodata_diskusage.c
new file mode 100644 (file)
index 0000000..fd9c5cc
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * repodata_diskusage.c
+ *
+ * Small helper to convert diskusage data from sustags or rpmmd
+ *
+ * Copyright (c) 2017, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "repodata_diskusage.h"
+
+/* The queue contains (dirid, kbytes, inodes) triplets */
+
+static int
+add_diskusage_sortfn(const void *ap, const void *bp, void *dp)
+{
+  return *(Id *)ap - *(Id *)bp;
+}
+
+void
+repodata_add_diskusage(Repodata *data, Id handle, Queue *q)
+{
+  int i, j;
+  Dirpool *dp = &data->dirpool;
+
+  /* Sort in dirid order. This ensures that parents come before
+   * their children. */
+  if (q->count > 3)
+    solv_sort(q->elements, q->count / 3, 3 * sizeof(Id), add_diskusage_sortfn, 0);
+  for (i = 3; i < q->count; i += 3)
+    {
+      /* subtract data from parent */
+      Id did = q->elements[i];
+      if (i + 3 < q->count && q->elements[i + 3] == did)
+       {
+         /* identical directory entry! zero this one */
+         q->elements[i + 1] = 0;
+         q->elements[i + 2] = 0;
+         continue;
+       }
+      while (did)
+       {
+         did = dirpool_parent(dp, did);
+         for (j = i - 3; j >= 0; j -= 3)
+           if (q->elements[j] == did)
+             break;
+         if (j >= 0)
+           {
+             if ((unsigned int)q->elements[j + 1] > (unsigned int)q->elements[i + 1])
+               q->elements[j + 1] -= q->elements[i + 1];
+             else
+               q->elements[j + 1] = 0;
+             if ((unsigned int)q->elements[j + 2] > (unsigned int)q->elements[i + 2])
+               q->elements[j + 2] -= q->elements[i + 2];
+             else
+               q->elements[j + 2] = 0;
+             break;
+           }
+       }
+    }
+  /* now commit data */
+  for (i = 0; i < q->count; i += 3)
+    if (q->elements[i + 1] || q->elements[i + 2])
+      repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, q->elements[i], q->elements[i + 1], q->elements[i + 2]);
+  /* empty queue */
+  queue_empty(q);
+}
+
diff --git a/libsolv-0.7.2/ext/repodata_diskusage.h b/libsolv-0.7.2/ext/repodata_diskusage.h
new file mode 100644 (file)
index 0000000..1beafea
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern void repodata_add_diskusage(Repodata *data, Id handle, Queue *q);
+
+
diff --git a/libsolv-0.7.2/ext/solv_jsonparser.c b/libsolv-0.7.2/ext/solv_jsonparser.c
new file mode 100644 (file)
index 0000000..053ee6f
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * solv_jsonparser.c
+ *
+ * Simple JSON stream parser
+ *
+ * Copyright (c) 2018, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "solv_jsonparser.h"
+
+struct solv_jsonparser *
+jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
+{
+  memset(jp, 0, sizeof(*jp));
+  jp->fp = fp;
+  jp->state = JP_START;
+  jp->line = jp->nextline = 1;
+  jp->nextc = ' ';
+  queue_init(&jp->stateq);
+  return jp;
+}
+
+struct solv_jsonparser *
+jsonparser_free(struct solv_jsonparser *jp)
+{
+  queue_free(&jp->stateq);
+  return 0;
+}
+
+static void
+savec(struct solv_jsonparser *jp, char c)
+{
+  if (jp->nspace == jp->aspace)
+    {
+      jp->aspace += 256;
+      jp->space = solv_realloc(jp->space, jp->aspace);
+    }
+  jp->space[jp->nspace++] = c;
+}
+
+static void
+saveutf8(struct solv_jsonparser *jp, int c)
+{
+  int i;
+  if (c < 0x80)
+    {
+      savec(jp, c);
+      return;
+    }
+  i = c < 0x800 ? 1 : c < 0x10000 ? 2 : 3;
+  savec(jp, (0x1f80 >> i) | (c >> (6 * i)));
+  while (--i >= 0)
+    savec(jp, 0x80 | ((c >> (6 * i)) & 0x3f));
+}
+
+static inline int
+nextc(struct solv_jsonparser *jp)
+{
+  int c = getc(jp->fp);
+  if (c == '\n')
+    jp->nextline++;
+  return c;
+}
+
+static int
+skipspace(struct solv_jsonparser *jp)
+{
+  int c = jp->nextc;
+  while (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+    c = nextc(jp);
+  jp->line = jp->nextline;
+  return (jp->nextc = c);
+}
+
+static int
+parseliteral(struct solv_jsonparser *jp)
+{
+  size_t nspace = jp->nspace;
+  int c;
+  savec(jp, jp->nextc);
+  for (;;)
+    {
+      c = nextc(jp);
+      if (c < 'a' || c > 'z')
+       break;
+      savec(jp, c);
+    }
+  jp->nextc = c;
+  savec(jp, 0);
+  if (!strcmp(jp->space + nspace, "true"))
+    return JP_BOOL;
+  if (!strcmp(jp->space + nspace, "false"))
+    return JP_BOOL;
+  if (!strcmp(jp->space + nspace, "null"))
+    return JP_NULL;
+  return JP_ERROR;
+}
+
+static int
+parsenumber(struct solv_jsonparser *jp)
+{
+  int c;
+  savec(jp, jp->nextc);
+  for (;;)
+    {
+      c = nextc(jp);
+      if ((c < '0' || c > '9') && c != '+' && c != '-' && c != '.' && c != 'e' && c != 'E')
+       break;
+      savec(jp, c);
+    }
+  jp->nextc = c;
+  savec(jp, 0);
+  return JP_NUMBER;
+}
+
+static int
+parseutf8(struct solv_jsonparser *jp, int surrogate)
+{
+  int c, i, r = 0;
+  /* parse 4-digit hex */
+  for (i = 0; i < 4; i++)
+    {
+      c = nextc(jp);
+      if (c >= '0' && c <= '9')
+       c -= '0';
+      else if (c >= 'a' && c <= 'f')
+       c -= 'a' - 10;
+      else if (c >= 'A' && c <= 'F')
+       c -= 'A' - 10;
+      else
+       return -1;
+      r = (r << 4) | c;
+    }
+  if (!surrogate && r >= 0xd800 && r < 0xdc00)
+    {
+      /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
+      int r2;
+      if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000)
+       return -1;
+      r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff));
+    }
+  return r;
+}
+
+static int
+parsestring(struct solv_jsonparser *jp)
+{
+  int c;
+  for (;;)
+    {
+      if ((c = nextc(jp)) < 32)
+       return JP_ERROR;
+      if (c == '"')
+       break;
+      if (c == '\\')
+       {
+         switch (c = nextc(jp))
+           {
+           case '"':
+           case '\\':
+           case '/':
+           case '\n':
+             break;
+           case 'b':
+             c = '\b';
+             break;
+           case 'f':
+             c = '\f';
+             break;
+           case 'n':
+             c = '\n';
+             break;
+           case 'r':
+             c = '\r';
+             break;
+           case 't':
+             c = '\t';
+             break;
+           case 'u':
+             if ((c = parseutf8(jp, 0)) < 0)
+               return JP_ERROR;
+             saveutf8(jp, c);
+             continue;
+           default:
+             return JP_ERROR;
+           }
+       }
+      savec(jp, c);
+    }
+  jp->nextc = ' ';
+  savec(jp, 0);
+  return JP_STRING;
+}
+
+static int
+parsevalue(struct solv_jsonparser *jp)
+{
+  int c = skipspace(jp);
+  if (c == '"')
+    return parsestring(jp);
+  if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
+    return parsenumber(jp);
+  if ((c >= 'a' && c <= 'z'))
+    return parseliteral(jp);
+  jp->nextc = ' ';
+  if (c == '[')
+    return JP_ARRAY;
+  if (c == '{')
+    return JP_OBJECT;
+  if (c == ']')
+    return JP_ARRAY_END;
+  if (c == '}')
+    return JP_OBJECT_END;
+  return JP_ERROR;
+}
+
+int
+jsonparser_parse(struct solv_jsonparser *jp)
+{
+  int type;
+  size_t nspace;
+
+  jp->depth = jp->stateq.count;
+  jp->key = jp->value = 0;
+  jp->keylen = jp->valuelen = 0;
+  nspace = jp->nspace = 0;
+
+  if (jp->state == JP_END)
+    return JP_END;
+  if (jp->state == JP_START)
+    jp->state = JP_END;
+  type = parsevalue(jp);
+  if (type <= 0)
+    return JP_ERROR;
+  if (type == JP_OBJECT_END || type == JP_ARRAY_END)
+    {
+      if (jp->state != type - 1)
+        return JP_ERROR;
+      jp->state = queue_pop(&jp->stateq);
+    }
+  else if (jp->state == JP_OBJECT)
+    {
+      nspace = jp->nspace;
+      if (type != JP_STRING)
+       return JP_ERROR;
+      if (skipspace(jp) != ':')
+       return JP_ERROR;
+      jp->nextc = ' ';
+      type = parsevalue(jp);
+      if (type == JP_OBJECT_END || type == JP_ARRAY_END)
+       return JP_ERROR;
+      jp->key = jp->space;
+      jp->keylen = nspace - 1;
+    }
+  if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
+    {
+      jp->value = jp->space + nspace;
+      jp->valuelen = jp->nspace - nspace - 1;
+    }
+  if (type == JP_ARRAY || type == JP_OBJECT)
+    {
+      queue_push(&jp->stateq, jp->state);
+      jp->state = type;
+    }
+  else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
+    {
+      int c = skipspace(jp);
+      if (c == ',')
+       jp->nextc = ' ';
+      else if (c != (jp->state == JP_OBJECT ? '}' : ']'))
+       return JP_ERROR;
+    }
+  return type;
+}
+
+int
+jsonparser_skip(struct solv_jsonparser *jp, int type)
+{
+  if (type == JP_ARRAY || type == JP_OBJECT)
+    {
+      int depth = jp->depth + 1, endtype = type + 1;
+      while (type > 0 && (type != endtype || jp->depth != depth))
+        type = jsonparser_parse(jp);
+    }
+  return type;
+}
+
diff --git a/libsolv-0.7.2/ext/solv_jsonparser.h b/libsolv-0.7.2/ext/solv_jsonparser.h
new file mode 100644 (file)
index 0000000..d58d9e3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef SOLV_JSONPARSER_H
+#define SOLV_JSONPARSER_H
+
+#include "queue.h"
+
+struct solv_jsonparser {
+  FILE *fp;
+  int line;
+  int depth;
+
+  char *key;
+  size_t keylen;
+  char *value;
+  size_t valuelen;
+
+  int state;
+  Queue stateq;
+  int nextc;
+  int nextline;
+  char *space;
+  size_t nspace;
+  size_t aspace;
+};
+
+#define JP_ERROR       -1
+#define JP_END         0
+#define JP_START       1
+#define JP_STRING      2
+#define JP_NUMBER      3
+#define JP_BOOL                4
+#define JP_NULL                5
+#define JP_OBJECT      6
+#define JP_OBJECT_END  7
+#define JP_ARRAY       8
+#define JP_ARRAY_END   9
+
+struct solv_jsonparser *jsonparser_init(struct solv_jsonparser *jp, FILE *fp);
+struct solv_jsonparser *jsonparser_free(struct solv_jsonparser *jp);
+int jsonparser_parse(struct solv_jsonparser *jp);
+int jsonparser_skip(struct solv_jsonparser *jp, int type);
+
+#endif /* SOLV_JSONPARSER_H */
diff --git a/libsolv-0.7.2/ext/solv_pgpvrfy.c b/libsolv-0.7.2/ext/solv_pgpvrfy.c
new file mode 100644 (file)
index 0000000..9bc256c
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* simple and slow rsa/dsa verification code. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "solv_pgpvrfy.h"
+
+typedef unsigned int mp_t;
+typedef unsigned long long mp2_t;
+#define MP_T_BYTES 4
+
+#define MP_T_BITS (MP_T_BYTES * 8)
+
+static inline void
+mpzero(int len, mp_t *target)
+{
+  memset(target, 0, MP_T_BYTES * len);
+}
+
+static inline mp_t *
+mpnew(int len)
+{
+  return solv_calloc(len, MP_T_BYTES);
+}
+
+static inline void
+mpcpy(int len, mp_t *target, mp_t *source)
+{
+  memcpy(target, source, len * MP_T_BYTES);
+}
+
+#if 0
+static void mpdump(int l, mp_t *a, char *s)
+{
+  int i;
+  if (s)
+    fprintf(stderr, "%s", s);
+  for (i = l - 1; i >= 0; i--)
+    fprintf(stderr, "%0*x", MP_T_BYTES * 2, a[i]);
+  fprintf(stderr, "\n");
+}
+#endif
+
+/* target[len] = x, target = target % mod
+ * assumes that target < (mod << MP_T_BITS)! */
+static void
+mpdomod(int len, mp_t *target, mp2_t x, mp_t *mod)
+{
+  int i, j;
+  for (i = len - 1; i >= 0; i--)
+    {
+      x = (x << MP_T_BITS) | target[i];
+      target[i] = 0;
+      if (mod[i])
+       break;
+    }
+  if (i < 0)
+    return;
+  while (x >= 2 * (mp2_t)mod[i])
+    {
+      /* reduce */
+      mp2_t z = x / ((mp2_t)mod[i] + 1);
+      mp2_t n = 0;
+      if ((z >> MP_T_BITS) != 0)
+       z = (mp2_t)1 << MP_T_BITS;      /* just in case... */
+      for (j = 0; j < i; j++)
+       {
+         mp_t n2;
+         n += mod[j] * z;
+         n2 = (mp_t)n;
+         n >>= MP_T_BITS;
+         if (n2 > target[j])
+           n++;
+         target[j] -= n2;
+       }
+      n += mod[j] * z;
+      x -= n;
+    }
+  target[i] = x;
+  if (x >= mod[i])
+    {
+      mp_t n;
+      if (x == mod[i])
+       {
+         for (j = i - 1; j >= 0; j--)
+           if (target[j] < mod[j])
+             return;
+           else if (target[j] > mod[j])
+             break;
+       }
+      /* target >= mod, subtract mod */
+      n = 0;
+      for (j = 0; j <= i; j++)
+       {
+         mp2_t n2 = mod[j] + n;
+         n = n2 > target[j] ? 1 : 0;
+         target[j] -= (mp_t)n2;
+       }
+    }
+}
+
+/* target += src * m */
+static void
+mpmult_add_int(int len, mp_t *target, mp_t *src, mp2_t m, mp_t *mod)
+{
+  int i;
+  mp2_t x = 0;
+  for (i = 0; i < len; i++)
+    {
+      x += src[i] * m + target[i];
+      target[i] = x;
+      x >>= MP_T_BITS;
+    }
+  mpdomod(len, target, x, mod);
+}
+
+/* target = target << MP_T_BITS */
+static void
+mpshift(int len, mp_t *target, mp_t *mod)
+{
+  mp_t x;
+  if (len <= 0)
+    return;
+  x = target[len - 1];
+  if (len > 1)
+    memmove(target + 1, target, (len - 1) * MP_T_BYTES);
+  target[0] = 0;
+  mpdomod(len, target, x, mod);
+}
+
+/* target += m1 * m2 */
+static void
+mpmult_add(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *tmp, mp_t *mod)
+{
+  int i, j;
+  for (j = m2len - 1; j >= 0; j--)
+    if (m2[j])
+      break;
+  if (j < 0)
+    return;
+  mpcpy(len, tmp, m1);
+  for (i = 0; i < j; i++)
+    {
+      if (m2[i])
+        mpmult_add_int(len, target, tmp, m2[i], mod);
+      mpshift(len, tmp, mod);
+    }
+  if (m2[i])
+    mpmult_add_int(len, target, tmp, m2[i], mod);
+}
+
+/* target = target * m */
+static void
+mpmult_inplace(int len, mp_t *target, mp_t *m, mp_t *tmp1, mp_t *tmp2, mp_t *mod)
+{
+  mpzero(len, tmp1);
+  mpmult_add(len, tmp1, target, len, m, tmp2, mod);
+  mpcpy(len, target, tmp1);
+}
+
+/* target = target ^ 16 * b ^ e */
+static void
+mppow_int(int len, mp_t *target, mp_t *t, mp_t *mod, int e)
+{
+  mp_t *t2 = t + len * 16;
+  mpmult_inplace(len, target, target, t, t2, mod);
+  mpmult_inplace(len, target, target, t, t2, mod);
+  mpmult_inplace(len, target, target, t, t2, mod);
+  mpmult_inplace(len, target, target, t, t2, mod);
+  if (e)
+    mpmult_inplace(len, target, t + len * e, t, t2, mod);
+}
+
+/* target = b ^ e (b has to be < mod) */
+static void
+mppow(int len, mp_t *target, mp_t *b, int elen, mp_t *e, mp_t *mod)
+{
+  int i, j;
+  mp_t *t;
+  mpzero(len, target);
+  target[0] = 1;
+  for (i = elen - 1; i >= 0; i--)
+    if (e[i])
+      break;
+  if (i < 0)
+    return;
+  t = mpnew(len * 17);
+  mpcpy(len, t + len, b);
+  for (j = 2; j < 16; j++)
+    mpmult_add(len, t + len * j, b, len, t + len * j - len, t + len * 16, mod);
+  for (; i >= 0; i--)
+    {
+#if MP_T_BYTES == 4
+      mppow_int(len, target, t, mod, (e[i] >> 28) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 24) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 20) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 16) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >> 12) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >>  8) & 0x0f);
+      mppow_int(len, target, t, mod, (e[i] >>  4) & 0x0f);
+      mppow_int(len, target, t, mod,  e[i]        & 0x0f);
+#elif MP_T_BYTES == 1
+      mppow_int(len, target, t, mod, (e[i] >>  4) & 0x0f);
+      mppow_int(len, target, t, mod,  e[i]        & 0x0f);
+#endif
+    }
+  free(t);
+}
+
+/* target = m1 * m2 (m1 has to be < mod) */
+static void
+mpmult(int len, mp_t *target, mp_t *m1, int m2len, mp_t *m2, mp_t *mod)
+{
+  mp_t *tmp = mpnew(len);
+  mpzero(len, target);
+  mpmult_add(len, target, m1, m2len, m2, tmp, mod);
+  free(tmp);
+}
+
+static int
+mpisless(int len, mp_t *a, mp_t *b)
+{
+  int i;
+  for (i = len - 1; i >= 0; i--)
+    if (a[i] < b[i])
+      return 1;
+    else if (a[i] > b[i])
+      return 0;
+  return 0;
+}
+
+static int
+mpiszero(int len, mp_t *a)
+{
+  int i;
+  for (i = 0; i < len; i++)
+    if (a[i])
+      return 0;
+  return 1;
+}
+
+static void
+mpdec(int len, mp_t *a)
+{
+  int i;
+  for (i = 0; i < len; i++)
+    if (a[i]--)
+      return;
+    else
+      a[i] = -(mp_t)1;
+}
+
+static int
+mpdsa(int pl, mp_t *p, int ql, mp_t *q, mp_t *g, mp_t *y, mp_t *r, mp_t *s, int hl, mp_t *h)
+{
+  mp_t *w;
+  mp_t *tmp;
+  mp_t *u1, *u2;
+  mp_t *gu1, *yu2;
+#if 0
+  mpdump(pl, p, "p = ");
+  mpdump(ql, q, "q = ");
+  mpdump(pl, g, "g = ");
+  mpdump(pl, y, "y = ");
+  mpdump(ql, r, "r = ");
+  mpdump(ql, s, "s = ");
+  mpdump(hl, h, "h = ");
+#endif
+  if (pl < ql || !mpisless(pl, g, p) || !mpisless(pl, y, p))
+    return 0;                          /* hmm, bad pubkey? */
+  if (!mpisless(ql, r, q) || mpiszero(ql, r))
+    return 0;
+  if (!mpisless(ql, s, q) || mpiszero(ql, s))
+    return 0;
+  tmp = mpnew(pl);                     /* note pl */
+  mpcpy(ql, tmp, q);                   /* tmp = q */
+  mpdec(ql, tmp);                      /* tmp-- */
+  mpdec(ql, tmp);                      /* tmp-- */
+  w = mpnew(ql);
+  mppow(ql, w, s, ql, tmp, q);         /* w = s ^ tmp (s ^ -1) */
+  u1 = mpnew(pl);                      /* note pl */
+  /* order is important here: h can be >= q */
+  mpmult(ql, u1, w, hl, h, q);         /* u1 = w * h */
+  u2 = mpnew(ql);                      /* u2 = 0 */
+  mpmult(ql, u2, w, ql, r, q);         /* u2 = w * r */
+  free(w);
+  gu1 = mpnew(pl);
+  yu2 = mpnew(pl);
+  mppow(pl, gu1, g, ql, u1, p);                /* gu1 = g ^ u1 */
+  mppow(pl, yu2, y, ql, u2, p);                /* yu2 = y ^ u2 */
+  mpmult(pl, u1, gu1, pl, yu2, p);     /* u1 = gu1 * yu2 */
+  free(gu1);
+  free(yu2);
+  mpzero(ql, u2);
+  u2[0] = 1;                           /* u2 = 1 */
+  mpmult(ql, tmp, u2, pl, u1, q);      /* tmp = u2 * u1 */
+  free(u1);
+  free(u2);
+#if 0
+  mpdump(ql, tmp, "res = ");
+#endif
+  if (memcmp(tmp, r, ql * MP_T_BYTES) != 0)
+    {
+      free(tmp);
+      return 0;
+    }
+  free(tmp);
+  return 1;
+}
+
+static int
+mprsa(int nl, mp_t *n, int el, mp_t *e, mp_t *m, mp_t *c)
+{
+  mp_t *tmp;
+#if 0
+  mpdump(nl, n, "n = ");
+  mpdump(el, e, "e = ");
+  mpdump(nl, m, "m = ");
+  mpdump(nl, c, "c = ");
+#endif
+  if (!mpisless(nl, m, n))
+    return 0;
+  if (!mpisless(nl, c, n))
+    return 0;
+  tmp = mpnew(nl);
+  mppow(nl, tmp, m, el, e, n);         /* tmp = m ^ e */
+#if 0
+  mpdump(nl, tmp, "res = ");
+#endif
+  if (memcmp(tmp, c, nl * MP_T_BYTES) != 0)
+    {
+      free(tmp);
+      return 0;
+    }
+  free(tmp);
+  return 1;
+}
+
+/* create mp with size tbits from data with size dbits */
+static mp_t *
+mpbuild(const unsigned char *d, int dbits, int tbits, int *mplp)
+{
+  int l = (tbits + MP_T_BITS - 1) / MP_T_BITS;
+  int dl, i;
+
+  mp_t *out = mpnew(l ? l : 1);
+  if (mplp)
+    *mplp = l;
+  dl = (dbits + 7) / 8;
+  d += dl;
+  if (dbits > tbits)
+    dl = (tbits + 7) / 8;
+  for (i = 0; dl > 0; dl--, i++)
+    {
+      int x = *--d;
+      out[i / MP_T_BYTES] |= x << (8 * (i % MP_T_BYTES));
+    }
+  return out;
+}
+
+static const unsigned char *
+findmpi(const unsigned char **mpip, int *mpilp, int maxbits, int *outlen)
+{
+  int mpil = *mpilp;
+  const unsigned char *mpi = *mpip;
+  int bits, l;
+
+  *outlen = 0;
+  if (mpil < 2)
+    return 0;
+  bits = mpi[0] << 8 | mpi[1];
+  l = 2 + (bits + 7) / 8;
+  if (bits > maxbits || mpil < l || (bits && !mpi[2]))
+    {
+      *mpilp = 0;
+      return 0;
+    }
+  *outlen = bits;
+  *mpilp = mpil - l;
+  *mpip = mpi + l;
+  return mpi + 2;
+}
+
+int
+solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int sigl)
+{
+  int hashl;
+  unsigned char *oid = 0;
+  const unsigned char *mpi;
+  int mpil;
+  int res = 0;
+
+  if (!pub || !sig || publ < 1 || sigl < 2)
+    return 0;
+  if (pub[0] != sig[0])
+    return 0;          /* key algo mismatch */
+  switch(sig[1])
+    {
+    case 1:
+      hashl = 16;      /* MD5 */
+      oid = (unsigned char *)"\022\060\040\060\014\006\010\052\206\110\206\367\015\002\005\005\000\004\020";
+      break;
+    case 2:
+      hashl = 20;      /* SHA-1 */
+      oid = (unsigned char *)"\017\060\041\060\011\006\005\053\016\003\002\032\005\000\004\024";
+      break;
+    case 8:
+      hashl = 32;      /* SHA-256 */
+      oid = (unsigned char *)"\023\060\061\060\015\006\011\140\206\110\001\145\003\004\002\001\005\000\004\040";
+      break;
+    case 9:
+      hashl = 48;      /* SHA-384 */
+      oid = (unsigned char *)"\023\060\101\060\015\006\011\140\206\110\001\145\003\004\002\002\005\000\004\060";
+      break;
+    case 10:
+      hashl = 64;      /* SHA-512 */
+      oid = (unsigned char *)"\023\060\121\060\015\006\011\140\206\110\001\145\003\004\002\003\005\000\004\100";
+      break;
+    case 11:
+      hashl = 28;      /* SHA-224 */
+      oid = (unsigned char *)"\023\060\061\060\015\006\011\140\206\110\001\145\003\004\002\004\005\000\004\034";
+      break;
+    default:
+      return 0;                /* unsupported hash algo */
+    }
+  if (sigl < 2 + hashl)
+    return 0;
+  switch (pub[0])
+    {
+    case 1:            /* RSA */
+      {
+       const unsigned char *n, *e, *m;
+       unsigned char *c;
+       int nlen, elen, mlen, clen;
+       mp_t *nx, *ex, *mx, *cx;
+       int nxl, exl;
+
+        mpi = pub + 1;
+        mpil = publ - 1;
+       n = findmpi(&mpi, &mpil, 8192, &nlen);
+       e = findmpi(&mpi, &mpil, 1024, &elen);
+        mpi = sig + 2 + hashl;
+        mpil = sigl - (2 + hashl);
+       m = findmpi(&mpi, &mpil, nlen, &mlen);
+        if (!n || !e || !m || !nlen || !elen)
+         return 0;
+       /* build padding block */
+       clen = (nlen - 1) / 8;
+       if (hashl + *oid + 2 > clen)
+         return 0;
+       c = solv_malloc(clen);
+       memset(c, 0xff, clen);
+       c[0] = 1;
+       memcpy(c + clen - hashl, sig + 2, hashl);
+       memcpy(c + clen - hashl - *oid, oid + 1, *oid);
+       c[clen - hashl - *oid - 1] = 0;
+       clen = clen * 8 - 7;    /* always <= nlen */
+       nx = mpbuild(n, nlen, nlen, &nxl);
+       ex = mpbuild(e, elen, elen, &exl);
+       mx = mpbuild(m, mlen, nlen, 0);
+       cx = mpbuild(c, clen, nlen, 0);
+       free(c);
+       res = mprsa(nxl, nx, exl, ex, mx, cx);
+       free(nx);
+       free(ex);
+       free(mx);
+       free(cx);
+       break;
+      }
+    case 17:           /* DSA */
+      {
+       const unsigned char *p, *q, *g, *y, *r, *s;
+       int plen, qlen, glen, ylen, rlen, slen, hlen;
+       mp_t *px, *qx, *gx, *yx, *rx, *sx, *hx;
+       int pxl, qxl, hxl;
+
+        mpi = pub + 1;
+        mpil = publ - 1;
+       p = findmpi(&mpi, &mpil, 8192, &plen);
+       q = findmpi(&mpi, &mpil, 1024, &qlen);
+       g = findmpi(&mpi, &mpil, plen, &glen);
+       y = findmpi(&mpi, &mpil, plen, &ylen);
+        mpi = sig + 2 + hashl;
+        mpil = sigl - (2 + hashl);
+       r = findmpi(&mpi, &mpil, qlen, &rlen);
+       s = findmpi(&mpi, &mpil, qlen, &slen);
+        if (!p || !q || !g || !y || !r || !s || !plen || !qlen)
+         return 0;
+       hlen = (qlen + 7) & ~7;
+       if (hlen > hashl * 8)
+         return 0;
+       px = mpbuild(p, plen, plen, &pxl);
+       qx = mpbuild(q, qlen, qlen, &qxl);
+       gx = mpbuild(g, glen, plen, 0);
+       yx = mpbuild(y, ylen, plen, 0);
+       rx = mpbuild(r, rlen, qlen, 0);
+       sx = mpbuild(s, slen, qlen, 0);
+       hx = mpbuild(sig + 2, hlen, hlen, &hxl);
+        res = mpdsa(pxl, px, qxl, qx, gx, yx, rx, sx, hxl, hx);
+       free(px);
+       free(qx);
+       free(gx);
+       free(yx);
+       free(rx);
+       free(sx);
+       free(hx);
+       break;
+      }
+    default:
+      return 0;                /* unsupported pubkey algo */
+    }
+  return res;
+}
+
diff --git a/libsolv-0.7.2/ext/solv_pgpvrfy.h b/libsolv-0.7.2/ext/solv_pgpvrfy.h
new file mode 100644 (file)
index 0000000..a623e85
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern int solv_pgpvrfy(const unsigned char *pub, int publ, const unsigned char *sig, int sigl);
+
diff --git a/libsolv-0.7.2/ext/solv_xfopen.c b/libsolv-0.7.2/ext/solv_xfopen.c
new file mode 100644 (file)
index 0000000..343aed8
--- /dev/null
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 2011, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "solv_xfopen.h"
+#include "util.h"
+
+
+static FILE *cookieopen(void *cookie, const char *mode,
+       ssize_t (*cread)(void *, char *, size_t),
+       ssize_t (*cwrite)(void *, const char *, size_t),
+       int (*cclose)(void *))
+{
+#ifdef HAVE_FUNOPEN
+  if (!cookie)
+    return 0;
+  return funopen(cookie,
+      (int (*)(void *, char *, int))(*mode == 'r' ? cread : NULL),             /* readfn */
+      (int (*)(void *, const char *, int))(*mode == 'w' ? cwrite : NULL),      /* writefn */
+      (fpos_t (*)(void *, fpos_t, int))NULL,                                   /* seekfn */
+      cclose
+      );
+#elif defined(HAVE_FOPENCOOKIE)
+  cookie_io_functions_t cio;
+
+  if (!cookie)
+    return 0;
+  memset(&cio, 0, sizeof(cio));
+  if (*mode == 'r')
+    cio.read = cread;
+  else if (*mode == 'w')
+    cio.write = cwrite;
+  cio.close = cclose;
+  return  fopencookie(cookie, *mode == 'w' ? "w" : "r", cio);
+#else
+# error Need to implement custom I/O
+#endif
+}
+
+
+#ifdef ENABLE_ZLIB_COMPRESSION
+
+/* gzip compression */
+
+#include <zlib.h>
+
+static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
+{
+  return gzread((gzFile)cookie, buf, nbytes);
+}
+
+static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
+{
+  return gzwrite((gzFile)cookie, buf, nbytes);
+}
+
+static int cookie_gzclose(void *cookie)
+{
+  return gzclose((gzFile)cookie);
+}
+
+static inline FILE *mygzfopen(const char *fn, const char *mode)
+{
+  gzFile gzf = gzopen(fn, mode);
+  return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
+}
+
+static inline FILE *mygzfdopen(int fd, const char *mode)
+{
+  gzFile gzf = gzdopen(fd, mode);
+  return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
+}
+
+#endif
+
+
+#ifdef ENABLE_BZIP2_COMPRESSION
+
+/* bzip2 compression */
+
+#include <bzlib.h>
+
+static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
+{
+  return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
+}
+
+static ssize_t cookie_bzwrite(void *cookie, const char *buf, size_t nbytes)
+{
+  return BZ2_bzwrite((BZFILE *)cookie, (char *)buf, nbytes);
+}
+
+static int cookie_bzclose(void *cookie)
+{
+  BZ2_bzclose((BZFILE *)cookie);
+  return 0;
+}
+
+static inline FILE *mybzfopen(const char *fn, const char *mode)
+{
+  BZFILE *bzf = BZ2_bzopen(fn, mode);
+  return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
+}
+
+static inline FILE *mybzfdopen(int fd, const char *mode)
+{
+  BZFILE *bzf = BZ2_bzdopen(fd, mode);
+  return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
+}
+
+#endif
+
+
+#ifdef ENABLE_LZMA_COMPRESSION
+
+/* lzma code written by me in 2008 for rpm's rpmio.c */
+
+#include <lzma.h>
+
+typedef struct lzfile {
+  unsigned char buf[1 << 15];
+  lzma_stream strm;
+  FILE *file;
+  int encoding;
+  int eof;
+} LZFILE;
+
+static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
+{
+  lzma_options_lzma options;
+  lzma_lzma_preset(&options, level);
+  return lzma_alone_encoder(strm, &options);
+}
+
+static lzma_stream stream_init = LZMA_STREAM_INIT;
+
+static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
+{
+  int level = 7;
+  int encoding = 0;
+  FILE *fp;
+  LZFILE *lzfile;
+  lzma_ret ret;
+
+  if (!path && fd < 0)
+    return 0;
+  for (; *mode; mode++)
+    {
+      if (*mode == 'w')
+       encoding = 1;
+      else if (*mode == 'r')
+       encoding = 0;
+      else if (*mode >= '1' && *mode <= '9')
+       level = *mode - '0';
+    }
+  if (fd != -1)
+    fp = fdopen(fd, encoding ? "w" : "r");
+  else
+    fp = fopen(path, encoding ? "w" : "r");
+  if (!fp)
+    return 0;
+  lzfile = calloc(1, sizeof(*lzfile));
+  if (!lzfile)
+    {
+      fclose(fp);
+      return 0;
+    }
+  lzfile->file = fp;
+  lzfile->encoding = encoding;
+  lzfile->eof = 0;
+  lzfile->strm = stream_init;
+  if (encoding)
+    {
+      if (isxz)
+       ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
+      else
+       ret = setup_alone_encoder(&lzfile->strm, level);
+    }
+  else
+    ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
+  if (ret != LZMA_OK)
+    {
+      fclose(fp);
+      free(lzfile);
+      return 0;
+    }
+  return lzfile;
+}
+
+static int lzclose(void *cookie)
+{
+  LZFILE *lzfile = cookie;
+  lzma_ret ret;
+  size_t n;
+  int rc;
+
+  if (!lzfile)
+    return -1;
+  if (lzfile->encoding)
+    {
+      for (;;)
+       {
+         lzfile->strm.avail_out = sizeof(lzfile->buf);
+         lzfile->strm.next_out = lzfile->buf;
+         ret = lzma_code(&lzfile->strm, LZMA_FINISH);
+         if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+           return -1;
+         n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
+         if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+           return -1;
+         if (ret == LZMA_STREAM_END)
+           break;
+       }
+    }
+  lzma_end(&lzfile->strm);
+  rc = fclose(lzfile->file);
+  free(lzfile);
+  return rc;
+}
+
+static ssize_t lzread(void *cookie, char *buf, size_t len)
+{
+  LZFILE *lzfile = cookie;
+  lzma_ret ret;
+  int eof = 0;
+
+  if (!lzfile || lzfile->encoding)
+    return -1;
+  if (lzfile->eof)
+    return 0;
+  lzfile->strm.next_out = (unsigned char *)buf;
+  lzfile->strm.avail_out = len;
+  for (;;)
+    {
+      if (!lzfile->strm.avail_in)
+       {
+         lzfile->strm.next_in = lzfile->buf;
+         lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
+         if (!lzfile->strm.avail_in)
+           eof = 1;
+       }
+      ret = lzma_code(&lzfile->strm, LZMA_RUN);
+      if (ret == LZMA_STREAM_END)
+       {
+         lzfile->eof = 1;
+         return len - lzfile->strm.avail_out;
+       }
+      if (ret != LZMA_OK)
+       return -1;
+      if (!lzfile->strm.avail_out)
+       return len;
+      if (eof)
+       return -1;
+    }
+}
+
+static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
+{
+  LZFILE *lzfile = cookie;
+  lzma_ret ret;
+  size_t n;
+  if (!lzfile || !lzfile->encoding)
+    return -1;
+  if (!len)
+    return 0;
+  lzfile->strm.next_in = (unsigned char *)buf;
+  lzfile->strm.avail_in = len;
+  for (;;)
+    {
+      lzfile->strm.next_out = lzfile->buf;
+      lzfile->strm.avail_out = sizeof(lzfile->buf);
+      ret = lzma_code(&lzfile->strm, LZMA_RUN);
+      if (ret != LZMA_OK)
+       return -1;
+      n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
+      if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+       return -1;
+      if (!lzfile->strm.avail_in)
+       return len;
+    }
+}
+
+static inline FILE *myxzfopen(const char *fn, const char *mode)
+{
+  LZFILE *lzf = lzopen(fn, mode, -1, 1);
+  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+static inline FILE *myxzfdopen(int fd, const char *mode)
+{
+  LZFILE *lzf = lzopen(0, mode, fd, 1);
+  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+static inline FILE *mylzfopen(const char *fn, const char *mode)
+{
+  LZFILE *lzf = lzopen(fn, mode, -1, 0);
+  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+static inline FILE *mylzfdopen(int fd, const char *mode)
+{
+  LZFILE *lzf = lzopen(0, mode, fd, 0);
+  return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
+}
+
+#endif /* ENABLE_LZMA_COMPRESSION */
+
+#ifdef ENABLE_ZSTD_COMPRESSION
+
+#include <zstd.h>
+
+typedef struct zstdfile {
+  ZSTD_CStream *cstream;
+  ZSTD_DStream *dstream;
+  FILE *file;
+  int encoding;
+  int eof;
+  ZSTD_inBuffer in;
+  ZSTD_outBuffer out;
+  unsigned char buf[1 << 15];
+} ZSTDFILE;
+
+static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd)
+{
+  int level = 7;
+  int encoding = 0;
+  FILE *fp;
+  ZSTDFILE *zstdfile;
+
+  if (!path && fd < 0)
+    return 0;
+  for (; *mode; mode++)
+    {
+      if (*mode == 'w')
+       encoding = 1;
+      else if (*mode == 'r')
+       encoding = 0;
+      else if (*mode >= '1' && *mode <= '9')
+       level = *mode - '0';
+    }
+  if (fd != -1)
+    fp = fdopen(fd, encoding ? "w" : "r");
+  else
+    fp = fopen(path, encoding ? "w" : "r");
+  if (!fp)
+    return 0;
+  zstdfile = solv_calloc(1, sizeof(*zstdfile));
+  zstdfile->encoding = encoding;
+  if (encoding)
+    {
+      zstdfile->cstream = ZSTD_createCStream();
+      zstdfile->encoding = 1;
+      if (!zstdfile->cstream)
+       {
+         solv_free(zstdfile);
+         fclose(fp);
+         return 0;
+       }
+      if (ZSTD_isError(ZSTD_initCStream(zstdfile->cstream, level)))
+       {
+         ZSTD_freeCStream(zstdfile->cstream);
+         solv_free(zstdfile);
+         fclose(fp);
+         return 0;
+       }
+      zstdfile->out.dst = zstdfile->buf;
+      zstdfile->out.pos = 0;
+      zstdfile->out.size = sizeof(zstdfile->buf);
+    }
+  else
+    {
+      zstdfile->dstream = ZSTD_createDStream();
+      if (ZSTD_isError(ZSTD_initDStream(zstdfile->dstream)))
+       {
+         ZSTD_freeDStream(zstdfile->dstream);
+         solv_free(zstdfile);
+         fclose(fp);
+         return 0;
+       }
+      zstdfile->in.src = zstdfile->buf;
+      zstdfile->in.pos = 0;
+      zstdfile->in.size = 0;
+    }
+  zstdfile->file = fp;
+  return zstdfile;
+}
+
+static int zstdclose(void *cookie)
+{
+  ZSTDFILE *zstdfile = cookie;
+  int rc;
+
+  if (!zstdfile)
+    return -1;
+  if (zstdfile->encoding)
+    {
+      for (;;)
+       {
+         size_t ret;
+         zstdfile->out.pos = 0;
+         ret = ZSTD_endStream(zstdfile->cstream, &zstdfile->out);
+         if (ZSTD_isError(ret))
+           return -1;
+         if (zstdfile->out.pos && fwrite(zstdfile->buf, 1, zstdfile->out.pos, zstdfile->file) != zstdfile->out.pos)
+           return -1;
+         if (ret == 0)
+           break;
+       }
+      ZSTD_freeCStream(zstdfile->cstream);
+    }
+  else
+    {
+      ZSTD_freeDStream(zstdfile->dstream);
+    }
+  rc = fclose(zstdfile->file);
+  free(zstdfile);
+  return rc;
+}
+
+static ssize_t zstdread(void *cookie, char *buf, size_t len)
+{
+  ZSTDFILE *zstdfile = cookie;
+  int eof = 0;
+  size_t ret = 0;
+  if (!zstdfile || zstdfile->encoding)
+    return -1;
+  if (zstdfile->eof)
+    return 0;
+  zstdfile->out.dst = buf;
+  zstdfile->out.pos = 0;
+  zstdfile->out.size = len;
+  for (;;)
+    {
+      if (!eof && zstdfile->in.pos == zstdfile->in.size)
+       {
+         zstdfile->in.pos = 0;
+         zstdfile->in.size = fread(zstdfile->buf, 1, sizeof(zstdfile->buf), zstdfile->file);
+         if (!zstdfile->in.size)
+           eof = 1;
+       }
+      if (ret || !eof)
+        ret = ZSTD_decompressStream(zstdfile->dstream, &zstdfile->out, &zstdfile->in);
+      if (ret == 0 && eof)
+       {
+         zstdfile->eof = 1;
+         return zstdfile->out.pos;
+       }
+      if (ZSTD_isError(ret))
+       return -1;
+      if (zstdfile->out.pos == len)
+       return len;
+    }
+}
+
+static ssize_t zstdwrite(void *cookie, const char *buf, size_t len)
+{
+  ZSTDFILE *zstdfile = cookie;
+  if (!zstdfile || !zstdfile->encoding)
+    return -1;
+  if (!len)
+    return 0;
+  zstdfile->in.src = buf;
+  zstdfile->in.pos = 0;
+  zstdfile->in.size = len;
+
+  for (;;)
+    {
+      size_t ret;
+      zstdfile->out.pos = 0;
+      ret = ZSTD_compressStream(zstdfile->cstream, &zstdfile->out, &zstdfile->in);
+      if (ZSTD_isError(ret))
+        return -1;
+      if (zstdfile->out.pos && fwrite(zstdfile->buf, 1, zstdfile->out.pos, zstdfile->file) != zstdfile->out.pos)
+        return -1;
+      if (zstdfile->in.pos == len)
+        return len;
+    }
+}
+
+static inline FILE *myzstdfopen(const char *fn, const char *mode)
+{
+  ZSTDFILE *zstdfile = zstdopen(fn, mode, -1);
+  return cookieopen(zstdfile, mode, zstdread, zstdwrite, zstdclose);
+}
+
+static inline FILE *myzstdfdopen(int fd, const char *mode)
+{
+  ZSTDFILE *zstdfile = zstdopen(0, mode, fd);
+  return cookieopen(zstdfile, mode, zstdread, zstdwrite, zstdclose);
+}
+
+#endif
+
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+
+#ifdef WITH_SYSTEM_ZCHUNK
+/* use the system's zchunk library that supports reading and writing of zchunk files */
+
+#include <zck.h>
+
+static ssize_t cookie_zckread(void *cookie, char *buf, size_t nbytes)
+{
+  return zck_read((zckCtx *)cookie, buf, nbytes);
+}
+
+static ssize_t cookie_zckwrite(void *cookie, const char *buf, size_t nbytes)
+{
+  return zck_write((zckCtx *)cookie, buf, nbytes);
+}
+
+static int cookie_zckclose(void *cookie)
+{
+  zckCtx *zck = (zckCtx *)cookie;
+  int fd = zck_get_fd(zck);
+  if (fd != -1)
+    close(fd);
+  zck_free(&zck);
+  return 0;
+}
+
+static void *zchunkopen(const char *path, const char *mode, int fd)
+{
+  zckCtx *f;
+
+  if (!path && fd < 0)
+    return 0;
+  if (fd == -1)
+    {
+      if (*mode != 'w')
+        fd = open(path, O_RDONLY);
+      else
+        fd = open(path, O_WRONLY | O_CREAT, 0666);
+      if (fd == -1)
+       return 0;
+    }
+  f = zck_create();
+  if (!f)
+    {
+      close(fd);
+      return 0;
+    }
+  if (*mode != 'w')
+    {
+      if(!zck_init_read(f, fd))
+        return 0;
+    }
+   else
+    {
+      if(!zck_init_write(f, fd))
+        return 0;
+    }
+  return cookieopen(f, mode, cookie_zckread, cookie_zckwrite, cookie_zckclose);
+}
+
+#else
+
+#include "solv_zchunk.h"
+/* use the libsolv's limited zchunk implementation that only supports reading of zchunk files */
+
+static void *zchunkopen(const char *path, const char *mode, int fd)
+{
+  FILE *fp;
+  void *f;
+  if (!path && fd < 0)
+    return 0;
+  if (fd != -1)
+    fp = fdopen(fd, mode);
+  else
+    fp = fopen(path, mode);
+  if (!fp)
+    return 0;
+  if (strcmp(mode, "r") != 0)
+    return 0;
+  f = solv_zchunk_open(fp, 1);
+  if (!f)
+    fclose(fp);
+  return cookieopen(f, mode, (ssize_t (*)(void *, char *, size_t))solv_zchunk_read, 0, (int (*)(void *))solv_zchunk_close);
+}
+
+#endif
+
+static inline FILE *myzchunkfopen(const char *fn, const char *mode)
+{
+  return zchunkopen(fn, mode, -1);
+}
+
+static inline FILE *myzchunkfdopen(int fd, const char *mode)
+{
+  return zchunkopen(0, mode, fd);
+}
+
+#endif /* ENABLE_ZCHUNK_COMPRESSION */
+
+
+FILE *
+solv_xfopen(const char *fn, const char *mode)
+{
+  char *suf;
+
+  if (!fn)
+    return 0;
+  if (!mode)
+    mode = "r";
+  suf = strrchr(fn, '.');
+#ifdef ENABLE_ZLIB_COMPRESSION
+  if (suf && !strcmp(suf, ".gz"))
+    return mygzfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".gz"))
+    return 0;
+#endif
+#ifdef ENABLE_LZMA_COMPRESSION
+  if (suf && !strcmp(suf, ".xz"))
+    return myxzfopen(fn, mode);
+  if (suf && !strcmp(suf, ".lzma"))
+    return mylzfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".xz"))
+    return 0;
+  if (suf && !strcmp(suf, ".lzma"))
+    return 0;
+#endif
+#ifdef ENABLE_BZIP2_COMPRESSION
+  if (suf && !strcmp(suf, ".bz2"))
+    return mybzfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".bz2"))
+    return 0;
+#endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+  if (suf && !strcmp(suf, ".zst"))
+    return myzstdfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".zst"))
+    return 0;
+#endif
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+  if (suf && !strcmp(suf, ".zck"))
+    return myzchunkfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".zck"))
+    return 0;
+#endif
+  return fopen(fn, mode);
+}
+
+FILE *
+solv_xfopen_fd(const char *fn, int fd, const char *mode)
+{
+  const char *simplemode = mode;
+  char *suf;
+
+  suf = fn ? strrchr(fn, '.') : 0;
+  if (!mode)
+    {
+      int fl = fcntl(fd, F_GETFL, 0);
+      if (fl == -1)
+       return 0;
+      fl &= O_RDONLY|O_WRONLY|O_RDWR;
+      if (fl == O_WRONLY)
+       mode = simplemode = "w";
+      else if (fl == O_RDWR)
+       {
+         mode = "r+";
+         simplemode = "r";
+       }
+      else
+       mode = simplemode = "r";
+    }
+#ifdef ENABLE_ZLIB_COMPRESSION
+  if (suf && !strcmp(suf, ".gz"))
+    return mygzfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".gz"))
+    return 0;
+#endif
+#ifdef ENABLE_LZMA_COMPRESSION
+  if (suf && !strcmp(suf, ".xz"))
+    return myxzfdopen(fd, simplemode);
+  if (suf && !strcmp(suf, ".lzma"))
+    return mylzfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".xz"))
+    return 0;
+  if (suf && !strcmp(suf, ".lzma"))
+    return 0;
+#endif
+#ifdef ENABLE_BZIP2_COMPRESSION
+  if (suf && !strcmp(suf, ".bz2"))
+    return mybzfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".bz2"))
+    return 0;
+#endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+  if (suf && !strcmp(suf, ".zst"))
+    return myzstdfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".zst"))
+    return 0;
+#endif
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+  if (suf && !strcmp(suf, ".zck"))
+    return myzchunkfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".zck"))
+    return 0;
+#endif
+  return fdopen(fd, mode);
+}
+
+int
+solv_xfopen_iscompressed(const char *fn)
+{
+  const char *suf = fn ? strrchr(fn, '.') : 0;
+  if (!suf)
+    return 0;
+#ifdef ENABLE_ZLIB_COMPRESSION
+  if (!strcmp(suf, ".gz"))
+    return 1;
+#else
+    return -1;
+#endif
+  if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma"))
+#ifdef ENABLE_LZMA_COMPRESSION
+    return 1;
+#else
+    return -1;
+#endif
+  if (!strcmp(suf, ".bz2"))
+#ifdef ENABLE_BZIP2_COMPRESSION
+    return 1;
+#else
+    return -1;
+#endif
+  if (!strcmp(suf, ".zst"))
+#ifdef ENABLE_ZSTD_COMPRESSION
+    return 1;
+#else
+    return -1;
+#endif
+  if (!strcmp(suf, ".zck"))
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+    return 1;
+#else
+    return -1;
+#endif
+  return 0;
+}
+
+struct bufcookie {
+  char **bufp;
+  size_t *buflp;
+  char *freemem;
+  size_t bufl_int;
+};
+
+static ssize_t cookie_bufread(void *cookie, char *buf, size_t nbytes)
+{
+  struct bufcookie *bc = cookie;
+  size_t n = *bc->buflp > nbytes ? nbytes : *bc->buflp;
+  if (n)
+    {
+      memcpy(buf, *bc->bufp, n);
+      *bc->bufp += n;
+      *bc->buflp -= n;
+    }
+  return n;
+}
+
+static ssize_t cookie_bufwrite(void *cookie, const char *buf, size_t nbytes)
+{
+  struct bufcookie *bc = cookie;
+  int n = nbytes > 0x40000000 ? 0x40000000 : nbytes;
+  if (n)
+    {
+      *bc->bufp = solv_extend(*bc->bufp, *bc->buflp, n + 1, 1, 4095);
+      memcpy(*bc->bufp, buf, n);
+      (*bc->bufp)[n] = 0;      /* zero-terminate */
+      *bc->buflp += n;
+    }
+  return n;
+}
+
+static int cookie_bufclose(void *cookie)
+{
+  struct bufcookie *bc = cookie;
+  if (bc->freemem)
+    solv_free(bc->freemem);
+  solv_free(bc);
+  return 0;
+}
+
+FILE *
+solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode)
+{
+  struct bufcookie *bc;
+  FILE *fp;
+  if (*mode != 'r' && *mode != 'w')
+    return 0;
+  bc = solv_calloc(1, sizeof(*bc));
+  bc->freemem = 0;
+  bc->bufp = bufp;
+  if (!buflp)
+    {
+      bc->bufl_int = *mode == 'w' ? 0 : strlen(*bufp);
+      buflp = &bc->bufl_int;
+    }
+  bc->buflp = buflp;
+  if (*mode == 'w')
+    {
+      *bc->bufp = solv_extend(0, 0, 1, 1, 4095);       /* always zero-terminate */
+      (*bc->bufp)[0] = 0;
+      *bc->buflp = 0;
+    }
+  fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose);
+  if (!strcmp(mode, "rf"))     /* auto-free */
+    bc->freemem = *bufp;
+  if (!fp)
+    {
+      if (*mode == 'w')
+       *bc->bufp = solv_free(*bc->bufp);
+      cookie_bufclose(bc);
+    }
+  return fp;
+}
diff --git a/libsolv-0.7.2/ext/solv_xfopen.h b/libsolv-0.7.2/ext/solv_xfopen.h
new file mode 100644 (file)
index 0000000..aa8740e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2009-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef SOLV_XFOPEN_H
+#define SOLV_XFOPEN_H
+
+extern FILE *solv_xfopen(const char *fn, const char *mode);
+extern FILE *solv_xfopen_fd(const char *fn, int fd, const char *mode);
+extern FILE *solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode);
+extern int   solv_xfopen_iscompressed(const char *fn);
+
+#endif
diff --git a/libsolv-0.7.2/ext/solv_xmlparser.c b/libsolv-0.7.2/ext/solv_xmlparser.c
new file mode 100644 (file)
index 0000000..6292663
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * solv_xmlparser.c
+ *
+ * XML parser abstraction
+ *
+ * Copyright (c) 2017, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WITH_LIBXML2
+#include <libxml/parser.h>
+#else
+#include <expat.h>
+#endif
+
+#include "util.h"
+#include "queue.h"
+#include "solv_xmlparser.h"
+
+static inline void
+add_contentspace(struct solv_xmlparser *xmlp, int l)
+{
+  l += xmlp->lcontent + 1;     /* plus room for trailing zero */
+  if (l > xmlp->acontent)
+    {    
+      xmlp->acontent = l + 256; 
+      xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
+    }    
+}
+
+
+#ifdef WITH_LIBXML2
+static void
+character_data(void *userData, const xmlChar *s, int len)
+#else
+static void XMLCALL
+character_data(void *userData, const XML_Char *s, int len) 
+#endif
+{
+  struct solv_xmlparser *xmlp = userData;
+
+  if (!xmlp->docontent || !len)
+    return;
+  add_contentspace(xmlp, len);
+  memcpy(xmlp->content + xmlp->lcontent, s, len);
+  xmlp->lcontent += len; 
+}
+
+#ifdef WITH_LIBXML2
+static void
+start_element(void *userData, const xmlChar *name, const xmlChar **atts)
+#else
+static void XMLCALL
+start_element(void *userData, const char *name, const char **atts)
+#endif
+{
+  struct solv_xmlparser *xmlp = userData;
+  struct solv_xmlparser_element *elements;
+  Id *elementhelper;
+  struct solv_xmlparser_element *el;
+  int i, oldstate;
+
+  if (xmlp->unknowncnt)
+    {
+      xmlp->unknowncnt++;
+      return;
+    }
+  elementhelper = xmlp->elementhelper;
+  elements = xmlp->elements;
+  oldstate = xmlp->state;
+  for (i = elementhelper[xmlp->nelements + oldstate]; i; i = elementhelper[i - 1])
+    if (!strcmp(elements[i - 1].element, (char *)name))
+      break;
+  if (!i)
+    {
+#if 0
+      fprintf(stderr, "into unknown: %s\n", name);
+#endif
+      xmlp->unknowncnt++;
+      return;
+    }
+  el = xmlp->elements + i - 1;
+  queue_push(&xmlp->elementq, xmlp->state);
+  xmlp->state = el->tostate;
+  xmlp->docontent = el->docontent;
+  xmlp->lcontent = 0;
+#ifdef WITH_LIBXML2
+  if (!atts)
+    {
+      static const char *nullattr;
+      atts = (const xmlChar **)&nullattr;
+    }
+#endif
+  if (xmlp->state != oldstate)
+    xmlp->startelement(xmlp, xmlp->state, el->element, (const char **)atts);
+}
+
+#ifdef WITH_LIBXML2
+static void
+end_element(void *userData, const xmlChar *name)
+#else
+static void XMLCALL
+end_element(void *userData, const char *name)
+#endif
+{
+  struct solv_xmlparser *xmlp = userData;
+
+  if (xmlp->unknowncnt)
+    {
+      xmlp->unknowncnt--;
+      xmlp->lcontent = 0;
+      xmlp->docontent = 0;
+      return;
+    }
+  xmlp->content[xmlp->lcontent] = 0;
+  if (xmlp->elementq.count && xmlp->state != xmlp->elementq.elements[xmlp->elementq.count - 1])
+    xmlp->endelement(xmlp, xmlp->state, xmlp->content);
+  xmlp->state = queue_pop(&xmlp->elementq);
+  xmlp->docontent = 0;
+  xmlp->lcontent = 0;
+}
+
+void
+solv_xmlparser_init(struct solv_xmlparser *xmlp,
+    struct solv_xmlparser_element *elements,
+    void *userdata,
+    void (*startelement)(struct solv_xmlparser *, int state, const char *name, const char **atts),
+    void (*endelement)(struct solv_xmlparser *, int state, char *content))
+{
+  int i, nstates, nelements;
+  struct solv_xmlparser_element *el;
+  Id *elementhelper;
+
+  memset(xmlp, 0, sizeof(*xmlp));
+  nstates = 0;
+  nelements = 0;
+  for (el = elements; el->element; el++)
+    {
+      nelements++;
+      if (el->fromstate > nstates)
+       nstates = el->fromstate;
+      if (el->tostate > nstates)
+       nstates = el->tostate;
+    }
+  nstates++;
+
+  xmlp->elements = elements;
+  xmlp->nelements = nelements;
+  elementhelper = solv_calloc(nelements + nstates, sizeof(Id));
+  for (i = nelements - 1; i >= 0; i--)
+    {
+      int fromstate = elements[i].fromstate;
+      elementhelper[i] = elementhelper[nelements + fromstate];
+      elementhelper[nelements + fromstate] = i + 1;
+    }
+  xmlp->elementhelper = elementhelper;
+  queue_init(&xmlp->elementq);
+  xmlp->acontent = 256;
+  xmlp->content = solv_malloc(xmlp->acontent);
+
+  xmlp->userdata = userdata;
+  xmlp->startelement = startelement;
+  xmlp->endelement = endelement;
+}
+
+void
+solv_xmlparser_free(struct solv_xmlparser *xmlp)
+{
+  xmlp->elementhelper = solv_free(xmlp->elementhelper);
+  queue_free(&xmlp->elementq);
+  xmlp->content = solv_free(xmlp->content);
+  xmlp->errstr = solv_free(xmlp->errstr);
+}
+
+static void
+set_error(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
+{
+  solv_free(xmlp->errstr);
+  xmlp->errstr = solv_strdup(errstr);
+  xmlp->line = line;
+  xmlp->column = column;
+}
+
+#ifdef WITH_LIBXML2
+
+static inline int
+create_parser(struct solv_xmlparser *xmlp)
+{
+  /* delayed to parse_block so that we have the first bytes */
+  return 1;
+}
+
+static inline void
+free_parser(struct solv_xmlparser *xmlp)
+{
+  if (xmlp->parser)
+    xmlFreeParserCtxt(xmlp->parser);
+  xmlp->parser = 0;
+}
+
+static xmlParserCtxtPtr
+create_parser_ctx(struct solv_xmlparser *xmlp, char *buf, int l)
+{
+  xmlSAXHandler sax;
+  memset(&sax, 0, sizeof(sax));
+  sax.startElement = start_element;
+  sax.endElement = end_element;
+  sax.characters = character_data;
+  return xmlCreatePushParserCtxt(&sax, xmlp, buf, l, NULL);
+}
+
+static inline int
+parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
+{
+  if (!xmlp->parser)
+    {
+      int l2 = l > 4 ? 4 : 0;
+      xmlp->parser = create_parser_ctx(xmlp, buf, l2);
+      if (!xmlp->parser)
+       {
+         set_error(xmlp, "could not create parser", 0, 0);
+         return 0;
+       }
+      buf += l2;
+      l -= l2;
+      if (l2 && !l)
+       return 1;
+    }
+  if (xmlParseChunk(xmlp->parser, buf, l, l == 0 ? 1 : 0))
+    {
+      xmlErrorPtr err = xmlCtxtGetLastError(xmlp->parser);
+      set_error(xmlp, err->message, err->line, err->int2);
+      return 0;
+    }
+  return 1;
+}
+
+unsigned int
+solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
+{
+  return (unsigned int)xmlSAX2GetLineNumber(xmlp->parser);
+}
+
+#else
+
+static inline int
+create_parser(struct solv_xmlparser *xmlp)
+{
+  xmlp->parser = XML_ParserCreate(NULL);
+  if (!xmlp->parser)
+    return 0;
+  XML_SetUserData(xmlp->parser, xmlp);
+  XML_SetElementHandler(xmlp->parser, start_element, end_element);
+  XML_SetCharacterDataHandler(xmlp->parser, character_data);
+  return 1;
+}
+
+static inline void
+free_parser(struct solv_xmlparser *xmlp)
+{
+  XML_ParserFree(xmlp->parser);
+  xmlp->parser = 0;
+}
+
+static inline int
+parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
+{
+  if (XML_Parse(xmlp->parser, buf, l, l == 0) == XML_STATUS_ERROR)
+    {
+      set_error(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), XML_GetCurrentLineNumber(xmlp->parser), XML_GetCurrentColumnNumber(xmlp->parser));
+      return 0;
+    }
+  return 1;
+}
+
+unsigned int
+solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
+{
+  return (unsigned int)XML_GetCurrentLineNumber(xmlp->parser);
+}
+
+#endif
+
+int
+solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp)
+{
+  char buf[8192];
+  int l, ret = SOLV_XMLPARSER_OK;
+
+  xmlp->state = 0;
+  xmlp->unknowncnt = 0;
+  xmlp->docontent = 0;
+  xmlp->lcontent = 0;
+  queue_empty(&xmlp->elementq);
+
+  if (!create_parser(xmlp))
+    {
+      set_error(xmlp, "could not create parser", 0, 0);
+      return SOLV_XMLPARSER_ERROR;
+    }
+  for (;;)
+    {
+      l = fread(buf, 1, sizeof(buf), fp);
+      if (!parse_block(xmlp, buf, l))
+       {
+         ret = SOLV_XMLPARSER_ERROR;
+         break;
+       }
+      if (!l)
+       break;
+    }
+  free_parser(xmlp);
+  return ret;
+}
+
+char *
+solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l)
+{
+  xmlp->lcontent = 0;
+  if (l > xmlp->acontent)
+    {    
+      xmlp->acontent = l + 256; 
+      xmlp->content = solv_realloc(xmlp->content, xmlp->acontent);
+    }    
+  return xmlp->content;
+}
+
diff --git a/libsolv-0.7.2/ext/solv_xmlparser.h b/libsolv-0.7.2/ext/solv_xmlparser.h
new file mode 100644 (file)
index 0000000..ced0571
--- /dev/null
@@ -0,0 +1,56 @@
+
+struct solv_xmlparser_element {
+  int fromstate;
+  char *element;
+  int tostate;
+  int docontent;
+};
+
+struct solv_xmlparser {
+  void *userdata;
+  char *errstr;
+  unsigned int line;
+  unsigned int column;
+
+  int state;
+  int docontent;
+
+  Queue elementq;
+  int unknowncnt;
+
+  char *content;
+  int lcontent;                /* current content length */
+  int acontent;                /* allocated content length */
+
+  struct solv_xmlparser_element *elements;
+  int nelements;
+
+  void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts);
+  void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content);
+
+  Id *elementhelper;
+  void *parser;
+};
+
+#define SOLV_XMLPARSER_OK      0
+#define SOLV_XMLPARSER_ERROR   -1
+
+static inline const char *
+solv_xmlparser_find_attr(const char *txt, const char **atts)
+{
+  for (; *atts; atts += 2)
+    if (!strcmp(*atts, txt))
+      return atts[1];
+  return 0;
+}
+
+extern void solv_xmlparser_init(struct solv_xmlparser *xmlp, struct solv_xmlparser_element *elements, void *userdata,
+    void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts),
+    void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content));
+
+extern void solv_xmlparser_free(struct solv_xmlparser *xmlp);
+extern int solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp);
+unsigned int solv_xmlparser_lineno(struct solv_xmlparser *xmlp);
+char *solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l);
+
+
diff --git a/libsolv-0.7.2/ext/solv_zchunk.c b/libsolv-0.7.2/ext/solv_zchunk.c
new file mode 100644 (file)
index 0000000..0833445
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <zstd.h>
+
+#include "chksum.h"
+#include "util.h"
+#include "solv_zchunk.h"
+
+#define MAX_HDR_SIZE  0xffffff00
+#define MAX_CHUNK_CNT 0x0fffffff
+
+#undef VERIFY_DATA_CHKSUM
+
+struct solv_zchunk {
+  FILE *fp;
+  unsigned char *hdr;
+  unsigned char *hdr_end;
+
+  unsigned int flags;  /* header flags */
+  unsigned int comp;   /* compression type */
+
+  unsigned int hdr_chk_type;   /* header + data checksum */
+  unsigned int hdr_chk_len;
+  Id hdr_chk_id;
+
+  unsigned int chunk_chk_type; /* chunk checksum */
+  unsigned int chunk_chk_len;
+  Id chunk_chk_id;
+
+  Chksum *data_chk;    /* for data checksum verification */
+  unsigned char *data_chk_ptr;
+
+  unsigned int streamid;       /* stream we are reading */
+  unsigned int nchunks;                /* chunks left */
+  unsigned char *chunks;
+
+  ZSTD_DCtx *dctx;
+  ZSTD_DDict *ddict;
+
+  int eof;
+  unsigned char *buf;
+  unsigned int buf_used;
+  unsigned int buf_avail;
+};
+
+/* return 32bit compressed integer. returns NULL on overflow. */
+static unsigned char *
+getuint(unsigned char *p, unsigned char *endp, unsigned int *dp)
+{
+  if (!p || p >= endp)
+    return 0;
+  if (p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[0] ^ 0x80;
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[-1] ^ ((p[0] ^ 0x80) << 7);
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[-2] ^ (p[-1] << 7) ^ ((p[0] ^ 0x80) << 14);
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[-3] ^ (p[-2] << 7) ^ (p[1] << 14) ^ ((p[0] ^ 0x80) << 21);
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0xf0) == 0x80)
+    {
+      *dp = p[-4] ^ (p[-3] << 7) ^ (p[2] << 14) ^ (p[1] << 21) ^ ((p[0] ^ 0x80) << 28);
+      return p + 1;
+    }
+  return 0;
+}
+
+static unsigned char *
+getchksum(unsigned char *p, unsigned char *endp, unsigned int *typep, unsigned int *lenp, Id *idp)
+{
+  if ((p = getuint(p, endp, typep)) == 0)
+    return 0;
+  switch (*typep)
+    {
+    case 0:
+      *lenp = 20;
+      *idp = REPOKEY_TYPE_SHA1;
+      return p;
+    case 1:
+      *lenp = 32;
+      *idp = REPOKEY_TYPE_SHA256;
+      return p;
+    case 2:
+      *lenp = 64;
+      *idp = REPOKEY_TYPE_SHA512;
+      return p;
+    case 3:
+      *lenp = 16;
+      *idp = REPOKEY_TYPE_SHA512;
+      return p;
+    default:
+      break;
+    }
+  return 0;
+}
+
+static int
+skip_bytes(FILE *fp, size_t skip, Chksum *chk)
+{
+  unsigned char buf[4096];
+  while (skip)
+    {
+      size_t bite = skip > sizeof(buf) ? sizeof(buf) : skip;
+      if (fread(buf, bite, 1, fp) != 1)
+       return 0;
+      if (chk)
+       solv_chksum_add(chk, buf, bite);
+      skip -= bite;
+    }
+  return 1;
+}
+
+static int
+nextchunk(struct solv_zchunk *zck, unsigned int streamid)
+{
+  unsigned char *p = zck->chunks;
+  unsigned char *chunk_chk_ptr;
+  unsigned int sid, chunk_len, uncompressed_len;
+  unsigned char *cbuf;
+
+  /* free old buffer */
+  zck->buf = solv_free(zck->buf);
+  zck->buf_avail = 0;
+  zck->buf_used = 0;
+
+  for (;;)
+    {
+      if (zck->nchunks == 0)
+       {
+         zck->chunks = p;
+         return 1;             /* EOF reached */
+       }
+      if (p >= zck->hdr_end)
+       return 0;
+      sid = streamid ? 1 : 0;
+      /* check if this is the correct stream */
+      if ((zck->flags & 1) != 0 && (p = getuint(p, zck->hdr_end, &sid)) == 0)
+       return 0;
+      chunk_chk_ptr = p;       /* remember for verification */
+      p += zck->chunk_chk_len;
+      if (p >= zck->hdr_end)
+       return 0;
+      if ((p = getuint(p, zck->hdr_end, &chunk_len)) == 0)
+       return 0;
+      if ((p = getuint(p, zck->hdr_end, &uncompressed_len)) == 0)
+       return 0;
+      zck->nchunks--;
+      if (sid == streamid)
+       break;
+      /* skip the chunk, but the dict chunk must come first */
+      if (streamid == 0 || skip_bytes(zck->fp, chunk_len, zck->data_chk) == 0)
+       return 0;
+    }
+  zck->chunks = p;
+
+  /* ok, read the compressed chunk */
+  if (!chunk_len)
+    return uncompressed_len ? 0 : 1;
+  cbuf = solv_malloc(chunk_len);
+  if (fread(cbuf, chunk_len, 1, zck->fp) != 1)
+    {
+      solv_free(cbuf);
+      return 0;
+    }
+  if (zck->data_chk)
+    solv_chksum_add(zck->data_chk, cbuf, chunk_len);
+
+  /* verify the chunk checksum */
+  if (zck->chunk_chk_id)
+    {
+      Chksum *chk = solv_chksum_create(zck->chunk_chk_id);
+      if (!chk)
+       {
+         solv_free(cbuf);
+         return 0;
+       }
+      solv_chksum_add(chk, cbuf, chunk_len);
+      if (memcmp(solv_chksum_get(chk, 0), chunk_chk_ptr, zck->chunk_chk_len) != 0)
+       {
+         solv_chksum_free(chk, 0);
+         solv_free(cbuf);
+         return 0;
+       }
+      solv_chksum_free(chk, 0);
+    }
+
+  /* uncompress */
+  if (zck->comp == 0)
+    {
+      /* not compressed */
+      if (chunk_len != uncompressed_len)
+       {
+         solv_free(cbuf);
+         return 0;
+       }
+      zck->buf = cbuf;
+      zck->buf_avail = uncompressed_len;
+      return 1;
+    }
+  if (zck->comp == 2)
+    {
+      /* zstd compressed */
+      size_t r;
+      zck->buf = solv_malloc(uncompressed_len + 1);    /* +1 so we can detect too large frames */
+      if (zck->ddict)
+       r = ZSTD_decompress_usingDDict(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len, zck->ddict);
+      else
+       r = ZSTD_decompressDCtx(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len);
+      solv_free(cbuf);
+      if (r != uncompressed_len)
+       return 0;
+      zck->buf_avail = uncompressed_len;
+      return 1;
+    }
+  solv_free(cbuf);
+  return 0;
+}
+
+static inline struct solv_zchunk *
+open_error(struct solv_zchunk *zck)
+{
+  solv_zchunk_close(zck);
+  return 0;
+}
+
+struct solv_zchunk *
+solv_zchunk_open(FILE *fp, unsigned int streamid)
+{
+  struct solv_zchunk *zck;
+  unsigned char *p;
+  unsigned int hdr_size;       /* preface + index + signatures */
+  unsigned int lead_size;
+  unsigned int preface_size;
+  unsigned int index_size;
+
+  zck = solv_calloc(1, sizeof(*zck));
+
+  /* read and parse the lead, read the complete header */
+  zck->hdr = solv_calloc(15, 1);
+  zck->hdr_end = zck->hdr + 15;
+  if (fread(zck->hdr, 15, 1, fp) != 1 || memcmp(zck->hdr, "\000ZCK1", 5) != 0)
+    return open_error(zck);
+  p = zck->hdr + 5;
+  if ((p = getchksum(p, zck->hdr_end, &zck->hdr_chk_type, &zck->hdr_chk_len, &zck->hdr_chk_id)) == 0)
+    return open_error(zck);
+  if ((p = getuint(p, zck->hdr_end, &hdr_size)) == 0 || hdr_size > MAX_HDR_SIZE)
+    return open_error(zck);
+  lead_size = p - zck->hdr + zck->hdr_chk_len;
+  zck->hdr = solv_realloc(zck->hdr, lead_size + hdr_size);
+  zck->hdr_end = zck->hdr + lead_size + hdr_size;
+  if (fread(zck->hdr + 15, lead_size + hdr_size - 15, 1, fp) != 1)
+    return open_error(zck);
+
+  /* verify header checksum to guard against corrupt files */
+  if (zck->hdr_chk_id)
+    {
+      Chksum *chk = solv_chksum_create(zck->hdr_chk_id);
+      if (!chk)
+       return open_error(zck);
+      solv_chksum_add(chk, zck->hdr, lead_size - zck->hdr_chk_len);
+      solv_chksum_add(chk, zck->hdr + lead_size, hdr_size);
+      if (memcmp(solv_chksum_get(chk, 0), zck->hdr + (lead_size - zck->hdr_chk_len), zck->hdr_chk_len) != 0)
+       {
+         solv_chksum_free(chk, 0);
+         return open_error(zck);
+       }
+      solv_chksum_free(chk, 0);
+    }
+
+  /* parse preface: data chksum, flags, compression */
+  p = zck->hdr + lead_size;
+  if (p + zck->hdr_chk_len > zck->hdr_end)
+    return open_error(zck);
+  zck->data_chk_ptr = p;
+  p += zck->hdr_chk_len;
+#ifdef VERIFY_DATA_CHKSUM
+  if (zck->hdr_chk_id && (zck->data_chk = solv_chksum_create(zck->hdr_chk_id)) == 0)
+    return open_error(zck);
+#endif
+  if ((p = getuint(p, zck->hdr_end, &zck->flags)) == 0)
+    return open_error(zck);
+  if ((zck->flags & ~(1)) != 0)
+    return open_error(zck);
+  if ((p = getuint(p, zck->hdr_end, &zck->comp)) == 0 || (zck->comp != 0 && zck->comp != 2))
+    return open_error(zck);    /* only uncompressed + zstd supported */
+  preface_size = p - (zck->hdr + lead_size);
+
+  /* parse index: index size, index chksum type, num chunks, chunk data  */
+  if ((p = getuint(p, zck->hdr_end, &index_size)) == 0)
+    return open_error(zck);
+  if (hdr_size < preface_size + index_size)
+    return open_error(zck);
+  if ((p = getchksum(p, zck->hdr_end, &zck->chunk_chk_type, &zck->chunk_chk_len, &zck->chunk_chk_id)) == 0)
+    return open_error(zck);
+  if ((p = getuint(p, zck->hdr_end, &zck->nchunks)) == 0 || zck->nchunks > MAX_CHUNK_CNT)
+    return open_error(zck);
+
+  /* setup decompressor */
+  if (zck->comp == 2)
+    {
+      if ((zck->dctx = ZSTD_createDCtx()) == 0)
+       return open_error(zck);
+    }
+
+  zck->fp = fp;
+  zck->chunks = p;
+  zck->streamid = streamid;
+  if (streamid == 0)
+    {
+      zck->nchunks = zck->nchunks ? 1 : 0;     /* limit to dict chunk */
+      return zck;      
+    }
+
+  /* setup dictionary */
+  if (!nextchunk(zck, 0))
+    {
+      zck->fp = 0;
+      return open_error(zck);
+    }
+  if (zck->comp == 2 && zck->buf_avail)
+    {
+      if ((zck->ddict = ZSTD_createDDict(zck->buf, zck->buf_avail)) == 0)
+       {
+         zck->fp = 0;
+         return open_error(zck);
+       }
+    }
+  zck->buf = solv_free(zck->buf);
+  zck->buf_used = 0;
+  zck->buf_avail = 0;
+
+  /* ready to read the rest of the chunks */
+  return zck;
+}
+
+ssize_t
+solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len)
+{
+  size_t n = 0;
+  if (!zck || zck->eof == 2)
+    return -1;
+  while (n < len && !zck->eof)
+    {
+      unsigned int bite;
+      while (!zck->buf_avail)
+       {
+         if (!zck->nchunks)
+           {
+             /* verify data checksum if requested */
+             if (zck->streamid != 0 && zck->data_chk && memcmp(solv_chksum_get(zck->data_chk, 0), zck->data_chk_ptr, zck->hdr_chk_len) != 0) {
+               zck->eof = 2;
+               return -1;
+             }
+             zck->eof = 1;
+             return n;
+           }
+         if (!nextchunk(zck, zck->streamid))
+           {
+             zck->eof = 2;
+             return -1;
+           }
+       }
+      bite = len - n > zck->buf_avail ? zck->buf_avail : len - n;
+      memcpy(buf + n, zck->buf + zck->buf_used, bite);
+      n += bite;
+      zck->buf_used += bite;
+      zck->buf_avail -= bite;
+    }
+  return n;
+}
+
+int
+solv_zchunk_close(struct solv_zchunk *zck)
+{
+  if (zck->data_chk)
+    solv_chksum_free(zck->data_chk, 0);
+  if (zck->ddict)
+    ZSTD_freeDDict(zck->ddict);
+  if (zck->dctx)
+    ZSTD_freeDCtx(zck->dctx);
+  solv_free(zck->hdr);
+  solv_free(zck->buf);
+  if (zck->fp)
+    fclose(zck->fp);
+  solv_free(zck);
+  return 0;
+}
diff --git a/libsolv-0.7.2/ext/solv_zchunk.h b/libsolv-0.7.2/ext/solv_zchunk.h
new file mode 100644 (file)
index 0000000..9d73486
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+struct solv_zchunk;
+
+extern struct solv_zchunk *solv_zchunk_open(FILE *fp, unsigned int streamid);
+extern ssize_t solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len);
+extern int solv_zchunk_close(struct solv_zchunk *zck);
+
diff --git a/libsolv-0.7.2/ext/testcase.c b/libsolv-0.7.2/ext/testcase.c
new file mode 100644 (file)
index 0000000..b815c56
--- /dev/null
@@ -0,0 +1,3034 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "poolarch.h"
+#include "poolvendor.h"
+#include "evr.h"
+#include "repo.h"
+#include "repo_solv.h"
+#include "solver.h"
+#include "solverdebug.h"
+#include "chksum.h"
+#include "testcase.h"
+#include "selection.h"
+#include "solv_xfopen.h"
+#if ENABLE_TESTCASE_HELIXREPO
+#include "ext/repo_helix.h"
+#endif
+
+#define DISABLE_JOIN2
+#include "tools_util.h"
+
+static struct job2str {
+  Id job;
+  const char *str;
+} job2str[] = {
+  { SOLVER_NOOP,           "noop" },
+  { SOLVER_INSTALL,        "install" },
+  { SOLVER_ERASE,          "erase" },
+  { SOLVER_UPDATE,         "update" },
+  { SOLVER_WEAKENDEPS,     "weakendeps" },
+  { SOLVER_MULTIVERSION,   "multiversion" },
+  { SOLVER_MULTIVERSION,   "noobsoletes" },    /* old name */
+  { SOLVER_LOCK,           "lock" },
+  { SOLVER_DISTUPGRADE,    "distupgrade" },
+  { SOLVER_VERIFY,         "verify" },
+  { SOLVER_DROP_ORPHANED,  "droporphaned" },
+  { SOLVER_USERINSTALLED,  "userinstalled" },
+  { SOLVER_ALLOWUNINSTALL, "allowuninstall" },
+  { SOLVER_FAVOR,          "favor" },
+  { SOLVER_DISFAVOR,       "disfavor" },
+  { 0, 0 }
+};
+
+static struct jobflags2str {
+  Id flag;
+  const char *str;
+} jobflags2str[] = {
+  { SOLVER_WEAK,      "weak" },
+  { SOLVER_ESSENTIAL, "essential" },
+  { SOLVER_CLEANDEPS, "cleandeps" },
+  { SOLVER_ORUPDATE,  "orupdate" },
+  { SOLVER_FORCEBEST, "forcebest" },
+  { SOLVER_TARGETED,  "targeted" },
+  { SOLVER_NOTBYUSER, "notbyuser" },
+  { SOLVER_SETEV,     "setev" },
+  { SOLVER_SETEVR,    "setevr" },
+  { SOLVER_SETARCH,   "setarch" },
+  { SOLVER_SETVENDOR, "setvendor" },
+  { SOLVER_SETREPO,   "setrepo" },
+  { SOLVER_NOAUTOSET, "noautoset" },
+  { 0, 0 }
+};
+
+static struct resultflags2str {
+  Id flag;
+  const char *str;
+} resultflags2str[] = {
+  { TESTCASE_RESULT_TRANSACTION,       "transaction" },
+  { TESTCASE_RESULT_PROBLEMS,          "problems" },
+  { TESTCASE_RESULT_ORPHANED,          "orphaned" },
+  { TESTCASE_RESULT_RECOMMENDED,       "recommended" },
+  { TESTCASE_RESULT_UNNEEDED,          "unneeded" },
+  { TESTCASE_RESULT_ALTERNATIVES,      "alternatives" },
+  { TESTCASE_RESULT_RULES,             "rules" },
+  { TESTCASE_RESULT_GENID,             "genid" },
+  { TESTCASE_RESULT_REASON,            "reason" },
+  { TESTCASE_RESULT_CLEANDEPS,         "cleandeps" },
+  { TESTCASE_RESULT_JOBS,              "jobs" },
+  { 0, 0 }
+};
+
+static struct solverflags2str {
+  Id flag;
+  const char *str;
+  int def;
+} solverflags2str[] = {
+  { SOLVER_FLAG_ALLOW_DOWNGRADE,            "allowdowngrade", 0 },
+  { SOLVER_FLAG_ALLOW_NAMECHANGE,           "allownamechange", 1 },
+  { SOLVER_FLAG_ALLOW_ARCHCHANGE,           "allowarchchange", 0 },
+  { SOLVER_FLAG_ALLOW_VENDORCHANGE,         "allowvendorchange", 0 },
+  { SOLVER_FLAG_ALLOW_UNINSTALL,            "allowuninstall", 0 },
+  { SOLVER_FLAG_NO_UPDATEPROVIDE,           "noupdateprovide", 0 },
+  { SOLVER_FLAG_SPLITPROVIDES,              "splitprovides", 0 },
+  { SOLVER_FLAG_IGNORE_RECOMMENDED,         "ignorerecommended", 0 },
+  { SOLVER_FLAG_ADD_ALREADY_RECOMMENDED,    "addalreadyrecommended", 0 },
+  { SOLVER_FLAG_NO_INFARCHCHECK,            "noinfarchcheck", 0 },
+  { SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES,    "keepexplicitobsoletes", 0 },
+  { SOLVER_FLAG_BEST_OBEY_POLICY,           "bestobeypolicy", 0 },
+  { SOLVER_FLAG_NO_AUTOTARGET,              "noautotarget", 0 },
+  { SOLVER_FLAG_DUP_ALLOW_DOWNGRADE,        "dupallowdowngrade", 1 },
+  { SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE,       "dupallowarchchange", 1 },
+  { SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE,     "dupallowvendorchange", 1 },
+  { SOLVER_FLAG_DUP_ALLOW_NAMECHANGE,       "dupallownamechange", 1 },
+  { SOLVER_FLAG_KEEP_ORPHANS,               "keeporphans", 0 },
+  { SOLVER_FLAG_BREAK_ORPHANS,              "breakorphans", 0 },
+  { SOLVER_FLAG_FOCUS_INSTALLED,            "focusinstalled", 0 },
+  { SOLVER_FLAG_YUM_OBSOLETES,              "yumobsoletes", 0 },
+  { SOLVER_FLAG_NEED_UPDATEPROVIDE,         "needupdateprovide", 0 },
+  { SOLVER_FLAG_URPM_REORDER,               "urpmreorder", 0 },
+  { SOLVER_FLAG_FOCUS_BEST,                 "focusbest", 0 },
+  { SOLVER_FLAG_STRONG_RECOMMENDS,          "strongrecommends", 0 },
+  { SOLVER_FLAG_INSTALL_ALSO_UPDATES,       "installalsoupdates", 0 },
+  { SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED, "onlynamespacerecommended", 0 },
+  { 0, 0, 0 }
+};
+
+static struct poolflags2str {
+  Id flag;
+  const char *str;
+  int def;
+} poolflags2str[] = {
+  { POOL_FLAG_PROMOTEEPOCH,                 "promoteepoch", 0 },
+  { POOL_FLAG_FORBIDSELFCONFLICTS,          "forbidselfconflicts", 0 },
+  { POOL_FLAG_OBSOLETEUSESPROVIDES,         "obsoleteusesprovides", 0 },
+  { POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES, "implicitobsoleteusesprovides", 0 },
+  { POOL_FLAG_OBSOLETEUSESCOLORS,           "obsoleteusescolors", 0 },
+  { POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS,   "implicitobsoleteusescolors", 0 },
+  { POOL_FLAG_NOINSTALLEDOBSOLETES,         "noinstalledobsoletes", 0 },
+  { POOL_FLAG_HAVEDISTEPOCH,                "havedistepoch", 0 },
+  { POOL_FLAG_NOOBSOLETESMULTIVERSION,      "noobsoletesmultiversion", 0 },
+  { POOL_FLAG_ADDFILEPROVIDESFILTERED,      "addfileprovidesfiltered", 0 },
+  { POOL_FLAG_NOWHATPROVIDESAUX,            "nowhatprovidesaux", 0 },
+  { 0, 0, 0 }
+};
+
+static struct disttype2str {
+  Id type;
+  const char *str;
+} disttype2str[] = {
+  { DISTTYPE_RPM,  "rpm" },
+  { DISTTYPE_DEB,  "deb" },
+  { DISTTYPE_ARCH, "arch" },
+  { DISTTYPE_HAIKU, "haiku" },
+  { 0, 0 }
+};
+
+static struct selflags2str {
+  Id flag;
+  const char *str;
+} selflags2str[] = {
+  { SELECTION_NAME, "name" },
+  { SELECTION_PROVIDES, "provides" },
+  { SELECTION_FILELIST, "filelist" },
+  { SELECTION_CANON, "canon" },
+  { SELECTION_DOTARCH, "dotarch" },
+  { SELECTION_REL, "rel" },
+  { SELECTION_INSTALLED_ONLY, "installedonly" },
+  { SELECTION_GLOB, "glob" },
+  { SELECTION_FLAT, "flat" },
+  { SELECTION_NOCASE, "nocase" },
+  { SELECTION_SOURCE_ONLY, "sourceonly" },
+  { SELECTION_WITH_SOURCE, "withsource" },
+  { SELECTION_SKIP_KIND, "skipkind" },
+  { SELECTION_MATCH_DEPSTR, "depstr" },
+  { SELECTION_WITH_DISABLED, "withdisabled" },
+  { SELECTION_WITH_BADARCH, "withbadarch" },
+  { SELECTION_ADD, "add" },
+  { SELECTION_SUBTRACT, "subtract" },
+  { SELECTION_FILTER, "filter" },
+  { 0, 0 }
+};
+
+static const char *features[] = {
+#ifdef ENABLE_LINKED_PKGS
+  "linked_packages",
+#endif
+#ifdef ENABLE_COMPLEX_DEPS
+  "complex_deps",
+#endif
+#if ENABLE_TESTCASE_HELIXREPO
+  "testcase_helixrepo",
+#endif
+  0
+};
+
+typedef struct strqueue {
+  char **str;
+  int nstr;
+} Strqueue;
+
+#define STRQUEUE_BLOCK 63
+
+static void
+strqueue_init(Strqueue *q)
+{
+  q->str = 0;
+  q->nstr = 0;
+}
+
+static void
+strqueue_free(Strqueue *q)
+{
+  int i;
+  for (i = 0; i < q->nstr; i++)
+    solv_free(q->str[i]);
+  q->str = solv_free(q->str);
+  q->nstr = 0;
+}
+
+static void
+strqueue_push(Strqueue *q, const char *s)
+{
+  q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK);
+  q->str[q->nstr++] = solv_strdup(s);
+}
+
+static void
+strqueue_pushjoin(Strqueue *q, const char *s1, const char *s2, const char *s3)
+{
+  q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK);
+  q->str[q->nstr++] = solv_dupjoin(s1, s2, s3);
+}
+
+static int
+strqueue_sort_cmp(const void *ap, const void *bp, void *dp)
+{
+  const char *a = *(const char **)ap;
+  const char *b = *(const char **)bp;
+  return strcmp(a ? a : "", b ? b : "");
+}
+
+static void
+strqueue_sort(Strqueue *q)
+{
+  if (q->nstr > 1)
+    solv_sort(q->str, q->nstr, sizeof(*q->str), strqueue_sort_cmp, 0);
+}
+
+static void
+strqueue_sort_u(Strqueue *q)
+{
+  int i, j;
+  strqueue_sort(q);
+  for (i = j = 0; i < q->nstr; i++)
+    if (!j || strqueue_sort_cmp(q->str + i, q->str + j - 1, 0) != 0)
+      q->str[j++] = q->str[i];
+  q->nstr = j;
+}
+
+static char *
+strqueue_join(Strqueue *q)
+{
+  int i, l = 0;
+  char *r, *rp;
+  for (i = 0; i < q->nstr; i++)
+    if (q->str[i])
+      l += strlen(q->str[i]) + 1;
+  l++; /* trailing \0 */
+  r = solv_malloc(l);
+  rp = r;
+  for (i = 0; i < q->nstr; i++)
+    if (q->str[i])
+      {
+        strcpy(rp, q->str[i]);
+        rp += strlen(rp);
+       *rp++ = '\n';
+      }
+  *rp = 0;
+  return r;
+}
+
+static void
+strqueue_split(Strqueue *q, const char *s)
+{
+  const char *p;
+  if (!s)
+    return;
+  while ((p = strchr(s, '\n')) != 0)
+    {
+      q->str = solv_extend(q->str, q->nstr, 1, sizeof(*q->str), STRQUEUE_BLOCK);
+      q->str[q->nstr] = solv_malloc(p - s + 1);
+      if (p > s)
+       memcpy(q->str[q->nstr], s, p - s);
+      q->str[q->nstr][p - s] = 0;
+      q->nstr++;
+      s = p + 1;
+    }
+  if (*s)
+    strqueue_push(q, s);
+}
+
+static void
+strqueue_diff(Strqueue *sq1, Strqueue *sq2, Strqueue *osq)
+{
+  int i = 0, j = 0;
+  while (i < sq1->nstr && j < sq2->nstr)
+    {
+      int r = strqueue_sort_cmp(sq1->str + i, sq2->str + j, 0);
+      if (!r)
+       i++, j++;
+      else if (r < 0)
+       strqueue_pushjoin(osq, "-", sq1->str[i++], 0);
+      else
+       strqueue_pushjoin(osq, "+", sq2->str[j++], 0);
+    }
+  while (i < sq1->nstr)
+    strqueue_pushjoin(osq, "-", sq1->str[i++], 0);
+  while (j < sq2->nstr)
+    strqueue_pushjoin(osq, "+", sq2->str[j++], 0);
+}
+
+
+static const char *
+testcase_id2str(Pool *pool, Id id, int isname)
+{
+  const char *s = pool_id2str(pool, id);
+  const char *ss;
+  char *s2, *s2p;
+  int bad = 0, paren = 0, parenbad = 0;
+
+  if (id == 0)
+    return "<NULL>";
+  if (id == 1)
+    return "\\00";
+  if (strchr("[(<=>!", *s))
+    bad++;
+  if (!strncmp(s, "namespace:", 10))
+    bad++;
+  for (ss = s + bad; *ss; ss++)
+    {
+      if (*ss == ' ' || *ss == '\\' || *(unsigned char *)ss < 32 || *ss == '(' || *ss == ')')
+        bad++;
+      if (*ss == '(')
+       paren = paren == 0 ? 1 : -1;
+      else if (*ss == ')')
+       {
+         paren = paren == 1 ? 0 : -1;
+         if (!paren)
+           parenbad += 2;
+       }
+    }
+  if (isname && ss - s > 4 && !strcmp(ss - 4, ":any"))
+    bad++;
+  if (!paren && !(bad - parenbad))
+    return s;
+
+  /* we need escaping! */
+  s2 = s2p = pool_alloctmpspace(pool, strlen(s) + bad * 2 + 1);
+  if (!strncmp(s, "namespace:", 10))
+    {
+      strcpy(s2p, "namespace\\3a");
+      s2p += 12;
+      s += 10;
+    }
+  ss = s;
+  for (; *ss; ss++)
+    {
+      *s2p++ = *ss;
+      if ((ss == s && strchr("[(<=>!", *s)) || *ss == ' ' || *ss == '\\' || *(unsigned char *)ss < 32 || *ss == '(' || *ss == ')')
+       {
+         s2p[-1] = '\\';
+         solv_bin2hex((unsigned char *)ss, 1, s2p);
+         s2p += 2;
+       }
+    }
+  *s2p = 0;
+  if (isname && s2p - s2 > 4 && !strcmp(s2p - 4, ":any"))
+    strcpy(s2p - 4, "\\3aany");
+  return s2;
+}
+
+struct oplist {
+  Id flags;
+  const char *opname;
+} oplist[] = {
+  { REL_EQ, "=" },
+  { REL_GT | REL_LT | REL_EQ, "<=>" },
+  { REL_LT | REL_EQ, "<=" },
+  { REL_GT | REL_EQ, ">=" },
+  { REL_GT, ">" },
+  { REL_GT | REL_LT, "<>" },
+  { REL_AND,   "&" },
+  { REL_OR ,   "|" },
+  { REL_WITH , "+" },
+  { REL_WITHOUT , "-" },
+  { REL_NAMESPACE , "<NAMESPACE>" },
+  { REL_ARCH,       "." },
+  { REL_MULTIARCH,  "<MULTIARCH>" },
+  { REL_FILECONFLICT,  "<FILECONFLICT>" },
+  { REL_COND,  "<IF>" },
+  { REL_COMPAT,  "compat >=" },
+  { REL_KIND,  "<KIND>" },
+  { REL_ELSE, "<ELSE>" },
+  { REL_ERROR, "<ERROR>" },
+  { REL_UNLESS, "<UNLESS>" },
+  { REL_LT, "<" },
+  { 0, 0 }
+};
+
+static char *
+testcase_dep2str_complex(Pool *pool, char *s, Id id, int addparens)
+{
+  Reldep *rd;
+  const char *s2;
+  int needparens;
+  struct oplist *op;
+
+  if (!ISRELDEP(id))
+    {
+      s2 = testcase_id2str(pool, id, 1);
+      s = pool_tmpappend(pool, s, s2, 0);
+      pool_freetmpspace(pool, s2);
+      return s;
+    }
+  rd = GETRELDEP(pool, id);
+
+  /* check for special shortcuts */
+  if (rd->flags == REL_NAMESPACE && !ISRELDEP(rd->name) && !strncmp(pool_id2str(pool, rd->name), "namespace:", 10))
+    {
+      s = pool_tmpappend(pool, s, pool_id2str(pool, rd->name), "(");
+      s = testcase_dep2str_complex(pool, s, rd->evr, 0);
+      return pool_tmpappend(pool, s, ")", 0);
+    }
+  if (rd->flags == REL_MULTIARCH && !ISRELDEP(rd->name) && rd->evr == ARCH_ANY)
+    {
+      /* append special :any suffix */
+      s2 = testcase_id2str(pool, rd->name, 1);
+      s = pool_tmpappend(pool, s, s2, ":any");
+      pool_freetmpspace(pool, s2);
+      return s;
+    }
+
+  needparens = 0;
+  if (ISRELDEP(rd->name))
+    {
+      Reldep *rd2 = GETRELDEP(pool, rd->name);
+      needparens = 1;
+      if (rd->flags > 7 && rd->flags != REL_COMPAT && rd2->flags && rd2->flags <= 7)
+       needparens = 0;
+    }
+
+  if (addparens)
+    s = pool_tmpappend(pool, s, "(", 0);
+  s = testcase_dep2str_complex(pool, s, rd->name, needparens);
+
+  for (op = oplist; op->flags; op++)
+    if (rd->flags == op->flags)
+      break;
+  if (op->flags)
+    {
+      s = pool_tmpappend(pool, s, " ", op->opname);
+      s = pool_tmpappend(pool, s, " ", 0);
+    }
+  else
+    {
+      char buf[64];
+      sprintf(buf, " <%u> ", rd->flags);
+      s = pool_tmpappend(pool, s, buf, 0);
+    }
+
+  needparens = 0;
+  if (ISRELDEP(rd->evr))
+    {
+      Reldep *rd2 = GETRELDEP(pool, rd->evr);
+      needparens = 1;
+      if (rd->flags > 7 && rd2->flags && rd2->flags <= 7)
+       needparens = 0;
+      if (rd->flags == REL_AND && rd2->flags == REL_AND)
+       needparens = 0; /* chain */
+      if (rd->flags == REL_OR && rd2->flags == REL_OR)
+       needparens = 0; /* chain */
+      if (rd->flags > 0 && rd->flags < 8 && rd2->flags == REL_COMPAT)
+       needparens = 0; /* chain */
+    }
+  if (!ISRELDEP(rd->evr))
+    {
+      s2 = testcase_id2str(pool, rd->evr, 0);
+      s = pool_tmpappend(pool, s, s2, 0);
+      pool_freetmpspace(pool, s2);
+    }
+  else
+    s = (char *)testcase_dep2str_complex(pool, s, rd->evr, needparens);
+  if (addparens)
+    s = pool_tmpappend(pool, s, ")", 0);
+  return s;
+}
+
+const char *
+testcase_dep2str(Pool *pool, Id id)
+{
+  char *s;
+  if (!ISRELDEP(id))
+    return testcase_id2str(pool, id, 1);
+  s = pool_alloctmpspace(pool, 1);
+  *s = 0;
+  return testcase_dep2str_complex(pool, s, id, 0);
+}
+
+
+/* Convert a simple string. Also handle the :any suffix */
+static Id
+testcase_str2dep_simple(Pool *pool, const char **sp, int isname)
+{
+  int haveesc = 0;
+  int paren = 0;
+  int isany = 0;
+  Id id;
+  const char *s;
+  for (s = *sp; *s; s++)
+    {
+      if (*s == '\\')
+       haveesc++;
+      if (*s == ' ' || *(unsigned char *)s < 32)
+       break;
+      if (*s == '(')
+       paren++;
+      if (*s == ')' && paren-- <= 0)
+       break;
+    }
+  if (isname && s - *sp > 4 && !strncmp(s - 4, ":any", 4))
+    {
+      isany = 1;
+      s -= 4;
+    }
+  if (!haveesc)
+    {
+      if (s - *sp == 6 && !strncmp(*sp, "<NULL>", 6))
+       id = 0;
+      else
+        id = pool_strn2id(pool, *sp, s - *sp, 1);
+    }
+  else if (s - *sp == 3 && !strncmp(*sp, "\\00", 3))
+    id = 1;
+  else
+    {
+      char buf[128], *bp, *bp2;
+      const char *sp2;
+      bp = s - *sp >= 128 ? solv_malloc(s - *sp + 1) : buf;
+      for (bp2 = bp, sp2 = *sp; sp2 < s;)
+       {
+         *bp2++ = *sp2++;
+         if (bp2[-1] == '\\')
+           solv_hex2bin(&sp2, (unsigned char *)bp2 - 1, 1);
+       }
+      *bp2 = 0;
+      id = pool_str2id(pool, bp, 1);
+      if (bp != buf)
+       solv_free(bp);
+    }
+  if (isany)
+    {
+      id = pool_rel2id(pool, id, ARCH_ANY, REL_MULTIARCH, 1);
+      s += 4;
+    }
+  *sp = s;
+  return id;
+}
+
+
+static Id
+testcase_str2dep_complex(Pool *pool, const char **sp, int relop)
+{
+  const char *s = *sp;
+  Id flags, id, id2, namespaceid = 0;
+  struct oplist *op;
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+  if (!strncmp(s, "namespace:", 10))
+    {
+      /* special namespace hack */
+      const char *s2;
+      for (s2 = s + 10; *s2 && *s2 != '('; s2++)
+       ;
+      if (*s2 == '(')
+       {
+         namespaceid = pool_strn2id(pool, s, s2 - s, 1);
+         s = s2;
+       }
+    }
+  if (*s == '(')
+    {
+      s++;
+      id = testcase_str2dep_complex(pool, &s, 0);
+      if (!s || *s != ')')
+       {
+         *sp = 0;
+         return 0;
+       }
+      s++;
+    }
+  else
+    id = testcase_str2dep_simple(pool, &s, relop ? 0 : 1);
+  if (namespaceid)
+    id = pool_rel2id(pool, namespaceid, id, REL_NAMESPACE, 1);
+    
+  for (;;)
+    {
+      while (*s == ' ' || *s == '\t')
+       s++;
+      if (!*s || *s == ')' || (relop && strncmp(s, "compat >= ", 10) != 0))
+       {
+         *sp = s;
+         return id;
+       }
+
+      /* we have an op! Find the end */
+      flags = -1;
+      if (s[0] == '<' && (s[1] >= '0' && s[1] <= '9'))
+       {
+         const char *s2;
+         for (s2 = s + 1; *s2 >= '0' && *s2 <= '9'; s2++)
+           ;
+         if (*s2 == '>')
+           {
+             flags = strtoul(s + 1, 0, 10);
+             s = s2 + 1;
+           }
+       }
+      if (flags == -1)
+       {
+         for (op = oplist; op->flags; op++)
+           if (!strncmp(s, op->opname, strlen(op->opname)))
+             break;
+         if (!op->flags)
+           {
+             *sp = 0;
+             return 0;
+           }
+         flags = op->flags;
+         s += strlen(op->opname);
+       }
+      id2 = testcase_str2dep_complex(pool, &s, flags > 0 && flags < 8);
+      if (!s)
+       {
+         *sp = 0;
+         return 0;
+       }
+      id = pool_rel2id(pool, id, id2, flags, 1);
+    }
+}
+
+Id
+testcase_str2dep(Pool *pool, const char *s)
+{
+  Id id = testcase_str2dep_complex(pool, &s, 0);
+  return s && !*s ? id : 0;
+}
+
+/**********************************************************/
+
+const char *
+testcase_repoid2str(Pool *pool, Id repoid)
+{
+  Repo *repo = pool_id2repo(pool, repoid);
+  if (repo->name)
+    {
+      char *r = pool_tmpjoin(pool, repo->name, 0, 0);
+      char *rp;
+      for (rp = r; *rp; rp++)
+       if (*rp == ' ' || *rp == '\t')
+         *rp = '_';
+      return r;
+    }
+  else
+    {
+      char buf[20];
+      sprintf(buf, "#%d", repoid);
+      return pool_tmpjoin(pool, buf, 0, 0);
+    }
+}
+
+const char *
+testcase_solvid2str(Pool *pool, Id p)
+{
+  Solvable *s = pool->solvables + p;
+  const char *n, *e, *a;
+  char *str, buf[20];
+
+  if (p == SYSTEMSOLVABLE)
+    return "@SYSTEM";
+  n = pool_id2str(pool, s->name);
+  e = pool_id2str(pool, s->evr);
+  a = pool_id2str(pool, s->arch);
+  str = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3);
+  sprintf(str, "%s-%s.%s", n, e, a);
+  if (!s->repo)
+    return pool_tmpappend(pool, str, "@", 0);
+  if (s->repo->name)
+    {
+      int l = strlen(str);
+      char *str2 = pool_tmpappend(pool, str, "@", s->repo->name);
+      for (; str2[l]; l++)
+       if (str2[l] == ' ' || str2[l] == '\t')
+         str2[l] = '_';
+      return str2;
+    }
+  sprintf(buf, "@#%d", s->repo->repoid);
+  return pool_tmpappend(pool, str, buf, 0);
+}
+
+Repo *
+testcase_str2repo(Pool *pool, const char *str)
+{
+  int repoid;
+  Repo *repo = 0;
+  if (str[0] == '#' && (str[1] >= '0' && str[1] <= '9'))
+    {
+      int j;
+      repoid = 0;
+      for (j = 1; str[j] >= '0' && str[j] <= '9'; j++)
+       repoid = repoid * 10 + (str[j] - '0');
+      if (!str[j] && repoid > 0 && repoid < pool->nrepos)
+       repo = pool_id2repo(pool, repoid);
+    }
+  if (!repo)
+    {
+      FOR_REPOS(repoid, repo)
+       {
+         int i, l;
+         if (!repo->name)
+           continue;
+         l = strlen(repo->name);
+         for (i = 0; i < l; i++)
+           {
+             int c = repo->name[i];
+             if (c == ' ' || c == '\t')
+               c = '_';
+             if (c != str[i])
+               break;
+           }
+         if (i == l && !str[l])
+           break;
+       }
+      if (repoid >= pool->nrepos)
+       repo = 0;
+    }
+  return repo;
+}
+
+Id
+testcase_str2solvid(Pool *pool, const char *str)
+{
+  int i, l = strlen(str);
+  int repostart;
+  Repo *repo;
+  Id arch;
+
+  if (!l)
+    return 0;
+  if (*str == '@' && !strcmp(str, "@SYSTEM"))
+    return SYSTEMSOLVABLE;
+  repo = 0;
+  for (i = l - 1; i >= 0; i--)
+    if (str[i] == '@' && (repo = testcase_str2repo(pool, str + i + 1)) != 0)
+      break;
+  if (i < 0)
+    i = l;
+  repostart = i;
+  /* now find the arch (if present) */
+  arch = 0;
+  for (i = repostart - 1; i > 0; i--)
+    if (str[i] == '.')
+      {
+       arch = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
+       if (arch)
+         repostart = i;
+       break;
+      }
+  /* now find the name */
+  for (i = repostart - 1; i > 0; i--)
+    {
+      if (str[i] == '-')
+       {
+         Id nid, evrid, p, pp;
+         nid = pool_strn2id(pool, str, i, 0);
+         if (!nid)
+           continue;
+         evrid = pool_strn2id(pool, str + i + 1, repostart - (i + 1), 0);
+         if (!evrid)
+           continue;
+         /* first check whatprovides */
+         FOR_PROVIDES(p, pp, nid)
+           {
+             Solvable *s = pool->solvables + p;
+             if (s->name != nid || s->evr != evrid)
+               continue;
+             if (repo && s->repo != repo)
+               continue;
+             if (arch && s->arch != arch)
+               continue;
+             return p;
+           }
+         /* maybe it's not installable and thus not in whatprovides. do a slow search */
+         if (repo)
+           {
+             Solvable *s;
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 if (s->name != nid || s->evr != evrid)
+                   continue;
+                 if (arch && s->arch != arch)
+                   continue;
+                 return p;
+               }
+           }
+         else
+           {
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->name != nid || s->evr != evrid)
+                   continue;
+                 if (arch && s->arch != arch)
+                   continue;
+                 return p;
+               }
+           }
+       }
+    }
+  return 0;
+}
+
+const char *
+testcase_job2str(Pool *pool, Id how, Id what)
+{
+  char *ret;
+  const char *jobstr;
+  const char *selstr;
+  const char *pkgstr;
+  int i, o;
+  Id select = how & SOLVER_SELECTMASK;
+
+  for (i = 0; job2str[i].str; i++)
+    if ((how & SOLVER_JOBMASK) == job2str[i].job)
+      break;
+  jobstr = job2str[i].str ? job2str[i].str : "unknown";
+  if (select == SOLVER_SOLVABLE)
+    {
+      selstr = " pkg ";
+      pkgstr = testcase_solvid2str(pool, what);
+    }
+  else if (select == SOLVER_SOLVABLE_NAME)
+    {
+      selstr = " name ";
+      pkgstr = testcase_dep2str(pool, what);
+    }
+  else if (select == SOLVER_SOLVABLE_PROVIDES)
+    {
+      selstr = " provides ";
+      pkgstr = testcase_dep2str(pool, what);
+    }
+  else if (select == SOLVER_SOLVABLE_ONE_OF)
+    {
+      Id p;
+      selstr = " oneof ";
+      pkgstr = 0;
+      while ((p = pool->whatprovidesdata[what++]) != 0)
+       {
+         const char *s = testcase_solvid2str(pool, p);
+         if (pkgstr)
+           {
+             pkgstr = pool_tmpappend(pool, pkgstr, " ", s);
+             pool_freetmpspace(pool, s);
+           }
+         else
+           pkgstr = s;
+       }
+      if (!pkgstr)
+       pkgstr = "nothing";
+    }
+  else if (select == SOLVER_SOLVABLE_REPO)
+    {
+      Repo *repo = pool_id2repo(pool, what);
+      selstr = " repo ";
+      if (!repo->name)
+       {
+          char buf[20];
+         sprintf(buf, "#%d", repo->repoid);
+         pkgstr = pool_tmpjoin(pool, buf, 0, 0);
+       }
+      else
+        pkgstr = pool_tmpjoin(pool, repo->name, 0, 0);
+    }
+  else if (select == SOLVER_SOLVABLE_ALL)
+    {
+      selstr = " all ";
+      pkgstr = "packages";
+    }
+  else
+    {
+      selstr = " unknown ";
+      pkgstr = "unknown";
+    }
+  ret = pool_tmpjoin(pool, jobstr, selstr, pkgstr);
+  o = strlen(ret);
+  ret = pool_tmpappend(pool, ret, " ", 0);
+  for (i = 0; jobflags2str[i].str; i++)
+    if ((how & jobflags2str[i].flag) != 0)
+      ret = pool_tmpappend(pool, ret, ",", jobflags2str[i].str);
+  if (!ret[o + 1])
+    ret[o] = 0;
+  else
+    {
+      ret[o + 1] = '[';
+      ret = pool_tmpappend(pool, ret, "]", 0);
+    }
+  return ret;
+}
+
+static int
+str2selflags(Pool *pool, char *s)      /* modifies the string! */
+{
+  int i, selflags = 0;
+  while (s)
+    {
+      char *se = strchr(s, ',');
+      if (se)
+       *se++ = 0;
+      for (i = 0; selflags2str[i].str; i++)
+       if (!strcmp(s, selflags2str[i].str))
+         {
+           selflags |= selflags2str[i].flag;
+           break;
+         }
+      if (!selflags2str[i].str)
+       pool_error(pool, 0, "str2job: unknown selection flag '%s'", s);
+      s = se;
+    }
+  return selflags;
+}
+
+static int
+str2jobflags(Pool *pool, char *s)      /* modifies the string */
+{
+  int i, jobflags = 0;
+  while (s)
+    {
+      char *se = strchr(s, ',');
+      if (se)
+       *se++ = 0;
+      for (i = 0; jobflags2str[i].str; i++)
+       if (!strcmp(s, jobflags2str[i].str))
+         {
+           jobflags |= jobflags2str[i].flag;
+           break;
+         }
+      if (!jobflags2str[i].str)
+       pool_error(pool, 0, "str2job: unknown job flag '%s'", s);
+      s = se;
+    }
+  return jobflags;
+}
+
+Id
+testcase_str2job(Pool *pool, const char *str, Id *whatp)
+{
+  int i;
+  Id job;
+  Id what;
+  char *s;
+  char **pieces = 0;
+  int npieces = 0;
+
+  *whatp = 0;
+  /* so we can patch it */
+  s = pool_tmpjoin(pool, str, 0, 0);
+  /* split it in pieces */
+  for (;;)
+    {
+      while (*s == ' ' || *s == '\t')
+       s++;
+      if (!*s)
+       break;
+      pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
+      pieces[npieces++] = s;
+      while (*s && *s != ' ' && *s != '\t')
+       s++;
+      if (*s)
+       *s++ = 0;
+    }
+  if (npieces < 3)
+    {
+      pool_error(pool, -1, "str2job: bad line '%s'", str);
+      solv_free(pieces);
+      return -1;
+    }
+
+  for (i = 0; job2str[i].str; i++)
+    if (!strcmp(pieces[0], job2str[i].str))
+      break;
+  if (!job2str[i].str)
+    {
+      pool_error(pool, -1, "str2job: unknown job '%s'", str);
+      solv_free(pieces);
+      return -1;
+    }
+  job = job2str[i].job;
+  what = 0;
+  if (npieces > 3)
+    {
+      char *flags = pieces[npieces - 1];
+      if (*flags == '[' && flags[strlen(flags) - 1] == ']')
+       {
+         npieces--;
+         flags++;
+         flags[strlen(flags) - 1] = 0;
+         job |= str2jobflags(pool, flags);
+       }
+    }
+  if (!strcmp(pieces[1], "pkg"))
+    {
+      if (npieces != 3)
+       {
+         pool_error(pool, -1, "str2job: bad pkg selector in '%s'", str);
+         solv_free(pieces);
+         return -1;
+       }
+      job |= SOLVER_SOLVABLE;
+      what = testcase_str2solvid(pool, pieces[2]);
+      if (!what)
+       {
+         pool_error(pool, -1, "str2job: unknown package '%s'", pieces[2]);
+         solv_free(pieces);
+         return -1;
+       }
+    }
+  else if (!strcmp(pieces[1], "name") || !strcmp(pieces[1], "provides"))
+    {
+      /* join em again for dep2str... */
+      char *sp;
+      for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
+       if (*sp == 0)
+         *sp = ' ';
+      what = 0;
+      if (pieces[1][0] == 'p' && strncmp(pieces[2], "namespace:", 10) == 0)
+       {
+         char *spe = strchr(pieces[2], '(');
+         int l = strlen(pieces[2]);
+         if (spe && pieces[2][l - 1] == ')')
+           {
+             /* special namespace provides */
+             if (strcmp(spe, "(<NULL>)") != 0)
+               {
+                 pieces[2][l - 1] = 0;
+                 what = testcase_str2dep(pool, spe + 1);
+                 pieces[2][l - 1] = ')';
+               }
+             what = pool_rel2id(pool, pool_strn2id(pool, pieces[2], spe - pieces[2], 1), what, REL_NAMESPACE, 1);
+           }
+       }
+      if (!what)
+        what = testcase_str2dep(pool, pieces[2]);
+      if (pieces[1][0] == 'n')
+       job |= SOLVER_SOLVABLE_NAME;
+      else
+       job |= SOLVER_SOLVABLE_PROVIDES;
+    }
+  else if (!strcmp(pieces[1], "oneof"))
+    {
+      Queue q;
+      job |= SOLVER_SOLVABLE_ONE_OF;
+      queue_init(&q);
+      if (npieces > 2 && strcmp(pieces[2], "nothing") != 0)
+       {
+         for (i = 2; i < npieces; i++)
+           {
+             Id p = testcase_str2solvid(pool, pieces[i]);
+             if (!p)
+               {
+                 pool_error(pool, -1, "str2job: unknown package '%s'", pieces[i]);
+                 queue_free(&q);
+                 solv_free(pieces);
+                 return -1;
+               }
+             queue_push(&q, p);
+           }
+       }
+      what = pool_queuetowhatprovides(pool, &q);
+      queue_free(&q);
+    }
+  else if (!strcmp(pieces[1], "repo"))
+    {
+      Repo *repo;
+      if (npieces != 3)
+       {
+         pool_error(pool, -1, "str2job: bad line '%s'", str);
+         solv_free(pieces);
+         return -1;
+       }
+      repo = testcase_str2repo(pool, pieces[2]);
+      if (!repo)
+       {
+         pool_error(pool, -1, "str2job: unknown repo '%s'", pieces[2]);
+         solv_free(pieces);
+         return -1;
+       }
+      job |= SOLVER_SOLVABLE_REPO;
+      what = repo->repoid;
+    }
+  else if (!strcmp(pieces[1], "all"))
+    {
+      if (npieces != 3 && strcmp(pieces[2], "packages") != 0)
+       {
+         pool_error(pool, -1, "str2job: bad line '%s'", str);
+         solv_free(pieces);
+         return -1;
+       }
+      job |= SOLVER_SOLVABLE_ALL;
+      what = 0;
+    }
+  else
+    {
+      pool_error(pool, -1, "str2job: unknown selection in '%s'", str);
+      solv_free(pieces);
+      return -1;
+    }
+  *whatp = what;
+  solv_free(pieces);
+  return job;
+}
+
+#define SELECTIONJOB_MATCHDEPS         1
+#define SELECTIONJOB_MATCHDEPID                2
+#define SELECTIONJOB_MATCHSOLVABLE     3
+
+static int
+addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int type, int keyname)
+{
+  Id job;
+  int i, r = 0;
+  int selflags;
+  Queue sel;
+  char *sp;
+
+  for (i = 0; job2str[i].str; i++)
+    if (!strcmp(pieces[0], job2str[i].str))
+      break;
+  if (!job2str[i].str)
+    return pool_error(pool, -1, "selstr2job: unknown job '%s'", pieces[0]);
+  job = job2str[i].job;
+  if (npieces > 3)
+    {
+      char *flags = pieces[npieces - 1];
+      if (*flags == '[' && flags[strlen(flags) - 1] == ']')
+       {
+         npieces--;
+         flags++;
+         flags[strlen(flags) - 1] = 0;
+         job |= str2jobflags(pool, flags);
+       }
+    }
+  if (npieces < 4)
+    return pool_error(pool, -1, "selstr2job: no selection flags");
+  selflags = str2selflags(pool, pieces[npieces - 1]);
+  /* re-join pieces */
+  for (sp = pieces[2]; sp < pieces[npieces - 2]; sp++)
+    if (*sp == 0)
+      *sp = ' ';
+  queue_init(&sel);
+  if (selflags & (SELECTION_ADD | SELECTION_SUBTRACT | SELECTION_FILTER))
+    {
+      for (i = 0; i < jobqueue->count; i += 2)
+       queue_push2(&sel, jobqueue->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK), jobqueue->elements[i + 1]);
+      queue_empty(jobqueue);
+    }
+  if (!type)
+    r = selection_make(pool, &sel, pieces[2], selflags);
+  else if (type == SELECTIONJOB_MATCHDEPS)
+    r = selection_make_matchdeps(pool, &sel, pieces[2], selflags, keyname, 0);
+  else if (type == SELECTIONJOB_MATCHDEPID)
+    r = selection_make_matchdepid(pool, &sel, testcase_str2dep(pool, pieces[2]), selflags, keyname, 0);
+  else if (type == SELECTIONJOB_MATCHSOLVABLE)
+    r = selection_make_matchsolvable(pool, &sel, testcase_str2solvid(pool, pieces[2]), selflags, keyname, 0);
+  for (i = 0; i < sel.count; i += 2)
+    queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]);
+  queue_free(&sel);
+  return r;
+}
+
+static void
+writedeps(Repo *repo, FILE *fp, const char *tag, Id key, Solvable *s, Offset off)
+{
+  Pool *pool = repo->pool;
+  Id id, *dp;
+  int tagwritten = 0;
+  const char *idstr;
+
+  if (!off)
+    return;
+  dp = repo->idarraydata + off;
+  while ((id = *dp++) != 0)
+    {
+      if (key == SOLVABLE_REQUIRES && id == SOLVABLE_PREREQMARKER)
+       {
+         if (tagwritten)
+           fprintf(fp, "-%s\n", tag);
+         tagwritten = 0;
+         tag = "Prq:";
+         continue;
+       }
+      if (key == SOLVABLE_PROVIDES && id == SOLVABLE_FILEMARKER)
+       continue;
+      idstr = testcase_dep2str(pool, id);
+      if (!tagwritten)
+       {
+         fprintf(fp, "+%s\n", tag);
+         tagwritten = 1;
+       }
+      fprintf(fp, "%s\n", idstr);
+    }
+  if (tagwritten)
+    fprintf(fp, "-%s\n", tag);
+}
+
+static void
+writefilelist(Repo *repo, FILE *fp, const char *tag, Solvable *s)
+{
+  Pool *pool = repo->pool;
+  int tagwritten = 0;
+  Dataiterator di;
+
+  dataiterator_init(&di, pool, repo, s - pool->solvables, SOLVABLE_FILELIST, 0, 0);
+  while (dataiterator_step(&di))
+    {
+      const char *s = repodata_dir2str(di.data, di.kv.id, di.kv.str);
+      if (!tagwritten)
+       {
+         fprintf(fp, "+%s\n", tag);
+         tagwritten = 1;
+       }
+      fprintf(fp, "%s\n", s);
+    }
+  if (tagwritten)
+    fprintf(fp, "-%s\n", tag);
+  dataiterator_free(&di);
+}
+
+int
+testcase_write_testtags(Repo *repo, FILE *fp)
+{
+  Pool *pool = repo->pool;
+  Solvable *s;
+  Id p;
+  const char *name;
+  const char *evr;
+  const char *arch;
+  const char *release;
+  const char *tmp;
+  unsigned int ti;
+  Queue q;
+
+  fprintf(fp, "=Ver: 3.0\n");
+  queue_init(&q);
+  FOR_REPO_SOLVABLES(repo, p, s)
+    {
+      name = pool_id2str(pool, s->name);
+      evr = pool_id2str(pool, s->evr);
+      arch = pool_id2str(pool, s->arch);
+      release = strrchr(evr, '-');
+      if (!release)
+       release = evr + strlen(evr);
+      fprintf(fp, "=Pkg: %s %.*s %s %s\n", name, (int)(release - evr), evr, *release && release[1] ? release + 1 : "-", arch);
+      tmp = solvable_lookup_str(s, SOLVABLE_SUMMARY);
+      if (tmp)
+        fprintf(fp, "=Sum: %s\n", tmp);
+      writedeps(repo, fp, "Req:", SOLVABLE_REQUIRES, s, s->requires);
+      writedeps(repo, fp, "Prv:", SOLVABLE_PROVIDES, s, s->provides);
+      writedeps(repo, fp, "Obs:", SOLVABLE_OBSOLETES, s, s->obsoletes);
+      writedeps(repo, fp, "Con:", SOLVABLE_CONFLICTS, s, s->conflicts);
+      writedeps(repo, fp, "Rec:", SOLVABLE_RECOMMENDS, s, s->recommends);
+      writedeps(repo, fp, "Sup:", SOLVABLE_SUPPLEMENTS, s, s->supplements);
+      writedeps(repo, fp, "Sug:", SOLVABLE_SUGGESTS, s, s->suggests);
+      writedeps(repo, fp, "Enh:", SOLVABLE_ENHANCES, s, s->enhances);
+      if (solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &q))
+       {
+         int i;
+         fprintf(fp, "+Ipr:\n");
+         for (i = 0; i < q.count; i++)
+           fprintf(fp, "%s\n", testcase_dep2str(pool, q.elements[i]));
+         fprintf(fp, "-Ipr:\n");
+       }
+      if (s->vendor)
+       fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor));
+      ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
+      if (ti)
+       fprintf(fp, "=Tim: %u\n", ti);
+      writefilelist(repo, fp, "Fls:", s);
+    }
+  queue_free(&q);
+  return 0;
+}
+
+static inline Offset
+adddep(Repo *repo, Offset olddeps, char *str, Id marker)
+{
+  Id id = *str == '/' ? pool_str2id(repo->pool, str, 1) : testcase_str2dep(repo->pool, str);
+  return repo_addid_dep(repo, olddeps, id, marker);
+}
+
+static void
+finish_v2_solvable(Pool *pool, Repodata *data, Solvable *s, char *filelist, int nfilelist)
+{
+  if (nfilelist)
+    {
+      int l;
+      Id did;
+      for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1)
+       {
+         char *p = strrchr(filelist + l, '/');
+         if (!p)
+           continue;
+         *p++ = 0;
+         did = repodata_str2dir(data, filelist + l, 1);
+         p[-1] = '/';
+         if (!did)
+           did = repodata_str2dir(data, "/", 1);
+         repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p);
+       }
+    }
+  repo_rewrite_suse_deps(s, 0);
+}
+
+/* stripped down version of susetags parser used for testcases */
+int
+testcase_add_testtags(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  char *line, *linep;
+  int aline;
+  int tag;
+  Repodata *data;
+  Solvable *s;
+  char *sp[5];
+  unsigned int t;
+  int intag;
+  char *filelist = 0;
+  int afilelist = 0;
+  int nfilelist = 0;
+  int tagsversion = 0;
+  int addselfprovides = 1;     /* for compat reasons */
+
+  data = repo_add_repodata(repo, flags);
+  s = 0;
+  intag = 0;
+
+  aline = 1024;
+  line = solv_malloc(aline);
+  linep = line;
+  for (;;)
+    {
+      if (linep - line + 16 > aline)
+       {
+         aline = linep - line;
+         line = solv_realloc(line, aline + 512);
+         linep = line + aline;
+         aline += 512;
+       }
+      if (!fgets(linep, aline - (linep - line), fp))
+       break;
+      linep += strlen(linep);
+      if (linep == line || linep[-1] != '\n')
+       continue;
+      linep[-1] = 0;
+      linep = line + intag;
+      if (intag)
+       {
+         if (line[intag] == '-' && !strncmp(line + 1, line + intag + 1, intag - 2))
+           {
+             intag = 0;
+             linep = line;
+             continue;
+           }
+       }
+      else if (line[0] == '+' && line[1] && line[1] != ':')
+       {
+         char *tagend = strchr(line, ':');
+         if (!tagend)
+           continue;
+         line[0] = '=';
+         tagend[1] = ' ';
+         intag = tagend + 2 - line;
+         linep = line + intag;
+         continue;
+       }
+      if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':')
+       continue;
+      tag = line[1] << 16 | line[2] << 8 | line[3];
+      /* tags that do not need a solvable */
+      switch(tag)
+       {
+       case 'V' << 16 | 'e' << 8 | 'r':
+         tagsversion = atoi(line + 6);
+         addselfprovides = tagsversion < 3 || strstr(line + 6, "addselfprovides") != 0;
+         continue;
+       case 'P' << 16 | 'k' << 8 | 'g':
+         if (s)
+           {
+             if (tagsversion == 2)
+               finish_v2_solvable(pool, data, s, filelist, nfilelist);
+             if (addselfprovides && s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+               s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+           }
+         nfilelist = 0;
+         if (split(line + 5, sp, 5) != 4)
+           break;
+         s = pool_id2solvable(pool, repo_add_solvable(repo));
+         s->name = pool_str2id(pool, sp[0], 1);
+         /* join back version and release */
+         if (sp[2] && !(sp[2][0] == '-' && !sp[2][1]))
+           sp[2][-1] = '-';
+         s->evr = makeevr(pool, sp[1]);
+         s->arch = pool_str2id(pool, sp[3], 1);
+         continue;
+       default:
+         break;
+       }
+      if (!s)
+       continue;
+      /* tags that need a solvable */
+      switch(tag)
+       {
+       case 'S' << 16 | 'u' << 8 | 'm':
+         repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6);
+         break;
+       case 'V' << 16 | 'n' << 8 | 'd':
+         s->vendor = pool_str2id(pool, line + 6, 1);
+         break;
+       case 'T' << 16 | 'i' << 8 | 'm':
+         t = atoi(line + 6);
+         if (t)
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
+         break;
+       case 'R' << 16 | 'e' << 8 | 'q':
+         s->requires = adddep(repo, s->requires, line + 6, -SOLVABLE_PREREQMARKER);
+         break;
+       case 'P' << 16 | 'r' << 8 | 'q':
+         s->requires = adddep(repo, s->requires, line + 6, SOLVABLE_PREREQMARKER);
+         break;
+       case 'P' << 16 | 'r' << 8 | 'v':
+         /* version 2 had the file list at the end of the provides */
+         if (tagsversion == 2)
+           {
+             if (line[6] == '/')
+               {
+                 int l = strlen(line + 6) + 1;
+                 if (nfilelist + l > afilelist)
+                   {
+                     afilelist = nfilelist + l + 512;
+                     filelist = solv_realloc(filelist, afilelist);
+                   }
+                 memcpy(filelist + nfilelist, line + 6, l);
+                 nfilelist += l;
+                 break;
+               }
+             if (nfilelist)
+               {
+                 int l;
+                 for (l = 0; l < nfilelist; l += strlen(filelist + l) + 1)
+                   s->provides = repo_addid_dep(repo, s->provides, pool_str2id(pool, filelist + l, 1), 0);
+                 nfilelist = 0;
+               }
+           }
+         s->provides = adddep(repo, s->provides, line + 6, 0);
+         break;
+       case 'F' << 16 | 'l' << 8 | 's':
+         {
+           char *p = strrchr(line + 6, '/');
+           Id did;
+           if (!p)
+             break;
+           *p++ = 0;
+           did = repodata_str2dir(data, line + 6, 1);
+           if (!did)
+             did = repodata_str2dir(data, "/", 1);
+           repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, did, p);
+           break;
+         }
+       case 'O' << 16 | 'b' << 8 | 's':
+         s->obsoletes = adddep(repo, s->obsoletes, line + 6, 0);
+         break;
+       case 'C' << 16 | 'o' << 8 | 'n':
+         s->conflicts = adddep(repo, s->conflicts, line + 6, 0);
+         break;
+       case 'R' << 16 | 'e' << 8 | 'c':
+         s->recommends = adddep(repo, s->recommends, line + 6, 0);
+         break;
+       case 'S' << 16 | 'u' << 8 | 'p':
+         s->supplements = adddep(repo, s->supplements, line + 6, 0);
+         break;
+       case 'S' << 16 | 'u' << 8 | 'g':
+         s->suggests = adddep(repo, s->suggests, line + 6, 0);
+         break;
+       case 'E' << 16 | 'n' << 8 | 'h':
+         s->enhances = adddep(repo, s->enhances, line + 6, 0);
+         break;
+       case 'I' << 16 | 'p' << 8 | 'r':
+         {
+           Id id = line[6] == '/' ? pool_str2id(pool, line + 6, 1) : testcase_str2dep(pool, line + 6);
+           repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id);
+           break;
+         }
+        default:
+         break;
+        }
+    }
+  if (s)
+    {
+      if (tagsversion == 2)
+       finish_v2_solvable(pool, data, s, filelist, nfilelist);
+      if (addselfprovides && s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+        s->provides = repo_addid_dep(s->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+    }
+  solv_free(line);
+  solv_free(filelist);
+  repodata_free_dircache(data);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
+const char *
+testcase_getpoolflags(Pool *pool)
+{
+  const char *str = 0;
+  int i, v;
+  for (i = 0; poolflags2str[i].str; i++)
+    {
+      v = pool_get_flag(pool, poolflags2str[i].flag);
+      if (v == poolflags2str[i].def)
+       continue;
+      str = pool_tmpappend(pool, str, v ? " " : " !", poolflags2str[i].str);
+    }
+  return str ? str + 1 : "";
+}
+
+int
+testcase_setpoolflags(Pool *pool, const char *str)
+{
+  const char *p = str, *s;
+  int i, v;
+  for (;;)
+    {
+      while (*p == ' ' || *p == '\t' || *p == ',')
+       p++;
+      v = 1;
+      if (*p == '!')
+       {
+         p++;
+         v = 0;
+       }
+      if (!*p)
+       break;
+      s = p;
+      while (*p && *p != ' ' && *p != '\t' && *p != ',')
+       p++;
+      for (i = 0; poolflags2str[i].str; i++)
+       if (!strncmp(poolflags2str[i].str, s, p - s) && poolflags2str[i].str[p - s] == 0)
+         break;
+      if (!poolflags2str[i].str)
+        return pool_error(pool, 0, "setpoolflags: unknown flag '%.*s'", (int)(p - s), s);
+      pool_set_flag(pool, poolflags2str[i].flag, v);
+    }
+  return 1;
+}
+
+void
+testcase_resetpoolflags(Pool *pool)
+{
+  int i;
+  for (i = 0; poolflags2str[i].str; i++)
+    pool_set_flag(pool, poolflags2str[i].flag, poolflags2str[i].def);
+}
+
+const char *
+testcase_getsolverflags(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  const char *str = 0;
+  int i, v;
+  for (i = 0; solverflags2str[i].str; i++)
+    {
+      v = solver_get_flag(solv, solverflags2str[i].flag);
+      if (v == solverflags2str[i].def)
+       continue;
+      str = pool_tmpappend(pool, str, v ? " " : " !", solverflags2str[i].str);
+    }
+  return str ? str + 1 : "";
+}
+
+int
+testcase_setsolverflags(Solver *solv, const char *str)
+{
+  const char *p = str, *s;
+  int i, v;
+  for (;;)
+    {
+      while (*p == ' ' || *p == '\t' || *p == ',')
+       p++;
+      v = 1;
+      if (*p == '!')
+       {
+         p++;
+         v = 0;
+       }
+      if (!*p)
+       break;
+      s = p;
+      while (*p && *p != ' ' && *p != '\t' && *p != ',')
+       p++;
+      for (i = 0; solverflags2str[i].str; i++)
+       if (!strncmp(solverflags2str[i].str, s, p - s) && solverflags2str[i].str[p - s] == 0)
+         break;
+      if (!solverflags2str[i].str)
+       return pool_error(solv->pool, 0, "setsolverflags: unknown flag '%.*s'", (int)(p - s), s);
+      if (solver_set_flag(solv, solverflags2str[i].flag, v) == -1)
+        return pool_error(solv->pool, 0, "setsolverflags: unsupported flag '%s'", solverflags2str[i].str);
+    }
+  return 1;
+}
+
+void
+testcase_resetsolverflags(Solver *solv)
+{
+  int i;
+  for (i = 0; solverflags2str[i].str; i++)
+    solver_set_flag(solv, solverflags2str[i].flag, solverflags2str[i].def);
+}
+
+static const char *
+testcase_ruleid(Solver *solv, Id rid)
+{
+  Strqueue sq;
+  Queue q;
+  int i;
+  Chksum *chk;
+  const unsigned char *md5;
+  int md5l;
+  const char *s;
+
+  queue_init(&q);
+  strqueue_init(&sq);
+  solver_ruleliterals(solv, rid, &q);
+  for (i = 0; i < q.count; i++)
+    {
+      Id p = q.elements[i];
+      s = testcase_solvid2str(solv->pool, p > 0 ? p : -p);
+      if (p < 0)
+       s = pool_tmpjoin(solv->pool, "!", s, 0);
+      strqueue_push(&sq, s);
+    }
+  queue_free(&q);
+  strqueue_sort_u(&sq);
+  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+  for (i = 0; i < sq.nstr; i++)
+    solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1);
+  md5 = solv_chksum_get(chk, &md5l);
+  s = pool_bin2hex(solv->pool, md5, md5l);
+  chk = solv_chksum_free(chk, 0);
+  strqueue_free(&sq);
+  return s;
+}
+
+static const char *
+testcase_problemid(Solver *solv, Id problem)
+{
+  Strqueue sq;
+  Queue q;
+  Chksum *chk;
+  const unsigned char *md5;
+  int i, md5l;
+  const char *s;
+
+  /* we build a hash of all rules that define the problem */
+  queue_init(&q);
+  strqueue_init(&sq);
+  solver_findallproblemrules(solv, problem, &q);
+  for (i = 0; i < q.count; i++)
+    strqueue_push(&sq, testcase_ruleid(solv, q.elements[i]));
+  queue_free(&q);
+  strqueue_sort_u(&sq);
+  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+  for (i = 0; i < sq.nstr; i++)
+    solv_chksum_add(chk, sq.str[i], strlen(sq.str[i]) + 1);
+  md5 = solv_chksum_get(chk, &md5l);
+  s = pool_bin2hex(solv->pool, md5, 4);
+  chk = solv_chksum_free(chk, 0);
+  strqueue_free(&sq);
+  return s;
+}
+
+static const char *
+testcase_solutionid(Solver *solv, Id problem, Id solution)
+{
+  Id intid;
+  Chksum *chk;
+  const unsigned char *md5;
+  int md5l;
+  const char *s;
+
+  intid = solver_solutionelement_internalid(solv, problem, solution);
+  /* internal stuff! handle with care! */
+  if (intid < 0)
+    {
+      /* it's a job */
+      s = testcase_job2str(solv->pool, solv->job.elements[-intid - 1], solv->job.elements[-intid]);
+    }
+  else
+    {
+      /* it's a rule */
+      s = testcase_ruleid(solv, intid);
+    }
+  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+  solv_chksum_add(chk, s, strlen(s) + 1);
+  md5 = solv_chksum_get(chk, &md5l);
+  s = pool_bin2hex(solv->pool, md5, 4);
+  chk = solv_chksum_free(chk, 0);
+  return s;
+}
+
+static const char *
+testcase_alternativeid(Solver *solv, int type, Id id, Id from)
+{
+  const char *s;
+  Pool *pool = solv->pool;
+  Chksum *chk;
+  const unsigned char *md5;
+  int md5l;
+  chk = solv_chksum_create(REPOKEY_TYPE_MD5);
+  if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+    {
+      s = testcase_solvid2str(pool, from);
+      solv_chksum_add(chk, s, strlen(s) + 1);
+      s = testcase_dep2str(pool, id);
+      solv_chksum_add(chk, s, strlen(s) + 1);
+    }
+  else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+    {
+      s = testcase_ruleid(solv, id);
+      solv_chksum_add(chk, s, strlen(s) + 1);
+    }
+  md5 = solv_chksum_get(chk, &md5l);
+  s = pool_bin2hex(pool, md5, 4);
+  chk = solv_chksum_free(chk, 0);
+  return s;
+}
+
+static struct class2str {
+  Id class;
+  const char *str;
+} class2str[] = {
+  { SOLVER_TRANSACTION_ERASE,          "erase" },
+  { SOLVER_TRANSACTION_INSTALL,        "install" },
+  { SOLVER_TRANSACTION_REINSTALLED,    "reinstall" },
+  { SOLVER_TRANSACTION_DOWNGRADED,     "downgrade" },
+  { SOLVER_TRANSACTION_CHANGED,        "change" },
+  { SOLVER_TRANSACTION_UPGRADED,       "upgrade" },
+  { SOLVER_TRANSACTION_OBSOLETED,      "obsolete" },
+  { SOLVER_TRANSACTION_MULTIINSTALL,   "multiinstall" },
+  { SOLVER_TRANSACTION_MULTIREINSTALL, "multireinstall" },
+  { 0, 0 }
+};
+
+static struct reason2str {
+  Id reason;
+  const char *str;
+} reason2str[] = {
+  { SOLVER_REASON_UNRELATED,           "unrelated" },
+  { SOLVER_REASON_UNIT_RULE,           "unit" },
+  { SOLVER_REASON_KEEP_INSTALLED,      "keep" },
+  { SOLVER_REASON_RESOLVE_JOB,         "job" },
+  { SOLVER_REASON_UPDATE_INSTALLED,    "update" },
+  { SOLVER_REASON_CLEANDEPS_ERASE,     "cleandeps" },
+  { SOLVER_REASON_RESOLVE,             "resolve" },
+  { SOLVER_REASON_WEAKDEP,             "weakdep" },
+  { SOLVER_REASON_RESOLVE_ORPHAN,      "orphan" },
+
+  { SOLVER_REASON_RECOMMENDED,         "recommended" },
+  { SOLVER_REASON_SUPPLEMENTED,                "supplemented" },
+  { 0, 0 }
+};
+
+static const char *
+testcase_reason2str(Id reason)
+{
+  int i;
+  for (i = 0; reason2str[i].str; i++)
+    if (reason == reason2str[i].reason)
+      return reason2str[i].str;
+  return "?";
+}
+
+static struct rclass2str {
+  Id rclass;
+  const char *str;
+} rclass2str[] = {
+  { SOLVER_RULE_PKG, "pkg" },
+  { SOLVER_RULE_UPDATE, "update" },
+  { SOLVER_RULE_FEATURE, "feature" },
+  { SOLVER_RULE_JOB, "job" },
+  { SOLVER_RULE_DISTUPGRADE, "distupgrade" },
+  { SOLVER_RULE_INFARCH, "infarch" },
+  { SOLVER_RULE_CHOICE, "choice" },
+  { SOLVER_RULE_LEARNT, "learnt" },
+  { SOLVER_RULE_BEST, "best" },
+  { SOLVER_RULE_YUMOBS, "yumobs" },
+  { 0, 0 }
+};
+
+static const char *
+testcase_rclass2str(Id rclass)
+{
+  int i;
+  for (i = 0; rclass2str[i].str; i++)
+    if (rclass == rclass2str[i].rclass)
+      return rclass2str[i].str;
+  return "unknown";
+}
+
+static int
+dump_genid(Pool *pool, Strqueue *sq, Id id, int cnt)
+{
+  struct oplist *op;
+  char cntbuf[20];
+  const char *s;
+
+  if (ISRELDEP(id))
+    {
+      Reldep *rd = GETRELDEP(pool, id);
+      for (op = oplist; op->flags; op++)
+       if (rd->flags == op->flags)
+         break;
+      cnt = dump_genid(pool, sq, rd->name, cnt);
+      cnt = dump_genid(pool, sq, rd->evr, cnt);
+      sprintf(cntbuf, "genid %2d: genid ", cnt++);
+      s = pool_tmpjoin(pool, cntbuf, "op ", op->flags ? op->opname : "unknown");
+    }
+  else
+    {
+      sprintf(cntbuf, "genid %2d: genid ", cnt++);
+      s = pool_tmpjoin(pool, cntbuf, id ? "lit " : "null", id ? pool_id2str(pool, id) : 0);
+    }
+  strqueue_push(sq, s);
+  return cnt;
+}
+
+char *
+testcase_solverresult(Solver *solv, int resultflags)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  Id p, op;
+  const char *s;
+  char *result;
+  Strqueue sq;
+
+  strqueue_init(&sq);
+  if ((resultflags & TESTCASE_RESULT_TRANSACTION) != 0)
+    {
+      Transaction *trans = solver_create_transaction(solv);
+      Queue q;
+
+      queue_init(&q);
+      for (i = 0; class2str[i].str; i++)
+       {
+         queue_empty(&q);
+         transaction_classify_pkgs(trans, SOLVER_TRANSACTION_KEEP_PSEUDO, class2str[i].class, 0, 0, &q);
+         for (j = 0; j < q.count; j++)
+           {
+             p = q.elements[j];
+             op = 0;
+             if (pool->installed && pool->solvables[p].repo == pool->installed)
+               op = transaction_obs_pkg(trans, p);
+             s = pool_tmpjoin(pool, class2str[i].str, " ", testcase_solvid2str(pool, p));
+             if (op)
+               s = pool_tmpjoin(pool, s, " ", testcase_solvid2str(pool, op));
+             strqueue_push(&sq, s);
+           }
+       }
+      queue_free(&q);
+      transaction_free(trans);
+    }
+  if ((resultflags & TESTCASE_RESULT_PROBLEMS) != 0)
+    {
+      char *probprefix, *solprefix;
+      int problem, solution, element;
+      int pcnt, scnt;
+
+      pcnt = solver_problem_count(solv);
+      for (problem = 1; problem <= pcnt; problem++)
+       {
+         Id rid, from, to, dep;
+         SolverRuleinfo rinfo;
+         rid = solver_findproblemrule(solv, problem);
+         s = testcase_problemid(solv, problem);
+         probprefix = solv_dupjoin("problem ", s, 0);
+         rinfo = solver_ruleinfo(solv, rid, &from, &to, &dep);
+         s = pool_tmpjoin(pool, probprefix, " info ", solver_problemruleinfo2str(solv, rinfo, from, to, dep));
+         strqueue_push(&sq, s);
+         scnt = solver_solution_count(solv, problem);
+         for (solution = 1; solution <= scnt; solution++)
+           {
+             s = testcase_solutionid(solv, problem, solution);
+             solprefix = solv_dupjoin(probprefix, " solution ", s);
+             element = 0;
+             while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &op)) != 0)
+               {
+                 if (p == SOLVER_SOLUTION_JOB)
+                   s = pool_tmpjoin(pool, solprefix, " deljob ", testcase_job2str(pool, solv->job.elements[op - 1], solv->job.elements[op]));
+                 else if (p > 0 && op == 0)
+                   s = pool_tmpjoin(pool, solprefix, " erase ", testcase_solvid2str(pool, p));
+                 else if (p > 0 && op > 0)
+                   {
+                     s = pool_tmpjoin(pool, solprefix, " replace ", testcase_solvid2str(pool, p));
+                     s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, op));
+                   }
+                 else if (p < 0 && op > 0)
+                   s = pool_tmpjoin(pool, solprefix, " allow ", testcase_solvid2str(pool, op));
+                 else
+                   s = pool_tmpjoin(pool, solprefix, " unknown", 0);
+                 strqueue_push(&sq, s);
+               }
+             solv_free(solprefix);
+           }
+         solv_free(probprefix);
+       }
+    }
+
+  if ((resultflags & TESTCASE_RESULT_ORPHANED) != 0)
+    {
+      Queue q;
+
+      queue_init(&q);
+      solver_get_orphaned(solv, &q);
+      for (i = 0; i < q.count; i++)
+       {
+         s = pool_tmpjoin(pool, "orphaned ", testcase_solvid2str(pool, q.elements[i]), 0);
+         strqueue_push(&sq, s);
+       }
+      queue_free(&q);
+    }
+
+  if ((resultflags & TESTCASE_RESULT_RECOMMENDED) != 0)
+    {
+      Queue qr, qs;
+
+      queue_init(&qr);
+      queue_init(&qs);
+      solver_get_recommendations(solv, &qr, &qs, 0);
+      for (i = 0; i < qr.count; i++)
+       {
+         s = pool_tmpjoin(pool, "recommended ", testcase_solvid2str(pool, qr.elements[i]), 0);
+         strqueue_push(&sq, s);
+       }
+      for (i = 0; i < qs.count; i++)
+       {
+         s = pool_tmpjoin(pool, "suggested ", testcase_solvid2str(pool, qs.elements[i]), 0);
+         strqueue_push(&sq, s);
+       }
+      queue_free(&qr);
+      queue_free(&qs);
+    }
+
+  if ((resultflags & TESTCASE_RESULT_UNNEEDED) != 0)
+    {
+      Queue q, qf;
+
+      queue_init(&q);
+      queue_init(&qf);
+      solver_get_unneeded(solv, &q, 0);
+      solver_get_unneeded(solv, &qf, 1);
+      for (i = j = 0; i < q.count; i++)
+       {
+         /* we rely on qf containing a subset of q in the same order */
+         if (j < qf.count && q.elements[i] == qf.elements[j])
+           {
+             s = pool_tmpjoin(pool, "unneeded_filtered ", testcase_solvid2str(pool, q.elements[i]), 0);
+             j++;
+           }
+         else
+           s = pool_tmpjoin(pool, "unneeded ", testcase_solvid2str(pool, q.elements[i]), 0);
+         strqueue_push(&sq, s);
+       }
+      queue_free(&q);
+      queue_free(&qf);
+    }
+  if ((resultflags & TESTCASE_RESULT_ALTERNATIVES) != 0)
+    {
+      char *altprefix;
+      Queue q, rq;
+      int cnt;
+      Id alternative;
+      queue_init(&q);
+      queue_init(&rq);
+      cnt = solver_alternatives_count(solv);
+      for (alternative = 1; alternative <= cnt; alternative++)
+       {
+         Id id, from, chosen;
+         char num[20];
+         int type = solver_get_alternative(solv, alternative, &id, &from, &chosen, &q, 0);
+         altprefix = solv_dupjoin("alternative ", testcase_alternativeid(solv, type, id, from), " ");
+         strcpy(num, " 0 ");
+         if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+           {
+             char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, from));
+             s = pool_tmpappend(pool, s, " recommends ", testcase_dep2str(pool, id));
+             strqueue_push(&sq, s);
+           }
+         else if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+           {
+             /* map choice rules back to pkg rules */
+             if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
+               id = solver_rule2pkgrule(solv, id);
+             solver_allruleinfos(solv, id, &rq);
+             for (i = 0; i < rq.count; i += 4)
+               {
+                 int rtype = rq.elements[i];
+                 if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
+                   {
+                     const char *js = testcase_job2str(pool, rq.elements[i + 2], rq.elements[i + 3]);
+                     char *s = pool_tmpjoin(pool, altprefix, num, " job ");
+                     s = pool_tmpappend(pool, s, js, 0);
+                     strqueue_push(&sq, s);
+                   }
+                 else if (rtype == SOLVER_RULE_PKG_REQUIRES)
+                   {
+                     char *s = pool_tmpjoin(pool, altprefix, num, testcase_solvid2str(pool, rq.elements[i + 1]));
+                     s = pool_tmpappend(pool, s, " requires ", testcase_dep2str(pool, rq.elements[i + 3]));
+                     strqueue_push(&sq, s);
+                   }
+               }
+           }
+         for (i = 0; i < q.count; i++)
+           {
+             Id p = q.elements[i];
+             if (i >= 9)
+               num[0] = '0' + (i + 1) / 10;
+             num[1] = '0' + (i + 1) % 10;
+             if (-p == chosen)
+               s = pool_tmpjoin(pool, altprefix, num, "+ ");
+             else if (p < 0)
+               s = pool_tmpjoin(pool, altprefix, num, "- ");
+             else if (p >= 0)
+               s = pool_tmpjoin(pool, altprefix, num, "  ");
+             s = pool_tmpappend(pool, s,  testcase_solvid2str(pool, p < 0 ? -p : p), 0);
+             strqueue_push(&sq, s);
+           }
+         solv_free(altprefix);
+       }
+      queue_free(&q);
+      queue_free(&rq);
+    }
+  if ((resultflags & TESTCASE_RESULT_RULES) != 0)
+    {
+      /* dump all rules */
+      Id rid;
+      SolverRuleinfo rclass;
+      Queue q;
+      int i;
+
+      queue_init(&q);
+      for (rid = 1; (rclass = solver_ruleclass(solv, rid)) != SOLVER_RULE_UNKNOWN; rid++)
+       {
+         char *prefix = solv_dupjoin("rule ", testcase_rclass2str(rclass), " ");
+         prefix = solv_dupappend(prefix, testcase_ruleid(solv, rid), 0);
+         solver_ruleliterals(solv, rid, &q);
+         if (rclass == SOLVER_RULE_FEATURE && q.count == 1 && q.elements[0] == -SYSTEMSOLVABLE)
+           continue;
+         for (i = 0; i < q.count; i++)
+           {
+             Id p = q.elements[i];
+             const char *s;
+             if (p < 0)
+               s = pool_tmpjoin(pool, prefix, " -", testcase_solvid2str(pool, -p));
+             else
+               s = pool_tmpjoin(pool, prefix, "  ", testcase_solvid2str(pool, p));
+             strqueue_push(&sq, s);
+           }
+         solv_free(prefix);
+       }
+      queue_free(&q);
+    }
+  if ((resultflags & TESTCASE_RESULT_GENID) != 0)
+    {
+      for (i = 0 ; i < solv->job.count; i += 2)
+       {
+         Id id, id2;
+         if (solv->job.elements[i] != (SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES))
+           continue;
+         id = solv->job.elements[i + 1];
+         s = testcase_dep2str(pool, id);
+         strqueue_push(&sq, pool_tmpjoin(pool, "genid dep ", s, 0));
+         if ((id2 = testcase_str2dep(pool, s)) != id)
+           {
+             s = pool_tmpjoin(pool, "genid roundtrip error: ", testcase_dep2str(pool, id2), 0);
+             strqueue_push(&sq, s);
+           }
+         dump_genid(pool, &sq, id, 1);
+       }
+    }
+  if ((resultflags & TESTCASE_RESULT_REASON) != 0)
+    {
+      Queue whyq;
+      queue_init(&whyq);
+      FOR_POOL_SOLVABLES(p)
+       {
+         Id info, p2, id;
+          int reason = solver_describe_decision(solv, p, &info);
+         if (reason == SOLVER_REASON_UNRELATED)
+           continue;
+         if (reason == SOLVER_REASON_WEAKDEP)
+           {
+             solver_describe_weakdep_decision(solv, p, &whyq);
+             if (whyq.count)
+               {
+                 for (i = 0; i < whyq.count; i += 3)
+                   {
+                     reason = whyq.elements[i];
+                     p2 = whyq.elements[i + 1];
+                     id = whyq.elements[i + 2];
+                     s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0);
+                     s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason));
+                     s = pool_tmpappend(pool, s, " ", testcase_dep2str(pool, id));
+                     if (p2)
+                       s = pool_tmpappend(pool, s, " ", testcase_solvid2str(pool, p2));
+                     strqueue_push(&sq, s);
+                   }
+                 continue;
+               }
+           }
+         s = pool_tmpjoin(pool, "reason ", testcase_solvid2str(pool, p), 0);
+         s = pool_tmpappend(pool, s, " ", testcase_reason2str(reason));
+         if (info)
+           s = pool_tmpappend(pool, s, " ", testcase_ruleid(solv, info));
+         strqueue_push(&sq, s);
+       }
+      queue_free(&whyq);
+    }
+  if ((resultflags & TESTCASE_RESULT_CLEANDEPS) != 0)
+    {
+      Queue q;
+
+      queue_init(&q);
+      solver_get_cleandeps(solv, &q);
+      for (i = 0; i < q.count; i++)
+       {
+         s = pool_tmpjoin(pool, "cleandeps ", testcase_solvid2str(pool, q.elements[i]), 0);
+         strqueue_push(&sq, s);
+       }
+      queue_free(&q);
+    }
+  if ((resultflags & TESTCASE_RESULT_JOBS) != 0)
+    {
+      for (i = 0; i < solv->job.count; i += 2)
+       {
+         s = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]);
+         s = pool_tmpjoin(pool, "job ", s, 0);
+         strqueue_push(&sq, s);
+       }
+    }
+  strqueue_sort(&sq);
+  result = strqueue_join(&sq);
+  strqueue_free(&sq);
+  return result;
+}
+
+
+static int
+testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
+{
+  Pool *pool = solv->pool;
+  Repo *repo;
+  int i;
+  Id arch, repoid;
+  Id lowscore;
+  FILE *fp;
+  Strqueue sq;
+  char *cmd, *out;
+  const char *s;
+
+  if (!testcasename)
+    testcasename = "testcase.t";
+  if (!resultname)
+    resultname = "solver.result";
+
+  if (mkdir(dir, 0777) && errno != EEXIST)
+    return pool_error(solv->pool, 0, "testcase_write: could not create directory '%s'", dir);
+  strqueue_init(&sq);
+  FOR_REPOS(repoid, repo)
+    {
+      const char *name = testcase_repoid2str(pool, repoid);
+      char priobuf[50];
+      if (repo->subpriority)
+       sprintf(priobuf, "%d.%d", repo->priority, repo->subpriority);
+      else
+       sprintf(priobuf, "%d", repo->priority);
+      out = pool_tmpjoin(pool, name, ".repo", ".gz");
+      for (i = 0; out[i]; i++)
+       if (out[i] == '/')
+         out[i] = '_';
+      cmd = pool_tmpjoin(pool, "repo ", name, " ");
+      cmd = pool_tmpappend(pool, cmd, priobuf, " ");
+      cmd = pool_tmpappend(pool, cmd, "testtags ", out);
+      strqueue_push(&sq, cmd);
+      out = pool_tmpjoin(pool, dir, "/", out);
+      if (!(fp = solv_xfopen(out, "w")))
+       {
+         pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
+         strqueue_free(&sq);
+         return 0;
+       }
+      testcase_write_testtags(repo, fp);
+      if (fclose(fp))
+       {
+         pool_error(solv->pool, 0, "testcase_write: write error");
+         strqueue_free(&sq);
+         return 0;
+       }
+    }
+  /* hmm, this is not optimal... we currently search for the lowest score */
+  lowscore = 0;
+  arch = pool->solvables[SYSTEMSOLVABLE].arch;
+  for (i = 0; i < pool->lastarch; i++)
+    {
+      if (pool->id2arch[i] == 1 && !lowscore)
+       arch = i;
+      if (pool->id2arch[i] > 0x10000 && (!lowscore || pool->id2arch[i] < lowscore))
+       {
+         arch = i;
+         lowscore = pool->id2arch[i];
+       }
+    }
+  cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "unset", 0);
+  for (i = 0; disttype2str[i].str != 0; i++)
+    if (pool->disttype == disttype2str[i].type)
+      break;
+  pool_tmpappend(pool, cmd, " ", disttype2str[i].str ? disttype2str[i].str : "unknown");
+  if (pool->installed)
+    cmd = pool_tmpappend(pool, cmd, " ", testcase_repoid2str(pool, pool->installed->repoid));
+  strqueue_push(&sq, cmd);
+  s = testcase_getpoolflags(solv->pool);
+  if (*s)
+    {
+      cmd = pool_tmpjoin(pool, "poolflags ", s, 0);
+      strqueue_push(&sq, cmd);
+    }
+
+  if (pool->vendorclasses)
+    {
+      cmd = 0;
+      for (i = 0; pool->vendorclasses[i]; i++)
+       {
+         cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", pool->vendorclasses[i]);
+         if (!pool->vendorclasses[i + 1])
+           {
+             strqueue_push(&sq, cmd);
+             cmd = 0;
+             i++;
+           }
+       }
+    }
+
+  /* dump disabled packages (must come before the namespace/job lines) */
+  if (pool->considered)
+    {
+      Id p;
+      FOR_POOL_SOLVABLES(p)
+       if (!MAPTST(pool->considered, p))
+         {
+           cmd = pool_tmpjoin(pool, "disable pkg ", testcase_solvid2str(pool, p), 0);
+           strqueue_push(&sq, cmd);
+         }
+    }
+
+  s = testcase_getsolverflags(solv);
+  if (*s)
+    {
+      cmd = pool_tmpjoin(pool, "solverflags ", s, 0);
+      strqueue_push(&sq, cmd);
+    }
+
+  /* now dump all the ns callback values we know */
+  if (pool->nscallback)
+    {
+      Id rid;
+      int d;
+      for (rid = 1; rid < pool->nrels; rid++)
+       {
+         Reldep *rd = pool->rels + rid;
+         if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
+           continue;
+         /* evaluate all namespace ids, skip empty results */
+         d = pool_whatprovides(pool, MAKERELDEP(rid));
+         if (!d || !pool->whatprovidesdata[d])
+           continue;
+         cmd = pool_tmpjoin(pool, "namespace ", pool_id2str(pool, rd->name), "(");
+         cmd = pool_tmpappend(pool, cmd, pool_id2str(pool, rd->evr), ")");
+         for (;  pool->whatprovidesdata[d]; d++)
+           cmd = pool_tmpappend(pool, cmd, " ", testcase_solvid2str(pool, pool->whatprovidesdata[d]));
+         strqueue_push(&sq, cmd);
+       }
+    }
+
+  for (i = 0; i < solv->job.count; i += 2)
+    {
+      cmd = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]);
+      cmd = pool_tmpjoin(pool, "job ", cmd, 0);
+      strqueue_push(&sq, cmd);
+    }
+
+  if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) != 0)
+    {
+      char *result;
+      cmd = 0;
+      for (i = 0; resultflags2str[i].str; i++)
+       if ((resultflags & resultflags2str[i].flag) != 0)
+         cmd = pool_tmpappend(pool, cmd, cmd ? "," : 0, resultflags2str[i].str);
+      cmd = pool_tmpjoin(pool, "result ", cmd ? cmd : "?", 0);
+      cmd = pool_tmpappend(pool, cmd, " ", resultname);
+      strqueue_push(&sq, cmd);
+      result = testcase_solverresult(solv, resultflags);
+      if (!strcmp(resultname, "<inline>"))
+       {
+         int i;
+         Strqueue rsq;
+         strqueue_init(&rsq);
+         strqueue_split(&rsq, result);
+         for (i = 0; i < rsq.nstr; i++)
+           {
+             cmd = pool_tmpjoin(pool, "#>", rsq.str[i], 0);
+             strqueue_push(&sq, cmd);
+           }
+         strqueue_free(&rsq);
+       }
+      else
+       {
+         out = pool_tmpjoin(pool, dir, "/", resultname);
+         if (!(fp = fopen(out, "w")))
+           {
+             pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
+             solv_free(result);
+             strqueue_free(&sq);
+             return 0;
+           }
+         if (result && *result && fwrite(result, strlen(result), 1, fp) != 1)
+           {
+             pool_error(solv->pool, 0, "testcase_write: write error");
+             solv_free(result);
+             strqueue_free(&sq);
+             fclose(fp);
+             return 0;
+           }
+         if (fclose(fp))
+           {
+             pool_error(solv->pool, 0, "testcase_write: write error");
+             strqueue_free(&sq);
+             return 0;
+           }
+       }
+      solv_free(result);
+    }
+
+  cmd = strqueue_join(&sq);
+  out = pool_tmpjoin(pool, dir, "/", testcasename);
+  if (!(fp = fopen(out, "w")))
+    {
+      pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
+      strqueue_free(&sq);
+      return 0;
+    }
+  if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1)
+    {
+      pool_error(solv->pool, 0, "testcase_write: write error");
+      strqueue_free(&sq);
+      fclose(fp);
+      return 0;
+    }
+  if (fclose(fp))
+    {
+      pool_error(solv->pool, 0, "testcase_write: write error");
+      strqueue_free(&sq);
+      return 0;
+    }
+  solv_free(cmd);
+  strqueue_free(&sq);
+  return 1;
+}
+
+int
+testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
+{
+  Pool *pool = solv->pool;
+  int i, r, repoid;
+  int mangle = 1;
+  const char **orignames;
+
+  /* mangle repo names so that there are no conflicts */
+  orignames = solv_calloc(pool->nrepos, sizeof(char *));
+  for (repoid = 1; repoid < pool->nrepos; repoid++)
+    {
+      Repo *repo = pool_id2repo(pool, repoid);
+      char *buf = solv_malloc((repo->name ? strlen(repo->name) : 0) + 40);
+      char *mp;
+      orignames[repoid] = repo->name;
+      if (!repo->name || !repo->name[0])
+        sprintf(buf, "#%d", repoid);
+      else
+       strcpy(buf, repo->name);
+      for (i = 0; buf[i]; i++)
+       if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '/')
+         buf[i] = '_';
+      mp = buf + strlen(buf);
+      for (;;)
+       {
+         for (i = 1; i < repoid; i++)
+           if (!strcmp(buf, pool_id2repo(pool, i)->name))
+             break;
+         if (i == repoid)
+           break;
+          sprintf(mp, "_%d", mangle++);
+       }
+      repo->name = buf;
+    }
+  r = testcase_write_mangled(solv, dir, resultflags, testcasename, resultname);
+  for (repoid = 1; repoid < pool->nrepos; repoid++)
+    {
+      Repo *repo = pool_id2repo(pool, repoid);
+      solv_free((void *)repo->name);
+      repo->name = orignames[repoid];
+    }
+  solv_free(orignames);
+  return r;
+}
+
+static char *
+read_inline_file(FILE *fp, char **bufp, char **bufpp, int *buflp)
+{
+  char *result = solv_malloc(1024);
+  char *rp = result;
+  int resultl = 1024;
+
+  for (;;)
+    {
+      size_t rl;
+      if (rp - result + 256 >= resultl)
+       {
+         resultl = rp - result;
+         result = solv_realloc(result, resultl + 1024);
+         rp = result + resultl;
+         resultl += 1024;
+       }
+      if (!fgets(rp, resultl - (rp - result), fp))
+       *rp = 0;
+      rl = strlen(rp);
+      if (rl && (rp == result || rp[-1] == '\n'))
+       {
+         if (rl > 1 && rp[0] == '#' && rp[1] == '>')
+           {
+             memmove(rp, rp + 2, rl - 2);
+             rl -= 2;
+           }
+         else
+           {
+             while (rl + 16 > *buflp)
+               {
+                 *bufp = solv_realloc(*bufp, *buflp + 512);
+                 *buflp += 512;
+               }
+             memmove(*bufp, rp, rl);
+             if ((*bufp)[rl - 1] == '\n')
+               {
+                 ungetc('\n', fp);
+                 rl--;
+               }
+             (*bufp)[rl] = 0;
+             (*bufpp) = *bufp + rl;
+             rl = 0;
+           }
+       }
+      if (rl <= 0)
+       {
+         *rp = 0;
+         break;
+       }
+      rp += rl;
+    }
+  return result;
+}
+
+static char *
+read_file(FILE *fp)
+{
+  char *result = solv_malloc(1024);
+  char *rp = result;
+  int resultl = 1024;
+
+  for (;;)
+    {
+      size_t rl;
+      if (rp - result + 256 >= resultl)
+       {
+         resultl = rp - result;
+         result = solv_realloc(result, resultl + 1024);
+         rp = result + resultl;
+         resultl += 1024;
+       }
+      rl = fread(rp, 1, resultl - (rp - result), fp);
+      if (rl <= 0)
+       {
+         *rp = 0;
+         break;
+       }
+      rp += rl;
+    }
+  return result;
+}
+
+static int
+str2resultflags(Pool *pool, char *s)   /* modifies the string! */
+{
+  int i, resultflags = 0;
+  while (s)
+    {
+      char *se = strchr(s, ',');
+      if (se)
+       *se++ = 0;
+      for (i = 0; resultflags2str[i].str; i++)
+       if (!strcmp(s, resultflags2str[i].str))
+         {
+           resultflags |= resultflags2str[i].flag;
+           break;
+         }
+      if (!resultflags2str[i].str)
+       pool_error(pool, 0, "result: unknown flag '%s'", s);
+      s = se;
+    }
+  return resultflags;
+}
+
+Solver *
+testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **resultp, int *resultflagsp)
+{
+  Solver *solv;
+  char *buf, *bufp;
+  int bufl;
+  char *testcasedir, *s;
+  int l;
+  char **pieces = 0;
+  int npieces = 0;
+  int prepared = 0;
+  int closefp = !fp;
+  int poolflagsreset = 0;
+  int missing_features = 0;
+  Id *genid = 0;
+  int ngenid = 0;
+  Queue autoinstq;
+
+  if (resultp)
+    *resultp = 0;
+  if (resultflagsp)
+    *resultflagsp = 0;
+  if (!fp && !(fp = fopen(testcase, "r")))
+    {
+      pool_error(pool, 0, "testcase_read: could not open '%s'", testcase);
+      return 0;
+    }
+  testcasedir = solv_strdup(testcase);
+  if ((s = strrchr(testcasedir, '/')) != 0)
+    s[1] = 0;
+  else
+    *testcasedir = 0;
+  bufl = 1024;
+  buf = solv_malloc(bufl);
+  bufp = buf;
+  solv = 0;
+  queue_init(&autoinstq);
+  for (;;)
+    {
+      if (bufp - buf + 16 > bufl)
+       {
+         bufl = bufp - buf;
+         buf = solv_realloc(buf, bufl + 512);
+         bufp = buf + bufl;
+          bufl += 512;
+       }
+      if (!fgets(bufp, bufl - (bufp - buf), fp))
+       break;
+      bufp = buf;
+      l = strlen(buf);
+      if (!l || buf[l - 1] != '\n')
+       {
+         bufp += l;
+         continue;
+       }
+      buf[--l] = 0;
+      s = buf;
+      while (*s && (*s == ' ' || *s == '\t'))
+       s++;
+      if (!*s || *s == '#')
+       continue;
+      npieces = 0;
+      /* split it in pieces */
+      for (;;)
+       {
+         while (*s == ' ' || *s == '\t')
+           s++;
+         if (!*s)
+           break;
+         pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
+         pieces[npieces++] = s;
+         while (*s && *s != ' ' && *s != '\t')
+           s++;
+         if (*s)
+           *s++ = 0;
+       }
+      pieces = solv_extend(pieces, npieces, 1, sizeof(*pieces), 7);
+      pieces[npieces] = 0;
+      if (!strcmp(pieces[0], "repo") && npieces >= 4)
+       {
+         Repo *repo = repo_create(pool, pieces[1]);
+         FILE *rfp;
+         int prio, subprio;
+         const char *rdata;
+
+         prepared = 0;
+          if (!poolflagsreset)
+           {
+             poolflagsreset = 1;
+             testcase_resetpoolflags(pool);    /* hmm */
+           }
+         if (sscanf(pieces[2], "%d.%d", &prio, &subprio) != 2)
+           {
+             subprio = 0;
+             prio = atoi(pieces[2]);
+           }
+          repo->priority = prio;
+          repo->subpriority = subprio;
+         if (strcmp(pieces[3], "empty") != 0)
+           {
+             const char *repotype = pool_tmpjoin(pool, pieces[3], 0, 0);       /* gets overwritten in <inline> case */
+             if (!strcmp(pieces[4], "<inline>"))
+               {
+                 char *idata = read_inline_file(fp, &buf, &bufp, &bufl);
+                 rdata = "<inline>";
+                 rfp = solv_xfopen_buf(rdata, &idata, 0, "rf");
+               }
+             else
+               {
+                 rdata = pool_tmpjoin(pool, testcasedir, pieces[4], 0);
+                 rfp = solv_xfopen(rdata, "r");
+               }
+             if (!rfp)
+               {
+                 pool_error(pool, 0, "testcase_read: could not open '%s'", rdata);
+               }
+             else if (!strcmp(repotype, "testtags"))
+               {
+                 testcase_add_testtags(repo, rfp, 0);
+                 fclose(rfp);
+               }
+             else if (!strcmp(repotype, "solv"))
+               {
+                 repo_add_solv(repo, rfp, 0);
+                 fclose(rfp);
+               }
+#if ENABLE_TESTCASE_HELIXREPO
+             else if (!strcmp(repotype, "helix"))
+               {
+                 repo_add_helix(repo, rfp, 0);
+                 fclose(rfp);
+               }
+#endif
+             else
+               {
+                 fclose(rfp);
+                 pool_error(pool, 0, "testcase_read: unknown repo type for repo '%s'", repo->name);
+               }
+           }
+       }
+      else if (!strcmp(pieces[0], "system") && npieces >= 3)
+       {
+         int i;
+
+         /* must set the disttype before the arch */
+         prepared = 0;
+         if (strcmp(pieces[2], "*") != 0)
+           {
+             char *dp = pieces[2];
+             while (dp && *dp)
+               {
+                 char *dpe = strchr(dp, ',');
+                 if (dpe)
+                   *dpe = 0;
+                 for (i = 0; disttype2str[i].str != 0; i++)
+                   if (!strcmp(disttype2str[i].str, dp))
+                     break;
+                 if (dpe)
+                   *dpe++ = ',';
+                 if (disttype2str[i].str)
+                   {
+#ifdef MULTI_SEMANTICS
+                     if (pool->disttype != disttype2str[i].type)
+                       pool_setdisttype(pool, disttype2str[i].type);
+#endif
+                     if (pool->disttype == disttype2str[i].type)
+                       break;
+                   }
+                 dp = dpe;
+               }
+             if (!(dp && *dp))
+               {
+                 pool_error(pool, 0, "testcase_read: system: could not change disttype to '%s'", pieces[2]);
+                 missing_features = 1;
+               }
+           }
+         if (strcmp(pieces[1], "unset") == 0)
+           pool_setarch(pool, 0);
+         else if (pieces[1][0] == ':')
+           pool_setarchpolicy(pool, pieces[1] + 1);
+         else
+           pool_setarch(pool, pieces[1]);
+         if (npieces > 3)
+           {
+             Repo *repo = testcase_str2repo(pool, pieces[3]);
+             if (!repo)
+               pool_error(pool, 0, "testcase_read: system: unknown repo '%s'", pieces[3]);
+             else
+               pool_set_installed(pool, repo);
+           }
+       }
+      else if (!strcmp(pieces[0], "job") && npieces > 1)
+       {
+         char *sp;
+         Id how, what;
+         if (prepared <= 0)
+           {
+             pool_addfileprovides(pool);
+             pool_createwhatprovides(pool);
+             prepared = 1;
+           }
+         if (npieces >= 3 && !strcmp(pieces[2], "selection"))
+           {
+             addselectionjob(pool, pieces + 1, npieces - 1, job, 0, 0);
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdeps"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPS, pool_str2id(pool, pieces[3], 1));
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdepid"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPID, pool_str2id(pool, pieces[3], 1));
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchsolvable"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHSOLVABLE, pool_str2id(pool, pieces[3], 1));
+             continue;
+           }
+         /* rejoin */
+         for (sp = pieces[1]; sp < pieces[npieces - 1]; sp++)
+           if (*sp == 0)
+             *sp = ' ';
+         how = testcase_str2job(pool, pieces[1], &what);
+         if (how >= 0 && job)
+           queue_push2(job, how, what);
+       }
+      else if (!strcmp(pieces[0], "vendorclass") && npieces > 1)
+       {
+         pool_addvendorclass(pool, (const char **)(pieces + 1));
+       }
+      else if (!strcmp(pieces[0], "namespace") && npieces > 1)
+       {
+         int i = strlen(pieces[1]);
+         s = strchr(pieces[1], '(');
+         if (!s && pieces[1][i - 1] != ')')
+           {
+             pool_error(pool, 0, "testcase_read: bad namespace '%s'", pieces[1]);
+           }
+         else
+           {
+             Id name, evr, id;
+             Queue q;
+             queue_init(&q);
+             *s = 0;
+             pieces[1][i - 1] = 0;
+             name = pool_str2id(pool, pieces[1], 1);
+             evr = pool_str2id(pool, s + 1, 1);
+             *s = '(';
+             pieces[1][i - 1] = ')';
+             id = pool_rel2id(pool, name, evr, REL_NAMESPACE, 1);
+             for (i = 2; i < npieces; i++)
+               queue_push(&q, testcase_str2solvid(pool, pieces[i]));
+             /* now do the callback */
+             if (prepared <= 0)
+               {
+                 pool_addfileprovides(pool);
+                 pool_createwhatprovides(pool);
+                 prepared = 1;
+               }
+             pool->whatprovides_rel[GETRELID(id)] = pool_queuetowhatprovides(pool, &q);
+             queue_free(&q);
+           }
+       }
+      else if (!strcmp(pieces[0], "poolflags"))
+        {
+         int i;
+          if (!poolflagsreset)
+           {
+             poolflagsreset = 1;
+             testcase_resetpoolflags(pool);    /* hmm */
+           }
+         for (i = 1; i < npieces; i++)
+           testcase_setpoolflags(pool, pieces[i]);
+        }
+      else if (!strcmp(pieces[0], "solverflags") && npieces > 1)
+        {
+         int i;
+         if (!solv)
+           {
+             solv = solver_create(pool);
+             testcase_resetsolverflags(solv);
+           }
+         for (i = 1; i < npieces; i++)
+           testcase_setsolverflags(solv, pieces[i]);
+        }
+      else if (!strcmp(pieces[0], "result") && npieces > 1)
+       {
+         char *result = 0;
+         int resultflags = str2resultflags(pool, pieces[1]);
+         const char *rdata;
+         if (npieces > 2)
+           {
+             rdata = pool_tmpjoin(pool, testcasedir, pieces[2], 0);
+             if (!strcmp(pieces[2], "<inline>"))
+               result = read_inline_file(fp, &buf, &bufp, &bufl);
+             else
+               {
+                 FILE *rfp = fopen(rdata, "r");
+                 if (!rfp)
+                   pool_error(pool, 0, "testcase_read: could not open '%s'", rdata);
+                 else
+                   {
+                     result = read_file(rfp);
+                     fclose(rfp);
+                   }
+               }
+           }
+         if (resultp)
+           *resultp = result;
+         else
+           solv_free(result);
+         if (resultflagsp)
+           *resultflagsp = resultflags;
+       }
+      else if (!strcmp(pieces[0], "nextjob"))
+       {
+         if (npieces == 2 && resultflagsp && !strcmp(pieces[1], "reusesolver"))
+           *resultflagsp |= TESTCASE_RESULT_REUSE_SOLVER;
+         break;
+       }
+      else if (!strcmp(pieces[0], "disable") && npieces == 3)
+       {
+         Id p;
+         if (strcmp(pieces[1], "pkg"))
+           {
+             pool_error(pool, 0, "testcase_read: bad disable type '%s'", pieces[1]);
+             continue;
+           }
+         if (!prepared)
+           pool_createwhatprovides(pool);
+         prepared = -1;
+         if (!pool->considered)
+           {
+             pool->considered = solv_calloc(1, sizeof(Map));
+             map_init(pool->considered, pool->nsolvables);
+             map_setall(pool->considered);
+           }
+         p = testcase_str2solvid(pool, pieces[2]);
+         if (p)
+           MAPCLR(pool->considered, p);
+         else
+           pool_error(pool, 0, "disable: unknown package '%s'", pieces[2]);
+       }
+      else if (!strcmp(pieces[0], "feature"))
+       {
+         int i, j;
+         for (i = 1; i < npieces; i++)
+           {
+             for (j = 0; features[j]; j++)
+               if (!strcmp(pieces[i], features[j]))
+                 break;
+             if (!features[j])
+               {
+                 pool_error(pool, 0, "testcase_read: missing feature '%s'", pieces[i]);
+                 missing_features++;
+               }
+           }
+         if (missing_features)
+           break;
+       }
+      else if (!strcmp(pieces[0], "genid") && npieces > 1)
+       {
+         Id id;
+         /* rejoin */
+         if (npieces > 2)
+           {
+             char *sp;
+             for (sp = pieces[2]; sp < pieces[npieces - 1]; sp++)
+               if (*sp == 0)
+                 *sp = ' ';
+           }
+         genid = solv_extend(genid, ngenid, 1, sizeof(*genid), 7);
+         if (!strcmp(pieces[1], "op") && npieces > 2)
+           {
+             struct oplist *op;
+             for (op = oplist; op->flags; op++)
+               if (!strncmp(pieces[2], op->opname, strlen(op->opname)))
+                 break;
+             if (!op->flags)
+               {
+                 pool_error(pool, 0, "testcase_read: genid: unknown op '%s'", pieces[2]);
+                 break;
+               }
+             if (ngenid < 2)
+               {
+                 pool_error(pool, 0, "testcase_read: genid: out of stack");
+                 break;
+               }
+             ngenid -= 2;
+             id = pool_rel2id(pool, genid[ngenid] , genid[ngenid + 1], op->flags, 1);
+           }
+         else if (!strcmp(pieces[1], "lit"))
+           id = pool_str2id(pool, npieces > 2 ? pieces[2] : "", 1);
+         else if (!strcmp(pieces[1], "null"))
+           id = 0;
+         else if (!strcmp(pieces[1], "dep"))
+           id = testcase_str2dep(pool, pieces[2]);
+         else
+           {
+             pool_error(pool, 0, "testcase_read: genid: unknown command '%s'", pieces[1]);
+             break;
+           }
+         genid[ngenid++] = id;
+       }
+      else if (!strcmp(pieces[0], "autoinst") && npieces > 2)
+       {
+         if (strcmp(pieces[1], "name"))
+           {
+             pool_error(pool, 0, "testcase_read: autoinst: illegal mode");
+             break;
+           }
+         queue_push(&autoinstq, pool_str2id(pool, pieces[2], 1));
+       }
+      else if (!strcmp(pieces[0], "evrcmp") && npieces == 3)
+       {
+         Id evr1 = pool_str2id(pool, pieces[1], 1);
+         Id evr2 = pool_str2id(pool, pieces[2], 1);
+         int r = pool_evrcmp(pool, evr1, evr2, EVRCMP_COMPARE);
+         r = r < 0 ? REL_LT : r > 0 ? REL_GT : REL_EQ;
+         queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, evr1, evr2, r, 1));
+       }
+      else
+       {
+         pool_error(pool, 0, "testcase_read: cannot parse command '%s'", pieces[0]);
+       }
+    }
+  while (job && ngenid > 0)
+    queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, genid[--ngenid]);
+  if (autoinstq.count)
+    pool_add_userinstalled_jobs(pool, &autoinstq, job, GET_USERINSTALLED_NAMES | GET_USERINSTALLED_INVERTED);
+  queue_free(&autoinstq);
+  genid = solv_free(genid);
+  buf = solv_free(buf);
+  pieces = solv_free(pieces);
+  solv_free(testcasedir);
+  if (!prepared)
+    {
+      pool_addfileprovides(pool);
+      pool_createwhatprovides(pool);
+    }
+  if (!solv)
+    {
+      solv = solver_create(pool);
+      testcase_resetsolverflags(solv);
+    }
+  if (closefp)
+    fclose(fp);
+  if (missing_features)
+    {
+      solver_free(solv);
+      solv = 0;
+      if (resultflagsp)
+       *resultflagsp = 77;     /* hack for testsolv */
+    }
+  return solv;
+}
+
+char *
+testcase_resultdiff(const char *result1, const char *result2)
+{
+  Strqueue sq1, sq2, osq;
+  char *r;
+  strqueue_init(&sq1);
+  strqueue_init(&sq2);
+  strqueue_init(&osq);
+  strqueue_split(&sq1, result1);
+  strqueue_split(&sq2, result2);
+  strqueue_sort(&sq1);
+  strqueue_sort(&sq2);
+  strqueue_diff(&sq1, &sq2, &osq);
+  r = osq.nstr ? strqueue_join(&osq) : 0;
+  strqueue_free(&sq1);
+  strqueue_free(&sq2);
+  strqueue_free(&osq);
+  return r;
+}
+
diff --git a/libsolv-0.7.2/ext/testcase.h b/libsolv-0.7.2/ext/testcase.h
new file mode 100644 (file)
index 0000000..387a506
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include "pool.h"
+#include "repo.h"
+#include "solver.h"
+
+#define TESTCASE_RESULT_TRANSACTION    (1 << 0)
+#define TESTCASE_RESULT_PROBLEMS       (1 << 1)
+#define TESTCASE_RESULT_ORPHANED       (1 << 2)
+#define TESTCASE_RESULT_RECOMMENDED    (1 << 3)
+#define TESTCASE_RESULT_UNNEEDED       (1 << 4)
+#define TESTCASE_RESULT_ALTERNATIVES   (1 << 5)
+#define TESTCASE_RESULT_RULES          (1 << 6)
+#define TESTCASE_RESULT_GENID          (1 << 7)
+#define TESTCASE_RESULT_REASON         (1 << 8)
+#define TESTCASE_RESULT_CLEANDEPS      (1 << 9)
+#define TESTCASE_RESULT_JOBS           (1 << 10)
+
+/* reuse solver hack, testsolv use only */
+#define TESTCASE_RESULT_REUSE_SOLVER   (1 << 31)
+
+extern Id testcase_str2dep(Pool *pool, const char *s);
+extern const char *testcase_dep2str(Pool *pool, Id id);
+extern const char *testcase_repoid2str(Pool *pool, Id repoid);
+extern const char *testcase_solvid2str(Pool *pool, Id p);
+extern Repo *testcase_str2repo(Pool *pool, const char *str);
+extern Id testcase_str2solvid(Pool *pool, const char *str);
+extern const char *testcase_job2str(Pool *pool, Id how, Id what);
+extern Id testcase_str2job(Pool *pool, const char *str, Id *whatp);
+extern int testcase_write_testtags(Repo *repo, FILE *fp);
+extern int testcase_add_testtags(Repo *repo, FILE *fp, int flags);
+extern const char *testcase_getsolverflags(Solver *solv);
+extern int testcase_setsolverflags(Solver *solv, const char *str);
+extern void testcase_resetsolverflags(Solver *solv);
+extern char *testcase_solverresult(Solver *solv, int flags);
+extern int testcase_write(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname);
+extern Solver *testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **resultp, int *resultflagsp);
+extern char *testcase_resultdiff(const char *result1, const char *result2);
diff --git a/libsolv-0.7.2/ext/tools_util.h b/libsolv-0.7.2/ext/tools_util.h
new file mode 100644 (file)
index 0000000..cc64892
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * util.h
+ *
+ */
+
+#ifndef LIBSOLV_TOOLS_UTIL_H
+#define LIBSOLV_TOOLS_UTIL_H
+
+static inline Id
+makeevr(Pool *pool, const char *s)
+{
+  if (!strncmp(s, "0:", 2) && s[2])
+    s += 2;
+  return pool_str2id(pool, s, 1);
+}
+
+/**
+ * split a string
+ */
+#ifndef DISABLE_SPLIT
+static int
+split(char *l, char **sp, int m)
+{
+  int i;
+  for (i = 0; i < m;)
+    {
+      while (*l == ' ')
+        l++;
+      if (!*l)
+        break;
+      sp[i++] = l;
+      while (*l && *l != ' ')
+        l++;
+      if (!*l)
+        break;
+      *l++ = 0;
+    }
+  return i;
+}
+#endif
+
+#ifndef DISABLE_JOIN2
+
+struct joindata {
+  char *tmp;
+  int tmpl;
+};
+
+/* this join does not depend on parsedata */
+static char *
+join2(struct joindata *jd, const char *s1, const char *s2, const char *s3)
+{
+  int l = 1;
+  char *p;
+
+  if (s1)
+    l += strlen(s1);
+  if (s2)
+    l += strlen(s2);
+  if (s3)
+    l += strlen(s3);
+  if (l > jd->tmpl)
+    {
+      jd->tmpl = l + 256;
+      jd->tmp = solv_realloc(jd->tmp, jd->tmpl);
+    }
+  p = jd->tmp;
+  if (s1)
+    {
+      strcpy(p, s1);
+      p += strlen(s1);
+    }
+  if (s2)
+    {
+      strcpy(p, s2);
+      p += strlen(s2);
+    }
+  if (s3)
+    {
+      strcpy(p, s3);
+      p += strlen(s3);
+    }
+  *p = 0;
+  return jd->tmp;
+}
+
+static inline char *
+join_dup(struct joindata *jd, const char *s)
+{
+  return s ? join2(jd, s, 0, 0) : 0;
+}
+
+static inline void
+join_freemem(struct joindata *jd)
+{
+  if (jd->tmp)
+    free(jd->tmp);
+  jd->tmp = 0;
+  jd->tmpl = 0;
+}
+
+#endif
+
+#endif /* LIBSOLV_TOOLS_UTIL_H */
diff --git a/libsolv-0.7.2/libsolv.pc.in b/libsolv-0.7.2/libsolv.pc.in
new file mode 100644 (file)
index 0000000..40a8623
--- /dev/null
@@ -0,0 +1,8 @@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: libsolv
+Description: Library for solving packages
+Version: @VERSION@
+Libs: -L${libdir} -lsolv
+Cflags: -I${includedir}
diff --git a/libsolv-0.7.2/libsolvext.pc.in b/libsolv-0.7.2/libsolvext.pc.in
new file mode 100644 (file)
index 0000000..d48b6fa
--- /dev/null
@@ -0,0 +1,9 @@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: libsolvext
+Description: Library for reading repositories
+Version: @VERSION@
+Requires: libsolv
+Libs: -L${libdir} -lsolvext
+Cflags: -I${includedir}
diff --git a/libsolv-0.7.2/package/libsolv.changes b/libsolv-0.7.2/package/libsolv.changes
new file mode 100644 (file)
index 0000000..53bfc30
--- /dev/null
@@ -0,0 +1,1598 @@
+-------------------------------------------------------------------
+Fri Dec  7 15:10:46 CET 2018 - mls@suse.de
+
+- do not autouninstall packages because of forcebest updates
+- support rpm's new '^' version separator
+- support set/get_considered_list in bindings
+- new experimental SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED flag
+  [fate#325513]
+- bump version to 0.7.2
+
+-------------------------------------------------------------------
+Wed Oct 31 13:50:22 CET 2018 - mls@suse.de
+
+- fix nasty off-by-one error in repo_write
+- also copy pattern categories from the rpm that defines the
+  pattern [fate#323785]
+- bump version to 0.7.1
+
+-------------------------------------------------------------------
+Wed Oct 24 10:48:56 CEST 2018 - mls@suse.de
+
+- new repowriter interface
+- new selection_make_matchsolvable function
+- dropped support of REPOKEY_TYPE_U32
+- bindings: Selection.flags is now an attribute
+- bump version to 0.7.0
+
+-------------------------------------------------------------------
+Thu Aug  9 17:09:41 CEST 2018 - mls@suse.de
+
+- refactor arch handling
+- add support for zstd and zchunk compression
+- convert repo2solv.sh script into a binary tool
+- bump version to 0.6.35
+
+------------------------------------------------------------------
+Wed Jul 18 14:11:51 UTC 2018 - ngompa13@gmail.com
+
+- Fix compatibility with Mageia and RH/Fedora
+
+------------------------------------------------------------------
+Wed Jul 18 11:02:29 UTC 2018 - tchvatal@suse.com
+
+- Sort a bit with spec-cleaner
+- Use python/ruby/etc condition names to match what other packages
+  do in order to make sure we are enabling/disabling stuff within
+  prjcfg
+- Silence the source unpacking
+- Make sure to execute tests
+
+-------------------------------------------------------------------
+Fri Mar 23 12:02:08 CET 2018 - mls@suse.de
+
+- make sure product files come from /etc/products.d in fallback
+  search [bnc#1086602]
+- bump version to 0.6.34
+
+-------------------------------------------------------------------
+Thu Mar  1 10:52:23 CET 2018 - mls@suse.de
+
+- also use suggests for ordering packages [bnc#1077635]
+
+-------------------------------------------------------------------
+Wed Feb 28 16:29:55 CET 2018 - mls@suse.de
+
+- fix bad assignment in solution refinement that led
+  to a memory leak [bnc#1075978]
+- use license tag instead of doc in the spec file [bnc#1082318]
+- bump version to 0.6.33
+
+-------------------------------------------------------------------
+Tue Feb 13 11:51:11 CET 2018 - mls@suse.de
+
+- fixed bug that could make fileconflict detection very slow
+  in some cases [bnc#953130]
+- bump version to 0.6.32
+
+-------------------------------------------------------------------
+Wed Jan 31 11:41:51 CET 2018 - mls@suse.de
+
+- new ENABLE_RPMDB_LIBRPM/ENABLE_RPMPKG_LIBRPM config options
+- new pool_set_whatprovides function to change the whatprovides
+  data
+- much improved selection code
+- bump version to 0.6.31
+
+-------------------------------------------------------------------
+Tue Oct 24 12:09:32 UTC 2017 - jengelh@inai.de
+
+- Update package descriptions and groups.
+  Replace old $RPM_* variables by macros.
+
+-------------------------------------------------------------------
+Mon Oct 23 11:40:22 CEST 2017 - mls@suse.de
+
+- many fixes and improvements for cleandeps
+- support debian packages with xz compressed control.tar
+- always create dup rules for "distupgrade" jobs
+- use recommends also for ordering packages
+- Fix splitprovides handling with addalreadyrecommended turned off
+  [bnc#1059065]
+- bump version to 0.6.30
+
+-------------------------------------------------------------------
+Thu Sep  7 16:18:20 CEST 2017 - mls@suse.de
+
+- expose solver_get_recommendations in bindings
+- fix bug in solver_prune_to_highest_prio_per_name resulting in
+  bad solver_get_recommendations output
+- support 'without' and 'unless' dependencies
+- fix yumobs rule generation bug
+- Use same heuristic as upstream to determine src rpms
+- bump version to 0.6.29
+
+-------------------------------------------------------------------
+Fri Jun 30 16:37:31 CEST 2017 - mls@suse.de
+
+- make peace with newer perl versions
+- fix memory leak in bindings
+- add pool_best_solvables() function
+- fix 64bit integer parsing from RPM headers
+- bump version to 0.6.28
+
+-------------------------------------------------------------------
+Sun May 28 13:32:15 UTC 2017 - ngompa13@gmail.com
+
+- Enable complex/rich dependencies for CentOS/RHEL 7, matching how
+  libsolv is configured there.
+
+-------------------------------------------------------------------
+Thu May 11 12:41:07 UTC 2017 - ngompa13@gmail.com
+
+- Disable bzip2 and xz/lzma compression support for SLE <= 12
+
+-------------------------------------------------------------------
+Mon May  8 13:15:09 UTC 2017 - ngompa13@gmail.com
+
+- Enable bzip2 and xz/lzma compression support
+- Enable complex/rich dependencies on distributions with RPM 4.13+
+- Simplified CentOS/RHEL conditionals
+- Added Mageia conditionals
+- Fixed a few spec portability issues
+
+-------------------------------------------------------------------
+Tue Apr 25 14:11:05 CEST 2017 - mls@suse.de
+
+- change queue resize code to use adaptive chunk sizes
+- fix potential segfault in testcase_depstr [bnc#1036002]
+- fix performance issues with name = md5sum dependencies
+  [bnc#1035946]
+- improve "forcebest with uninstall" handling
+- make dirid handling more robust
+- build with libxml2 instead of libexpat
+- bump version to 0.6.27
+
+-------------------------------------------------------------------
+Wed Feb 15 11:34:59 CET 2017 - mls@suse.de
+
+- export solvable_matchesdep function, as we now use it in
+  the bindings [bnc#1025440]
+- bump version to 0.6.26
+
+-------------------------------------------------------------------
+Tue Feb  7 13:13:01 CET 2017 - mls@suse.de
+
+- add SOLVABLE_NAME hack for pool_whatmatchesdep and
+  solvable_matchesdep
+- add SOLVER_FLAG_STRONG_RECOMMENDS option
+- add SOLVER_FLAG_INSTALL_ALSO_UPDATES option
+- do not special case release-less provides in sort_by_common_dep
+- solver_problemruleinfo2str: return reason why a package is not
+  installable
+- guard against dirpool_add_dir being called with an illegal
+  component id
+- reject solv files with bad directories
+- bump version to 0.6.25
+
+-------------------------------------------------------------------
+Thu Nov 10 15:09:25 CET 2016 - mls@suse.de
+
+- make testcase_str2solvid work with ignored packages
+- improve checks against corrupt rpm 
+- add SOLVER_FLAG_FOCUS_BEST solver flag
+- rework susetags multi-line handling [bnc#1007273]
+- build both for python2 and python3
+- bump version to 0.6.24
+
+-------------------------------------------------------------------
+Fri Jul 22 11:37:23 CEST 2016 - mls@suse.de
+
+- also scan /usr/share/metainfo for appdata files [bnc#989830]
+- support tri-state product-endoflife [fate#320699]
+- take lockstep into account when calculating unneeded packages
+- ignore appplication extensions for now in appdata parser
+  [bnc#984332]
+- add enabled features to solvversion.h
+- take disfavors into account when auto-minimizing for recommended
+  packages
+- change cleandeps code so that it keeps all providers
+- make sure that all repos have different names in a testcase
+- bump version to 0.6.23
+
+-------------------------------------------------------------------
+Tue Jun  7 11:24:47 CEST 2016 - mls@suse.de
+
+- fix bug in ignoreinst logic [bnc#983141]
+
+-------------------------------------------------------------------
+Wed May 18 15:09:56 CEST 2016 - mls@suse.de
+
+- add pool->setdisttype to the bindings
+- fix error in repo_deb that could lead to missing packages
+- add reason testing to testcase code
+- add pool_whatcontainsdep, selection_make_matchdepid, and
+  SELECTION_MATCH_DEPSTR
+- add SOLVER_FAVOR and SOLVER_DISFAVOR job types
+- allow unknown archs in pool_setarch
+- add the SOLVER_FLAG_URPM_REORDER solver flag
+- fix segfault in cshash dedup code [bnc#980901]
+- fix supplements handling when implicitobsoleteusescolors is set
+- bump version to 0.6.21
+
+-------------------------------------------------------------------
+Fri Apr  8 15:36:21 CEST 2016 - mls@suse.de
+
+- Better support of complex deps in pool_match_dep and
+  selection_make_matchdeps
+- make SOLVER_REASON_CLEANDEPS_ERASE introspection reason work again
+- make dep2str use rpm-like output if disttype is rpm
+- implement filtering of Requires(pre,post) for installed packages
+- simplify handling of pseudo package updates [bnc#967006]
+- improve speed of rpmmd metadata parsing
+- bump version to 0.6.20
+
+-------------------------------------------------------------------
+Mon Feb 15 16:46:31 CET 2016 - mls@suse.de
+
+- parse media number from baseurl
+- support susedata.<lang>.xml language files
+- bump version to 0.6.19
+
+-------------------------------------------------------------------
+Fri Jan 29 14:17:26 CET 2016 - mls@suse.de
+
+- fix rule generation for linked packages [bnc#961738]
+- add hash method in bindings for some classes
+- bump version to 0.6.18
+
+-------------------------------------------------------------------
+Tue Dec 22 11:49:02 CET 2015 - mls@suse.de
+
+- fix update handling of multiversion packages [bnc#957606]
+- bump version to 0.6.17
+
+-------------------------------------------------------------------
+Mon Dec 21 12:59:19 CET 2015 - mls@suse.de
+
+- fix orphan handling for dup with keeporphans set [bnc#957606]
+- bump version to 0.6.16
+
+-------------------------------------------------------------------
+Mon Dec 14 15:48:01 CET 2015 - mls@suse.de
+
+- change product links to also look at timestamps [bnc#956443]
+- rework multiversion orphaned handling [bnc#957606]
+- support key type changes in repodata_internalize()
+- allow serialization of REPOKEY_TYPE_DELETED
+- improve appdata handling of installed packages
+- improve performance when run under xen
+- bump version to 0.6.15
+
+-------------------------------------------------------------------
+Mon Oct  5 13:27:25 CEST 2015 - mls@suse.de
+
+- fix bug in recommends handling [bnc#948482]
+- also check installed packages in multiversion handling
+- fix build on Mageia
+- bump version to 0.6.14
+
+-------------------------------------------------------------------
+Fri Sep 25 11:54:02 CEST 2015 - mls@suse.de
+
+- support a generic string for pattern-visible() [bnc#900769]
+- add a SOLVER_ALLOWUNINSTALL job type
+- add ordercycle introspection
+- fix mkmask handling of a zero size
+- support 'recommends' in repo_mdk.c
+- support filelist parsing in installcheck
+- bump version to 0.6.13
+
+-------------------------------------------------------------------
+Tue Sep  1 13:37:11 CEST 2015 - mls@suse.de
+
+- added tcl bindings
+- improve debian ar archive handling
+- bindings: set the CLOEXEC flags in xfopen
+- bindings: support testcase writing [bnc#946752]
+- support REL_ELSE as evr of REL_COND
+- bump version to 0.6.12
+
+-------------------------------------------------------------------
+Tue Jun  2 11:41:10 CEST 2015 - mls@suse.de
+
+- add forgotten sha-512 support to data_skip
+- speed up whatprovides lookup with a new helper array
+- fix dup with allowuninstall
+- improve alreadyinstalled handling of supplements
+- some code cleanup
+- bump version to 0.6.11
+
+-------------------------------------------------------------------
+Sat May  2 11:44:08 UTC 2015 - mrueckert@suse.de
+
+- you really want to use rbconfig there
+
+-------------------------------------------------------------------
+Wed Mar 18 11:04:34 CET 2015 - mls@suse.de
+
+- fix bug in dislike_old_versions that could lead to a segfault
+  [bnc#922352]
+- bump version to 0.6.10
+
+-------------------------------------------------------------------
+Mon Mar  9 16:42:35 CET 2015 - mls@suse.de
+
+- rework splitprovides handling [bnc#921332]
+- improve package choosing code
+- new testcase dependency format
+- add alternatives introspection
+- make reorder_dq_for_jobrules also look at recommends/suggests
+- rework branch handling
+- add parser for rpm rich deps
+- bump version to 0.6.9
+
+-------------------------------------------------------------------
+Wed Jan 14 08:58:46 CET 2015 - ma@suse.de
+
+- fixes to build with swig 3.0.3
+- bump version to 0.6.8
+
+-------------------------------------------------------------------
+Fri Dec 19 08:59:27 CET 2014 - ma@suse.de
+
+- add product:regflavor attribute [bnc#896224]
+- bump version to 0.6.7
+
+-------------------------------------------------------------------
+Tue Oct  7 14:39:23 CEST 2014 - mls@suse.de
+
+- fix bug in reorder_dq_for_jobrules leading to crashes
+  [bnc#899907]
+- rename rpm rules to pkg rules
+- add manpages for the tools
+- bump version to 0.6.6
+
+-------------------------------------------------------------------
+Thu Sep 11 17:33:04 CEST 2014 - mls@suse.de
+
+- support DUCHANGES_ONLYADD flag in diskusage calculation
+  [bnc#783100]
+- add whatmatchesdep to bindings
+- support pool->considered in testcases
+- always call selection_filelist if SELECTION_FILELIST is set
+- support yum style obsolete handling for package splits
+- bump version to 0.6.5
+
+-------------------------------------------------------------------
+Tue Jul  8 14:13:40 CEST 2014 - mls@suse.de
+
+- expand solver_identical fix to applications [bnc#885830]
+- fix instbuddy generation code
+- improve autominimizing implementation to also look at
+  supplements
+- bump version to 0.6.4
+
+-------------------------------------------------------------------
+Fri Jun 13 08:28:12 CEST 2014 - ma@suse.de
+
+- quick fix for [bnc#881320]
+- bump version to 0.6.3
+
+-------------------------------------------------------------------
+Fri Jun  6 11:37:00 CEST 2014 - ma@suse.de
+
+- Provide PRODUCT_REGISTER_TARGET for available products [bnc#881320]
+- bump version to 0.6.2
+
+-------------------------------------------------------------------
+Thu Apr 17 14:47:42 CEST 2014 - mls@suse.de
+
+- support BREAK_ORPHANS and KEEP_ORPHANS solver flags
+- adapt to AppStream 0.6
+- reduce memory usage in repo_write and repodata_internalize
+- make repodata_stringify return the result string
+- bump version to 0.6.1
+
+-------------------------------------------------------------------
+Mon Apr  7 15:36:07 CEST 2014 - mls@suse.de
+
+- add support for sha224/sha384/sha512
+- add userinstalled helper functions
+- improve dataiterator bindings (in an incompatible way)
+- automatically free pool in bindings
+- bump version to 0.6.0 (ABI + bindings API breakage)
+
+-------------------------------------------------------------------
+Wed Mar 26 15:08:46 CET 2014 - mls@suse.de
+
+- fix handling of packages with no update/feature rule [bnc#870195]
+- fix crash when in internalize() when the schemadata gets
+  reallocated
+- fix access to uninitialized memory in repo_empty()
+- a couple of optimizations
+- support REPOKEYWORDS in content parser
+- bindings: don't let str(Datamatch) change the strings
+- fix basename optimization for STRINGEND
+- bump version to 0.5.1
+
+-------------------------------------------------------------------
+Wed Feb 26 15:08:35 CET 2014 - mls@suse.de
+
+- improve appdata.xml parsing [bnc#865293]
+- repo_helix: parse application elements
+- bump version to 0.5.0
+
+-------------------------------------------------------------------
+Fri Feb 21 16:23:58 CET 2014 - mls@suse.de
+
+- fix bug in solver_get_unneeded that could lead to an
+  endless loop [bnc#828764]
+- adapt to new rpm tags for weak dependencies
+- fix pseudo packages obsoleting other pseudo packages
+- optimize unfulfilled rule handling a bit
+- bump version to 0.4.5
+
+-------------------------------------------------------------------
+Fri Feb 14 11:03:18 CET 2014 - mls@suse.de
+
+- always keep job/jobflags in selection_filter()
+- implement COND handling in supplements/enhances
+- improve OR handling in supplements/enhances
+- fix typo in application backlink creation
+- support PRODUCT_ENDOFLIFE
+- store repoid as flexarray
+- also translate autoproduct strings
+- bump version to 0.4.4
+
+-------------------------------------------------------------------
+Mon Jan 27 17:15:41 CET 2014 - mls@suse.de
+
+- add support for autogenerated products
+- support repoid array in product definition
+- bump version to 0.4.3
+
+-------------------------------------------------------------------
+Fri Jan 24 13:50:03 CET 2014 - mls@suse.de
+
+- add -X option to susetags2solv [bnc#860271]
+- fix typos in pool_job2str
+- support DISTRO in content parser
+- make addfilelist more resistant against corrupt rpms
+- encode flags into rpmdb cookie
+- add identical and evrcmp methods in bindings
+- copy checksums in repo_add_rpmdb_reffp
+- repo_autopattern: make sure that the category is valid utf8
+- fix double-free if the number of languages is reduced to zero
+- bump version to 0.4.2
+
+-------------------------------------------------------------------
+Mon Dec  9 11:53:06 CET 2013 - mls@suse.de
+
+- make repo2solv.sh work when appdata support is off
+- enable appdata support for SUSE
+
+-------------------------------------------------------------------
+Tue Dec  3 14:30:17 CET 2013 - mls@suse.de
+
+- support appdata parsing and auto-pattern generation in tools
+- adapt to python3
+- tweak findproblemrule heuristic for conflicts
+- add m68k/ppc64le architectures
+- plug weakrulemap memory hole
+- support debian multiarch annotation
+- support product/pattern/application links
+- bump version to 0.4.1
+
+-------------------------------------------------------------------
+Tue Sep 24 11:14:25 CEST 2013 - mls@suse.de
+
+- do not add back cleandeps_updatepkgs packages [bnc#841781]
+
+-------------------------------------------------------------------
+Mon Sep 23 11:31:28 CEST 2013 - mls@suse.de
+
+- added repodata_lookup_binary
+- fix pattern obsoleting real packages [bnc#834376]
+- add selection_make_matchdeps function to query dependencies
+  other than provides
+- bump version to 0.4.0
+
+-------------------------------------------------------------------
+Wed Aug 21 14:39:54 CEST 2013 - mls@suse.de
+
+- add describe_decision() and unset() methods to bindings
+- do recommends pruning after selecting the highest versions
+- improve filelist handling
+- be more tolerant about bad xml: an empty epoch attribute means no epoch
+- fix another edge case will dup mode and multiversion packages [bnc#828389]
+- bring installcheck up to speed
+
+-------------------------------------------------------------------
+Mon Jun 17 15:54:44 CEST 2013 - mls@suse.de
+
+- add SOLVER_RULE_JOB_UNSUPPORTED and SOLVER_RULE_JOB_UNKNOWN_PACKAGE
+  for better problem reporting
+- start with library documentation
+- adapt to obsoletes handling of new rpm versions
+
+-------------------------------------------------------------------
+Wed Mar  6 16:55:57 CET 2013 - mls@suse.de
+
+- fix dataiterator returning random data in some cases
+- add changelog parser
+- fix nasty bug in selection_filter_rel
+- allow re-run of an existing solver
+- bump version to 0.3.0
+
+-------------------------------------------------------------------
+Mon Jan 14 16:01:04 CET 2013 - mls@suse.de
+
+- trivial_installable: check vendor of affected package to see if
+  a patch should be ignored [bnc#736100]
+- fix trivial installable requires handling
+- bump version to 0.2.4
+
+-------------------------------------------------------------------
+Tue Dec 18 19:20:19 CET 2012 - mls@suse.de
+
+- fix potential access to freed memory
+- improve find_problemrule speed
+- add support for special namespaceprovides jobs
+- bump version to 0.2.3
+
+-------------------------------------------------------------------
+Wed Dec  5 14:37:39 CET 2012 - mls@suse.de
+
+- many Selection improvements
+- fix perl binding memory issue
+- improve file list matching
+- support targeted up/dup with cleandeps
+- bump version to 0.2.2
+
+-------------------------------------------------------------------
+Fri Nov 23 13:57:19 CET 2012 - mls@suse.de
+
+- support targeted up/dup
+- support best rules to enforce the installation of the best package
+- implement selection class to ease package selection
+- fix obsolete handling for debian packages
+- add pool_lookup_deltalocation helper
+- bump version to 0.2.1
+
+-------------------------------------------------------------------
+Thu Oct 18 16:58:10 CEST 2012 - mls@suse.de
+
+- fix susetags parser, it ignored the filelist of the last
+  solvable
+- fix encoding of large values
+- bump version to 0.2.0
+
+-------------------------------------------------------------------
+Mon Jun 25 13:40:58 CEST 2012 - mls@suse.de
+
+- fix typo in repodata_merge_attrs [bnc#767510]
+
+-------------------------------------------------------------------
+Wed May 30 14:46:48 CEST 2012 - mls@suse.de
+
+- fix build for older suse versions
+- fix memory corruption in unneeded calculation when there are
+  product buddies
+
+-------------------------------------------------------------------
+Tue May  8 10:59:39 CEST 2012 - ma@suse.de
+
+- build with swig-2.0.6
+
+-------------------------------------------------------------------
+Mon Apr 23 15:52:26 CEST 2012 - mls@suse.de
+
+- added testcase framework
+- add solver_get_unneeded() to get a list of no longer needed
+  installed packages
+- changed duprule generation to ignore uninstallable packages [bnc#750485]
+- fix memory leaks
+- speed up whatprovides generation
+- support 64bit nums, return files sizes in bytes
+- return errors instead of calling exit()
+- support tilde in rpm version comparison [bnc#466994]
+- 0.1.0
+
+-------------------------------------------------------------------
+Tue Feb  7 16:33:10 CET 2012 - mls@suse.de
+
+- add findutils to the requires of libsolv-tools [bnc#743634]
+
+-------------------------------------------------------------------
+Wed Feb  1 14:06:59 CET 2012 - mls@suse.de
+
+- add cleandeps support for install/update
+- check for cleandeps mistakes (untested)
+
+-------------------------------------------------------------------
+Fri Jan 27 14:10:34 CET 2012 - mls@suse.de
+
+- make repo type code selection modular
+- add more solvable_ functions
+- add dependency getter/setter code to bindings
+- cleanup dup handling
+- hide more internals
+
+-------------------------------------------------------------------
+Mon Oct 24 13:26:18 CEST 2011 - ma@suse.de
+
+- mls fixed package provides/obsoletes, but forgot to write
+  a changes entry.
+
+-------------------------------------------------------------------
+Tue Oct 18 16:18:39 CEST 2011 - ma@suse.de
+
+- Add arch arvm7tnhl and  armv7thl
+
+-------------------------------------------------------------------
+Fri Apr 29 14:35:59 CEST 2011 - mls@suse.de
+
+- bup version to 0.17.0 to make it different from 11.4
+- 0.17.0
+
+-------------------------------------------------------------------
+Thu Mar 24 10:04:16 UTC 2011 - mls@suse.de
+
+- add missing else part in rpmdbid2db()
+
+-------------------------------------------------------------------
+Thu Feb 24 17:44:05 CET 2011 - mls@suse.de
+
+- ignore to be dropped orhaned packages when calculating
+  candidates for recommends/supplements installation
+
+-------------------------------------------------------------------
+Wed Feb  2 09:24:42 UTC 2011 - kkaempf@novell.com
+
+- Split off 'applayer' and 'bindings' as a separate package
+  to make the bindings more independant of libsatsolver
+- 0.16.4
+
+-------------------------------------------------------------------
+Tue Jan 25 09:52:48 CET 2011 - ma@suse.de
+
+- Apply patch introducing armv7nhl:armv7h
+
+-------------------------------------------------------------------
+Fri Oct 22 15:51:11 CEST 2010 - ma@suse.de
+
+- updateinfoxml: Correctly parse 'issued date' field.
+- 0.16.1
+
+-------------------------------------------------------------------
+Thu Sep  9 17:30:36 CEST 2010 - mls@suse.de
+
+- bump version to 0.16 to make it different from code11_3 branch
+- 0.16.0
+
+-------------------------------------------------------------------
+Mon Sep  6 13:50:02 UTC 2010 - dmacvicar@novell.com
+
+- ruby bindings: fix bugs regarding include path loading
+  (was hardcoded) and refactor the way the library path is defined
+  (only once in a helper)
+
+-------------------------------------------------------------------
+Mon Sep  6 12:38:21 UTC 2010 - dmacvicar@novell.com
+
+- SLE10SP3 also has vendor_ruby
+
+-------------------------------------------------------------------
+Wed Aug 18 14:11:08 UTC 2010 - kkaempf@novell.com
+
+- refactor ruby-satsolver, pure-Ruby extensions added
+- 0.15.1
+
+-------------------------------------------------------------------
+Thu May  6 17:39:20 CEST 2010 - mls@suse.de
+
+- fix bug in cleandeps code
+- bump version to 0.15 to make it different from code11_2 branch
+- 0.15.0
+
+-------------------------------------------------------------------
+Tue Mar 23 17:24:46 CET 2010 - ma@suse.de
+
+- Parse an installed products <shortsummary> tag [bnc#586303]
+
+-------------------------------------------------------------------
+Mon Mar 22 18:45:42 CET 2010 - mls@suse.de
+
+- dataiterator: reset parent when jumping to a solvid [bnc#589640]
+- 0.14.17
+
+-------------------------------------------------------------------
+Thu Mar 11 22:13:26 CET 2010 - ma@suse.de
+
+- parse global repository ids. [bnc#377568]
+- fix pattern parsing in repomd format. [bnc#585000]
+- 0.14.16
+
+-------------------------------------------------------------------
+Thu Mar 11 12:18:23 CET 2010 - mls@suse.de
+
+- fix language code lookup for fallback languages [bnc#584644]
+- change solvable_lookup_str_lang interface a bit for libzypp
+
+-------------------------------------------------------------------
+Fri Feb 19 17:31:51 CET 2010 - mls@suse.de
+
+- make dup rules work when system repo is not first [bnc#581276]
+- parse pattern visibility flag in repomd format
+- 0.14.15
+
+-------------------------------------------------------------------
+Fri Jan 29 14:48:34 CET 2010 - mls@suse.de
+
+- speed up createwhatprovides when many solvables provide the same dep
+- fix choice rule creation for real (bnc#551637)
+- 0.14.14
+
+-------------------------------------------------------------------
+Mon Jan 18 14:42:27 CET 2010 - mls@suse.de
+
+- set repository:toolversion to 1.0 in common_write
+- 0.14.13
+
+-------------------------------------------------------------------
+Mon Dec 21 14:29:24 CET 2009 - mls@suse.de
+
+- disable update rule in noobsoletes case if installed package is to
+  be kept [bnc#564239]
+- work around rpm bug when --prefix is used [bnc#565525]
+- add support for sparc architecture [bnc#566291]
+- 0.14.12
+
+-------------------------------------------------------------------
+Mon Dec  7 13:59:08 CET 2009 - ma@suse.de
+
+- Support optionally compressed product(s).xml in rpmmd metadata.
+- 0.14.11
+
+-------------------------------------------------------------------
+Mon Nov  2 14:10:23 CET 2009 - mls@suse.de
+
+- look at infarch/dup rules when creating choice rules, makes dup
+  also install 32bit packages [bnc#551637]
+- 0.14.10
+
+-------------------------------------------------------------------
+Wed Oct 14 16:21:32 CEST 2009 - mls@suse.de
+
+- ignore products element so that repo2solv works
+- support MULTI_SEMANTICS
+- add --withsrc option for installcheck
+- add SOLVER_DROP_ORPHANED job type
+- fix dropped package handling in removedisabledconflicts
+- 0.14.9
+
+-------------------------------------------------------------------
+Thu Sep 24 10:27:42 CEST 2009 - mls@suse.de
+
+- fix bug in solvable_lookup_str_base
+
+-------------------------------------------------------------------
+Wed Sep 23 11:10:08 CEST 2009 - mls@suse.de
+
+- get missing translations from other solvables [bnc#386449]
+- also look at triggers when ordering packages
+- add support for REPOKEY_TYPE_BINARY
+- 0.14.8
+
+-------------------------------------------------------------------
+Wed Sep 16 10:56:44 CEST 2009 - mls@suse.de
+
+- use repomdxml to query for the location [bnc#501425]
+- fix assertion failue... again
+- fix fp leak [bnc#535468]
+- 0.14.7
+
+-------------------------------------------------------------------
+Fri Sep  4 11:40:47 CEST 2009 - mls@suse.de
+
+- fix multiversion handling for real
+- fix speed regression in repo_susetags
+- close fd leak [bnc#527506]
+- remove db.h workaround
+- 0.14.6
+
+-------------------------------------------------------------------
+Mon Aug 31 13:57:29 CEST 2009 - mls@suse.de
+
+- fix to build with rpm-4.7
+
+-------------------------------------------------------------------
+Fri Aug 28 11:06:31 CEST 2009 - ma@suse.de
+
+- add support for SOLVER_SOLVABLE_REPO
+- 0.14.5
+
+-------------------------------------------------------------------
+Thu Jul 30 12:49:38 CEST 2009 - mls@suse.de
+
+- speed up file list parsing
+- speed up addfileprovides
+- fix bugs in pubkey handling
+- fix bug in filelist handling when there are no abs paths
+- 0.14.4
+
+-------------------------------------------------------------------
+Fri Jul 17 14:07:07 CEST 2009 - mls@suse.de
+
+- add satversion.h header file
+- many changes regarding the load callback
+- more dataiterator control functions
+- add transaction ordering code
+- add support for file conflict checking
+- 0.14.3
+
+-------------------------------------------------------------------
+Mon Jun 22 16:01:02 CEST 2009 - mls@suse.de
+
+- create libsatsolverext.a
+- 0.14.2
+
+-------------------------------------------------------------------
+Wed May  6 19:52:39 CEST 2009 - ma@suse.de
+
+- Fix to support sha256 hashes (bnc#501425)
+
+-------------------------------------------------------------------
+Wed Apr  1 10:32:43 CEST 2009 - kkaempf@suse.de
+
+- 0.14.1
+  Core changes
+  - fix potential NULL deref in srcrpm handling (mls)
+  - clean up and fix suggested/recommended list creation code (mls)
+  - kill obsolete and broken patchxml support (mls)
+  - replace old solver_problemruleinfo with new solver_ruleinfo
+    function (mls)
+  - add solvable_selfprovidedep() function (mls)
+  - add noinfarchcheck solver option (mls)
+  - clone job queue to make the code more flexible (mls)
+  - rewrite policy rule disabling/re-enabling (bnc#481836) (mls)
+  - fix out-of-bounds in solver_printproblem() (mls)
+  Bindings changes
+  - provide 'Repo.attr(String)' accessor function (kkaempf)
+  - provide 'Solver.sizechange' to compute the changes of the
+    installed size after a transaction is applied (kkaempf)
+  - solver result iterators for Python (jblunck)
+  - add %newobject to track newly created objects better (kkaempf)
+  - generate rdoc documentation from swig input files (kkaempf)
+  - add a no-op Pool destructor (bnc#483252) (kkaempf)
+  - provide access to all flags and settings (kkaempf)
+
+-------------------------------------------------------------------
+Wed Mar  4 14:39:00 CET 2009 - mls@suse.de
+
+- fix problem_to_solutions segfault
+- bump version to 0.14 to make it different from code11 branch
+- 0.14.0
+
+-------------------------------------------------------------------
+Mon Mar  2 18:20:22 CET 2009 - mls@suse.de
+
+- add solver_trivial_installable() to fix multiversion patches [bnc#480303]
+- 0.13.5
+
+-------------------------------------------------------------------
+Wed Feb 18 16:48:41 CET 2009 - ma@suse.de
+
+- Use correct namespace (e.g. pattern:) even if solvable has no name [bnc#470011]
+
+-------------------------------------------------------------------
+Fri Jan 30 14:26:42 CET 2009 - mls@suse.de
+
+- fix weakmap boundary check
+- 0.13.3
+
+-------------------------------------------------------------------
+Tue Jan 27 13:12:30 CET 2009 - ma@suse.de
+
+- Ignore trailing whitespace in content file parser.
+
+-------------------------------------------------------------------
+Mon Jan 26 13:55:35 CET 2009 - mls@suse.de
+
+- fix segfault caused by whatprovides reallocation [bnc#468313]
+- 0.13.1
+
+-------------------------------------------------------------------
+Tue Jan 20 17:12:17 CET 2009 - ma@suse.de
+
+- repo_rpmdb: Fix conversion to UTF8
+
+-------------------------------------------------------------------
+Fri Dec  5 14:43:55 CET 2008 - kkaempf@suse.de
+
+- enhance bindings to provide reasons for solver decisions
+
+-------------------------------------------------------------------
+Mon Dec  1 11:50:12 CET 2008 - mls@suse.de
+
+- prefer patterns again until there's a real fix [bnc#450226]
+
+-------------------------------------------------------------------
+Mon Dec  1 11:13:55 CET 2008 - mls@suse.de
+
+- susetags: fix file dependency parsing [bnc#450286]
+
+-------------------------------------------------------------------
+Fri Nov 28 18:29:08 CET 2008 - mls@suse.de
+
+- correct problem solving algorithm
+- 0.13.0
+
+-------------------------------------------------------------------
+Fri Nov 21 16:54:44 CET 2008 - dmacvicar@suse.de
+
+- remove unused updaterepokey, replaced by repo
+  product information
+
+-------------------------------------------------------------------
+Thu Nov 20 10:32:01 CET 2008 - dmacvicar@suse.de
+
+- support content, distro and updates tag properly
+- remove the unused products tag
+
+-------------------------------------------------------------------
+Mon Nov 17 14:30:08 CET 2008 - ma@suse.de
+
+- Parse RELEASE tag from contentfile (bnc #444978)
+- 0.12.3
+
+-------------------------------------------------------------------
+Fri Nov 14 18:00:19 CET 2008 - mls@suse.de
+
+- fix bugs in multiversion handling
+- bring perl bindings up to speed
+- 0.12.2
+
+-------------------------------------------------------------------
+Fri Nov  7 18:26:07 CET 2008 - ma@suse.de
+
+- fix SOLVID_POS dataiterator handling
+
+-------------------------------------------------------------------
+Fri Nov  7 11:56:37 CET 2008 - kkaempf@suse.de
+
+- make repo_zyppdb more robust (bnc#441043)
+
+-------------------------------------------------------------------
+Thu Nov  6 09:49:51 CET 2008 - kkaempf@suse.de
+
+- Add 'user_data' argument to all applayer iterator callbacks
+  (bnc#418491)
+
+-------------------------------------------------------------------
+Wed Oct 29 12:36:57 CET 2008 - ma@suse.de
+
+- Add 'sh4' architectures.
+
+-------------------------------------------------------------------
+Tue Oct 28 16:55:03 CET 2008 - ma@suse.de
+
+- Add 'arm' architectures.
+
+-------------------------------------------------------------------
+Mon Oct 27 10:54:36 CET 2008 - kkaempf@suse.de
+
+- Improve error detection and reporting when parsing 'content' file
+
+-------------------------------------------------------------------
+Fri Oct 24 16:03:13 CEST 2008 - ma@suse.de
+
+- Remember the /etc/products.d enties filename in .solv
+  (bnc #432932)
+- 0.12.1
+
+-------------------------------------------------------------------
+Thu Oct 23 10:49:40 CEST 2008 - mrueckert@suse.de
+
+- add zlib-devel as buildrequires, cmake is looking for it
+  explicitely. rpm-devel used to require it but you dont really
+  need it to link against librpm*
+- requires rpm-devel in the devel package, it is required to link
+  against libsatsolver.
+
+-------------------------------------------------------------------
+Wed Oct 22 13:00:56 CEST 2008 - mls@suse.de
+
+- add pool_set_installed()
+- drop "installed" arguments from some functions
+- 0.12.0
+
+-------------------------------------------------------------------
+Wed Oct 22 13:00:25 CEST 2008 - dmacvicar@suse.de
+
+- support the new standarized tags available in
+  createrepo > 0.9.6
+  saving of the distro tag still missing.
+
+-------------------------------------------------------------------
+Thu Oct 16 00:50:47 CEST 2008 - mls@suse.de
+
+- make iterator work with completely empty repos [bnc#435838]
+
+-------------------------------------------------------------------
+Tue Oct 14 18:28:57 CEST 2008 - mls@suse.de
+
+- the big solv data change
+  * incompatible new file format
+  * repodata handles are solvable ids
+  * no more extra handles
+  * no need to call repodata_extend anymore
+- work around solver dup repo priority bug, real fix follows soon
+- implement releasever
+- repo_products.c is now more robust
+
+-------------------------------------------------------------------
+Mon Oct 13 16:50:14 CEST 2008 - kkaempf@suse.de
+
+- make product parsing more robust (bnc#433362)
+
+-------------------------------------------------------------------
+Thu Oct  2 18:46:55 CEST 2008 - ma@suse.de
+
+- Product arttributes: removed FLAVOR and REFERENCES, added PRODUCTLINE.
+- revision 11233
+- 0.11.0
+
+-------------------------------------------------------------------
+Tue Sep 30 13:03:10 CEST 2008 - ma@suse.de
+
+- repo_content.c: fix broken dependency parsing.
+- revision 11214
+
+-------------------------------------------------------------------
+Mon Sep 29 14:53:09 CEST 2008 - ma@suse.de
+
+- rpms2solv failed to write out most solvable data (bnc #422338).
+- revision 11201
+
+-------------------------------------------------------------------
+Fri Sep 26 11:54:34 CEST 2008 - kkaempf@suse.de
+
+- new fallback strategy for installed products in rpmdb2solv
+  try /etc/products.d (code11 style) first
+  if this fails, try /var/lib/zypp/db/products/*
+  if this fails, fallback to /etc/*-release
+  (bnc#429177)
+- 0.10.16
+
+-------------------------------------------------------------------
+Thu Sep 25 17:14:42 CEST 2008 - kkaempf@suse.de
+
+- fully support Dataiterator in Python and Ruby bindings.
+- 0.10.15
+
+-------------------------------------------------------------------
+Thu Sep 25 13:53:54 CEST 2008 - dmacvicar@suse.de
+
+- add support for keywords in susedata
+
+-------------------------------------------------------------------
+Wed Sep 24 10:55:01 CEST 2008 - kkaempf@suse.de
+
+- parse /etc/<xyz>-release if no /etc/products.d present
+  (bnc#429177)
+- 0.10.14
+
+-------------------------------------------------------------------
+Mon Sep 22 12:51:51 CEST 2008 - dmacvicar@suse.de
+
+- ability to parse suseinfo.xml for extended repomd.xml attributes
+- fix susedata.xml parsing
+- add CPE attribute to installed product
+- real fix for segfault in multiarch parsing (bnc#427271)
+- 0.10.13
+
+-------------------------------------------------------------------
+Thu Sep 18 14:44:31 CEST 2008 - dmacvicar@suse.de
+
+- fix segfault in multiarch parsing (bnc#427271)
+
+-------------------------------------------------------------------
+Wed Sep 17 14:10:23 CEST 2008 - mls@suse.de
+
+- fix segfault in provides iterator
+- 0.10.12
+
+-------------------------------------------------------------------
+Fri Sep 12 17:32:02 CEST 2008 - dmacvicar@suse.de
+
+- support for susedata.xml
+
+-------------------------------------------------------------------
+Fri Sep 12 14:01:11 CEST 2008 - dmacvicar@suse.de
+
+- add repo_add_poolstr_array
+- move updates="key,key.." to repomd.xml
+- make product url ids more extensible
+- 0.10.11
+
+-------------------------------------------------------------------
+Thu Sep 11 14:30:16 CEST 2008 - dmacvicar@suse.de
+
+- add REPOSITORY_UPDATES to match product -> repos
+- make updateinfo.xml support id attribute in collection that
+  leads to insert that the repository updates that id.
+
+-------------------------------------------------------------------
+Wed Sep 10 18:11:10 CEST 2008 - dmacvicar@suse.de
+
+- create one product per BASEARCHS
+
+-------------------------------------------------------------------
+Wed Sep 10 14:19:26 CEST 2008 - ma@suse.de
+
+- repo_products: Parse schemeversion, propagate product
+  updaterepokey and flavor. Fix segfault on malformed
+  xml.
+- 0.10.10
+
+-------------------------------------------------------------------
+Wed Sep 10 11:57:27 CEST 2008 - dmacvicar@suse.de
+
+- accept the PATTERNS tag in content file
+
+-------------------------------------------------------------------
+Tue Sep  9 21:26:31 CEST 2008 - kkaempf@suse.de
+
+- rpmdb2solv changes:
+  - fix bug when parsing multiple products
+  - adapt to .prod file as of 9/9/08 7:20pm
+- 0.10.9
+
+-------------------------------------------------------------------
+Tue Sep  9 17:52:30 CEST 2008 - ma@suse.de
+
+- Reenable -Werror and fix bindings.
+- 0.10.8
+
+-------------------------------------------------------------------
+Tue Sep  9 11:50:39 CEST 2008 - dmacvicar@suse.de
+
+- disable -Werror for swig generated stuff
+
+-------------------------------------------------------------------
+Fri Sep  5 18:59:35 CEST 2008 - kkaempf@suse.de
+
+- adapt /etc/product.d parser to generated .prod files.
+
+-------------------------------------------------------------------
+Fri Sep  5 13:29:47 CEST 2008 - ma@suse.de
+
+- tools/repo_susetags.c: Parse packages vendor (bnc #422493).
+- 0.10.7
+
+-------------------------------------------------------------------
+Thu Sep  4 12:30:06 CEST 2008 - kkaempf@suse.de
+
+- tools/rpmdb2solv: Adapt to xml-based /etc/products.d
+- tools/rpmdb2solv: Add '-a <attribute>' to print
+  distribution.target attribute of baseproduct.
+
+-------------------------------------------------------------------
+Tue Sep  2 12:17:03 CEST 2008 - mls@suse.de
+
+- make solver includes use "" instead of <>, fixes bnc#415920
+- implement otherproviders()
+- make patches do nevr matching
+- make patch conflicts work with multiversion
+- new job commands, now combinded from job type and select type
+- support for distupgrade mode
+- make SOLVER_ERASE_SOLVABLE work
+- also check obsoletes when disabling update rules
+- 0.10.6
+
+-------------------------------------------------------------------
+Fri Aug 22 18:04:12 CEST 2008 - dmacvicar@suse.de
+
+- add support for extensible metadata over primary +
+  diskusage
+- 0.10.5
+
+-------------------------------------------------------------------
+Fri Aug 15 16:29:00 CEST 2008 - kkaempf@suse.de
+
+- ensure existance of product solvable in repo_content(bnc#417594)
+
+-------------------------------------------------------------------
+Fri Aug 15 15:00:32 CEST 2008 - kkaempf@suse.de
+
+- follow /etc/products.d/baseproduct and mark product as 'base'
+
+-------------------------------------------------------------------
+Fri Aug 15 14:26:29 CEST 2008 - kkaempf@suse.de
+
+- Implement pre-code11 fallback for products, parse /etc/*-release
+  if /etc/products.d is not available.
+
+-------------------------------------------------------------------
+Wed Aug 13 18:06:41 CEST 2008 - kkaempf@suse.de
+
+- provide installtime for installed products.
+
+-------------------------------------------------------------------
+Wed Aug 13 15:42:36 CEST 2008 - dmacvicar@suse.de
+
+- include new file search capability commited by matz
+  (SEARCH_FILES)
+- 0.10.4
+
+-------------------------------------------------------------------
+Wed Aug 13 10:31:01 CEST 2008 - kkaempf@suse.de
+
+- Honor rpmdb2solv's '-r <root>' also for the products.d path.
+
+-------------------------------------------------------------------
+Tue Aug 12 14:22:29 CEST 2008 - kkaempf@suse.de
+
+- Add .prod parsing for 'installed' products to rpmdb2solv.
+- Improve python-bindings, add iterators.
+
+-------------------------------------------------------------------
+Thu Aug  7 22:00:55 CEST 2008 - dmacvicar@suse.de
+
+- implement relogin suggested support (fate#304889)
+
+-------------------------------------------------------------------
+Thu Aug  7 13:36:59 CEST 2008 - ma@suse.de
+
+- Susetags: Allow whitespace in file provides generated by
+  autobuild (bnc#415115)
+
+-------------------------------------------------------------------
+Fri Aug  1 18:59:22 CEST 2008 - dmacvicar@suse.de
+
+- insert the checksum in rpmmd generated solv files
+  (bnc#414002)
+- 0.10.3
+
+-------------------------------------------------------------------
+Tue Jul 29 10:53:22 CEST 2008 - mls@suse.de
+
+- resolve job rules before installing system packages [bnc#411086]
+- no more freshens. R.I.P.
+- make repo2solv.sh also take repomd.xml in count
+- install repomdxml2solv
+- add Packager, Build Host, Distribution
+- disallow arch/vendor changes even if the package name changes
+
+-------------------------------------------------------------------
+Sat Jul 12 02:32:15 CEST 2008 - dmacvicar@suse.de
+
+- infrastructure to save generated and expiration time
+  stamp in rpm-md repositories (fate #301904)
+- 0.10.1
+
+-------------------------------------------------------------------
+Wed Jul  9 16:25:36 CEST 2008 - ma@suse.de
+
+- Fix repo_content dependency parsing. Parser may lose up to
+  two trailing dependencies.
+
+-------------------------------------------------------------------
+Tue Jul  1 14:54:38 CEST 2008 - kkaempf@suse.de
+
+- rename language bindings to {perl,python,ruby}-satsolver
+  to follow naming conventions.
+
+-------------------------------------------------------------------
+Mon Jun 30 23:55:20 CEST 2008 - dmacvicar@suse.de
+
+- forward port
+- add message tag to updateinfo.xml for displaying
+  messages in the user interface
+- Fix missing self provides for patches (bnc #397132).
+- do not reorder binary rules if they are not rpm rules [bnc#397456]
+- 0.10.0
+
+-------------------------------------------------------------------
+Mon Jun  2 11:47:32 CEST 2008 - coolo@suse.de
+
+- calculate recommendation list also if ignorealreadyrecommended is set,
+  as some recommendations would be missing otherwise
+- make dependency output less confusing (bnc#396309)
+- 0.9.0
+
+-------------------------------------------------------------------
+Tue May 27 22:34:05 CEST 2008 - coolo@suse.de
+
+- compile with RPM_OPT_FLAGS
+
+-------------------------------------------------------------------
+Fri May 23 21:07:01 CEST 2008 - mls@suse.de
+
+- add "zypper" flag
+- add "ignorealreadyrecommended" aka "zypper" solver option
+
+-------------------------------------------------------------------
+Thu May 22 20:16:22 CEST 2008 - coolo@suse.de
+
+- fixed language support in patterns (bnc#386524)
+
+-------------------------------------------------------------------
+Mon May 19 14:53:01 CEST 2008 - dmacvicar@suse.de
+
+- make solvable_look_bool more robust by allowing both
+  the void or the num == 1 strategy.
+
+-------------------------------------------------------------------
+Thu May 15 16:05:50 CEST 2008 - coolo@suse.de
+
+- fix susetags parser
+
+------------------------------------------------------------------
+Wed May 14 16:41:26 CEST 2008 - dmacvicar@suse.de
+
+- mls fix of satisfied patterns
+- 0.0.33
+
+-------------------------------------------------------------------
+Tue May 13 17:14:26 CEST 2008 - dmacvicar@suse.de
+
+- use repodata_set_void for pattern visible attr
+
+-------------------------------------------------------------------
+Tue May 13 14:11:30 CEST 2008 - jreidinger@suse.cz
+
+- read description dir path from content file (bnc #389414)
+
+-------------------------------------------------------------------
+Tue May 13 12:20:58 CEST 2008 - dmacvicar@suse.de
+
+- a boolean is not a num attribute set to 1, but just a existing void
+  attribute. (bnc#388818)
+
+-------------------------------------------------------------------
+Mon May 12 10:16:20 CEST 2008 - coolo@suse.de
+
+- provide libsatsolver to fix requires of debuginfo
+
+-------------------------------------------------------------------
+Sat May 10 15:33:15 CEST 2008 - coolo@suse.de
+
+- resubmit clean tar
+
+-------------------------------------------------------------------
+Fri May  9 21:56:43 CEST 2008 - ma@suse.de
+
+- Parse the products LABEL in content file to SUMMARY.
+
+-------------------------------------------------------------------
+Fri May  9 20:26:52 CEST 2008 - dmacvicar@suse.de
+
+- recognize 1 as true for reboot suggested and
+  restart suggested (bnc#388818)
+
+-------------------------------------------------------------------
+Fri May  9 16:04:42 CEST 2008 - kkaempf@suse.de
+
+- move 'helix2solv' from satsolver-tools to satsolver-devel package
+  (bnc#388595)
+
+-------------------------------------------------------------------
+Mon May  5 16:24:14 CEST 2008 - coolo@suse.de
+
+- add obsoleteusesprovides and implicitobsoleteusesprovides solver
+  flags
+- speed up solving by not recreating the watch chains every time
+  some rule is enabled/disabled. To do this, the "disabled" flag
+  had to be moved from w1 to d.
+- fix bug that broke rule disabling when "forceResolve" was true
+- fix bug in update rule calculation
+- speed up solver a bit by creating a queue holding all assertion
+  rules, so we do not have to scan all rules for assertions
+- parse also DISTPRODUCT and DISTVERSION (for registration), and the other
+  (often unused) attributes of products.
+
+-------------------------------------------------------------------
+Mon Apr 28 19:36:54 CEST 2008 - coolo@suse.de
+
+- (De-)Serialize structured types.  Dataiterator and repo_search support
+  them too, but not yet nested, so that is unsupported for now.
+- skipping kinds in matcher when a flag is specified.
+- make --force behave a bit more like --noforce
+
+-------------------------------------------------------------------
+Fri Apr 25 19:23:51 CEST 2008 - coolo@suse.de
+
+- detect and skip empty lines (bnc#381828)
+- fix endless loop
+- move debug functions to solverdebug.c
+- do not delete negative bitfield entries [bnc#381908]
+- add "showinstalledrecommended" option to make the solver
+  put installed packages on the suggestions/recommendations
+  queues
+- Fix content parsing if PRODUCT isn't the first entry.
+- add more statistics
+- add two assertions
+- add support for susetags filelist
+- plug mem join2 leak
+- fix anchoring of filelist data
+- susetags move files added to provides back into filelist
+- ignore packages.FL for now
+
+-------------------------------------------------------------------
+Sun Apr 20 18:25:14 CEST 2008 - coolo@suse.de
+
+- fix build
+
+-------------------------------------------------------------------
+Sat Apr 19 08:10:51 CEST 2008 - coolo@suse.de
+
+- fix probleminfo if solvable conflicts with itself and has no requires
+- Fix parsing dep lines of content files (bnc #380396).
+- C++-guard also solver.h
+- add support for feature rules
+- fix a couple of small bugs
+- use new interface
+
+-------------------------------------------------------------------
+Wed Apr 16 17:44:20 CEST 2008 - coolo@suse.de
+
+- fix (rare) case of crashing solver
+
+-------------------------------------------------------------------
+Tue Apr 15 09:06:36 CEST 2008 - coolo@suse.de
+
+- some fixes around updateinfo parsing
+
+-------------------------------------------------------------------
+Wed Apr  9 16:09:36 CEST 2008 - jkupec@suse.cz
+
+- enable regex matching in Dataiterator
+
+-------------------------------------------------------------------
+Fri Apr  4 15:45:44 CEST 2008 - coolo@suse.de
+
+- package deptestomatic in -devel
+
+-------------------------------------------------------------------
+Mon Mar 31 16:25:03 CEST 2008 - coolo@suse.de
+
+- truly restart when analyze_unsolvable is hit (fixes bnc#368209)
+- make it work with really large directories
+
+-------------------------------------------------------------------
+Mon Mar 24 15:31:18 CET 2008 - coolo@suse.de
+
+- install rpms2solv
+
+-------------------------------------------------------------------
+Mon Mar 17 16:10:22 CET 2008 - matz@suse.de
+
+- Initialize all allocated array members for blocky arrays (when it
+  matters, e.g. when extending also in blocks - bnc#371137)
+
+-------------------------------------------------------------------
+Fri Mar 14 08:37:47 CET 2008 - coolo@suse.de
+
+- fix build on other distris
+- fix requires of tools
+
+-------------------------------------------------------------------
+Wed Mar 12 11:45:21 CET 2008 - coolo@suse.de
+
+- store datadir for susetags
+- fixing assertion in rules learning
+
+-------------------------------------------------------------------
+Fri Mar  7 10:51:09 CET 2008 - coolo@suse.de
+
+- several fixes in whatprovides (possibly root cause of bnc#367210)
+
+-------------------------------------------------------------------
+Mon Feb 25 12:59:00 CET 2008 - coolo@suse.de
+
+- fixing rpmdb2solv argument handling
+
+-------------------------------------------------------------------
+Fri Feb 22 11:09:05 CET 2008 - coolo@suse.de
+
+- support rpmdb2solv -r for chroots
+
+-------------------------------------------------------------------
+Thu Feb 21 18:14:41 CET 2008 - coolo@suse.de
+
+- fix susetags parser for so called full trees
+
+-------------------------------------------------------------------
+Wed Feb 20 13:23:31 CET 2008 - coolo@suse.de
+
+- no longer link against db43 but against rpmlib
+
+-------------------------------------------------------------------
+Tue Feb 19 15:01:55 CET 2008 - coolo@suse.de
+
+- fix requires/obsoletes
+
+-------------------------------------------------------------------
+Tue Feb 19 08:10:01 CET 2008 - coolo@suse.de
+
+- mls is back from vacation - several fixes and enhancements
+
+-------------------------------------------------------------------
+Fri Feb 15 11:04:09 CET 2008 - coolo@suse.de
+
+- several fixes for the solv files
+
+-------------------------------------------------------------------
+Tue Feb 12 18:29:43 CET 2008 - kkaempf@suse.de
+
+- add libappsatsolver, an application layer to ease coding
+  against sat-solver.
+
+-------------------------------------------------------------------
+Tue Feb 12 17:14:04 CET 2008 - coolo@suse.de
+
+- let susetags parse vendors
+
+-------------------------------------------------------------------
+Thu Feb  7 18:41:05 CET 2008 - coolo@suse.de
+
+- rename libsatsolver in satsolver-tools
+- several updates and fixes
+
+-------------------------------------------------------------------
+Fri Feb  1 13:59:53 CET 2008 - coolo@suse.de
+
+- really don't strip
+
+-------------------------------------------------------------------
+Mon Jan 14 17:14:03 CET 2008 - coolo@suse.de
+
+- update from SVN:
+  - various fixes
+  - less logging
+
+-------------------------------------------------------------------
+Tue Jan  8 16:02:26 CET 2008 - coolo@suse.de
+
+- update to SVN again and don't strip
+
+-------------------------------------------------------------------
+Sat Dec 22 19:02:57 CET 2007 - coolo@suse.de
+
+- update to SVN so libzypp compiles again
+
+-------------------------------------------------------------------
+Fri Nov 30 16:01:39 CET 2007 - schubi@suse.de
+
+- update for libzypp integration
+
+-------------------------------------------------------------------
+Fri Nov 16 12:17:13 CET 2007 - coolo@suse.de
+
+- update to SVN again to make libzypp compilable again
+
+-------------------------------------------------------------------
+Wed Nov 14 16:10:21 CET 2007 - schubi@suse.de
+
+- further develpment. bugfix, logging, docu,...
+
+-------------------------------------------------------------------
+Mon Nov 12 13:44:52 CET 2007 - coolo@suse.de
+
+- update to the latest version from SVN
+  - compilation fixes
+  - policy engine
+
+-------------------------------------------------------------------
+Thu Nov  8 13:14:20 CET 2007 - coolo@suse.de
+
+- update to the latest version from SVN
+
+-------------------------------------------------------------------
+Tue Oct  2 15:26:36 CEST 2007 - kkaempf@suse.de
+
+- Initial release
+
diff --git a/libsolv-0.7.2/package/libsolv.spec.in b/libsolv-0.7.2/package/libsolv.spec.in
new file mode 100644 (file)
index 0000000..dd35ea9
--- /dev/null
@@ -0,0 +1,342 @@
+#
+# spec file for package libsolv
+#
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+#
+# All modifications and additions to the file contributed by third parties
+# remain the property of their copyright owners, unless otherwise agreed
+# upon. The license for this file, and modifications and additions to the
+# file, is the same license as for the pristine package itself (unless the
+# license for the pristine package is not an Open Source License, in which
+# case the license is the MIT License). An "Open Source License" is a
+# license that conforms to the Open Source Definition (Version 1.9)
+# published by the Open Source Initiative.
+
+# Please submit bugfixes or comments via http://bugs.opensuse.org/
+#
+
+%define libname libsolv@LIBSOLV_SOVERSION@
+
+%if 0%{?sle_version} >= 120300 || 0%{?suse_version} >= 1330 || !0%{?suse_version}
+%bcond_without bz2
+%bcond_without xz
+%else
+%bcond_with bz2
+%bcond_with xz
+%endif
+%if 0%{?is_opensuse} && (0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500)
+%bcond_without zstd
+%else
+%bcond_with zstd
+%endif
+%if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?mageia} >= 6 || 0%{?suse_version} >= 1330
+%bcond_without richdeps
+%else
+%bcond_with richdeps
+%endif
+# we need at least swig 1.3.40 for the bindings ($typemap support)
+%if 0%{?suse_version} != 1110
+%bcond_without python3
+%bcond_without python
+%bcond_without ruby
+%bcond_without perl
+%else
+%bcond_with python3
+%bcond_with python
+%bcond_with ruby
+%bcond_with perl
+%endif
+%bcond_without static
+%bcond_with shared
+%bcond_with zypp
+
+Name:           libsolv
+Version:        @VERSION@
+Release:        0
+Summary:        Package dependency solver using a satisfiability algorithm
+License:        BSD-3-Clause
+Group:          Development/Libraries/C and C++
+Url:            https://github.com/openSUSE/libsolv
+Source:         libsolv-%{version}.tar.bz2
+BuildRequires:  cmake
+BuildRequires:  gcc-c++
+BuildRequires:  libxml2-devel
+BuildRequires:  rpm-devel
+BuildRequires:  zlib-devel
+BuildRoot:      %{_tmppath}/%{name}-%{version}-build
+
+%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
+BuildRequires:  db-devel
+%endif
+
+%if %{with perl}
+BuildRequires:  perl
+%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
+BuildRequires:  perl-devel
+%endif
+BuildRequires:  swig
+%endif
+
+%if %{with ruby}
+%global ruby_vendorarch %(ruby  -r rbconfig -e "puts RbConfig::CONFIG['vendorarchdir'].nil? ? RbConfig::CONFIG['sitearchdir'] : RbConfig::CONFIG['vendorarchdir']")
+BuildRequires:  ruby
+BuildRequires:  ruby-devel
+BuildRequires:  swig
+%endif
+
+%if %{with python}
+%global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))")
+BuildRequires:  python-devel
+BuildRequires:  swig
+%endif
+
+%if %{with python3}
+%global python3_sitearch %(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))")
+BuildRequires:  python3-devel
+BuildRequires:  swig
+%endif
+
+%if %{with bz2}
+%if 0%{?suse_version}
+BuildRequires:  libbz2-devel
+%else
+BuildRequires:  bzip2-devel
+%endif
+%endif
+
+%if %{with xz}
+BuildRequires:  xz-devel
+%endif
+
+%if %{with zstd}
+BuildRequires:  libzstd-devel
+%endif
+
+
+%description
+libsolv is a library for solving packages and reading repositories.
+The solver uses a satisfiability algorithm.
+
+%if %{with shared}
+%package -n %{libname}
+Summary:        Package dependency solver using a satisfiability algorithm
+Group:          System/Libraries
+
+%description -n %{libname}
+libsolv is a library for solving packages and reading repositories.
+It consists of two central blocks: Using a dictionary approach to
+store and retrieve package and dependency information, and, using a
+so-called satisfiability algorithm for resolving package
+dependencies.
+
+%endif
+%package devel
+Summary:        Development files for libsolv, a package solver
+Group:          Development/Libraries/C and C++
+%if %{with shared}
+Requires:       %{libname} = %version
+%endif
+Requires:       rpm-devel
+Conflicts:      libsatsolver-devel
+
+%description devel
+Development files for libsolv, a library for solving packages and
+reading repositories.
+
+%package tools
+Summary:        Utilities to work with .solv files
+Group:          System/Management
+Conflicts:      satsolver-tools-obsolete
+Obsoletes:      satsolver-tools < 0.18
+Provides:       satsolver-tools = 0.18
+
+%description tools
+libsolv is a library for solving packages and reading repositories.
+
+This subpackage contains utilities to create and work with the .solv
+files used by libsolv.
+
+%package demo
+Summary:        Applications demoing the libsolv library
+Group:          System/Management
+Requires:       curl
+Conflicts:      libsatsolver-demo
+%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
+Requires:       gnupg2
+%endif
+%if 0%{?suse_version}
+Requires:       gpg2
+%endif
+
+%description demo
+Applications demoing the libsolv library.
+
+%package -n ruby-solv
+Summary:        Ruby bindings for the libsolv library
+Group:          Development/Languages/Ruby
+
+%description -n ruby-solv
+Ruby bindings for libsolv.
+
+%package -n python-solv
+%if 0%{?py_requires:1} && %{with python}
+%py_requires
+%endif
+Summary:        Python bindings for the libsolv library
+Group:          Development/Languages/Python
+
+%description -n python-solv
+Python bindings for libsolv.
+
+%package -n python3-solv
+Summary:        Python3 bindings for the libsolv library
+Group:          Development/Languages/Python
+
+%description -n python3-solv
+Python3 bindings for libsolv.
+
+%package -n perl-solv
+Summary:        Perl bindings for the libsolv library
+Group:          Development/Languages/Perl
+Requires:       perl = %{perl_version}
+
+%description -n perl-solv
+Perl bindings for libsolv.
+
+%prep
+%setup -q
+
+%build
+export CFLAGS="%{optflags}"
+export CXXFLAGS="$CFLAGS"
+
+CMAKE_FLAGS=
+%if 0%{?fedora} || 0%{?rhel} >= 6
+CMAKE_FLAGS="-DFEDORA=1"
+%endif
+%if 0%{?mageia}
+CMAKE_FLAGS="-DMAGEIA=1"
+%endif
+%if 0%{?suse_version}
+CMAKE_FLAGS="-DSUSE=1"
+%endif
+
+cmake  $CMAKE_FLAGS \
+       -DCMAKE_INSTALL_PREFIX=%{_prefix} \
+       -DLIB=%{_lib} \
+       -DCMAKE_VERBOSE_MAKEFILE=TRUE \
+       -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+       -DWITH_LIBXML2=1 \
+       -DENABLE_APPDATA=1 \
+       -DENABLE_COMPS=1 \
+       %{?with_static:-DENABLE_STATIC=1} \
+       %{!?with_shared:-DDISABLE_SHARED=1} \
+       %{?with_perl:-DENABLE_PERL=1} \
+       %{?with_python:-DENABLE_PYTHON=1} \
+       %{?with_python3:-DENABLE_PYTHON3=1} \
+       %{?with_ruby:-DENABLE_RUBY=1} \
+       %{?with_bz2:-DENABLE_BZIP2_COMPRESSION=1} \
+       %{?with_xz:-DENABLE_LZMA_COMPRESSION=1} \
+       %{?with_zstd:-DENABLE_ZSTD_COMPRESSION=1} \
+       %{?with_zstd:-DENABLE_ZCHUNK_COMPRESSION=1} \
+       %{?with_richdeps:-DENABLE_COMPLEX_DEPS=1} \
+       %{?with_zypp:-DENABLE_SUSEREPO=1 -DENABLE_HELIXREPO=1} \
+       -DUSE_VENDORDIRS=1 \
+       -DCMAKE_SKIP_RPATH=1
+make %{?_smp_mflags}
+
+%install
+make DESTDIR=%{buildroot} install
+ln -s repo2solv %{buildroot}/%{_bindir}/repo2solv.sh
+
+%if 0%{?suse_version}
+%if %{with python}
+%py_compile -O %{buildroot}/%{python_sitearch}
+%endif
+%if %{with python3}
+%py3_compile %{buildroot}/%{python3_sitearch}
+%endif
+%endif
+%if %{with static}
+# we want to leave the .a file untouched
+export NO_BRP_STRIP_DEBUG=true
+%endif
+
+%check
+make ARGS=--output-on-failure test
+
+%if %{with shared}
+%post -n %{libname} -p /sbin/ldconfig
+
+%postun -n %{libname} -p /sbin/ldconfig
+
+%files -n %{libname}
+%defattr(-,root,root)
+%license LICENSE*
+%{_libdir}/libsolv.so.*
+%{_libdir}/libsolvext.so.*
+%endif
+
+%files tools
+%defattr(-,root,root)
+%if 0%{?suse_version}
+%exclude %{_bindir}/helix2solv
+%exclude %{_mandir}/man1/helix2solv*
+%endif
+%exclude %{_mandir}/man1/solv.1*
+%exclude %{_bindir}/solv
+%{_bindir}/*
+%{_mandir}/man1/*
+
+%files devel
+%defattr(-,root,root)
+%if %{with static}
+%{_libdir}/libsolv.a
+%{_libdir}/libsolvext.a
+%endif
+%if %{with shared}
+%{_libdir}/libsolv.so
+%{_libdir}/libsolvext.so
+%endif
+%{_includedir}/solv
+%if 0%{?suse_version}
+%{_bindir}/helix2solv
+%{_mandir}/man1/helix2solv*
+%endif
+%{_datadir}/cmake/Modules/*
+%{_libdir}/pkgconfig/libsolv*.pc
+%{_mandir}/man3/*
+
+%files demo
+%defattr(-,root,root)
+%{_bindir}/solv
+%{_mandir}/man1/solv.1*
+
+%if %{with perl}
+%files -n perl-solv
+%defattr(-,root,root)
+%{perl_vendorarch}/*
+%endif
+
+%if %{with ruby}
+%files -n ruby-solv
+%defattr(-,root,root)
+%{ruby_vendorarch}/*
+%endif
+
+%if %{with python}
+%files -n python-solv
+%defattr(-,root,root)
+%{python_sitearch}/*
+%endif
+
+%if %{with python3}
+%files -n python3-solv
+%defattr(-,root,root)
+%{python3_sitearch}/*solv*
+%if 0%{?suse_version}
+%{python3_sitearch}/*/*solv*
+%endif
+%endif
+
+%changelog
diff --git a/libsolv-0.7.2/src/CMakeLists.txt b/libsolv-0.7.2/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2e32968
--- /dev/null
@@ -0,0 +1,55 @@
+
+INCLUDE (CheckFunctionExists)
+CHECK_FUNCTION_EXISTS (qsort_r HAVE_QSORT_R)
+CHECK_FUNCTION_EXISTS (__qsort_r HAVE___QSORT_R)
+
+IF (HAVE_QSORT_R)
+  ADD_DEFINITIONS (-DHAVE_QSORT_R=1)
+ENDIF (HAVE_QSORT_R)
+
+IF (HAVE___QSORT_R)
+  ADD_DEFINITIONS (-DHAVE___QSORT_R=1)
+ENDIF (HAVE___QSORT_R)
+
+ADD_DEFINITIONS (-DLIBSOLV_INTERNAL=1)
+
+SET (libsolv_SRCS
+    bitmap.c poolarch.c poolvendor.c poolid.c strpool.c dirpool.c
+    solver.c solverdebug.c repo_solv.c repo_write.c evr.c pool.c
+    queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
+    transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
+    chksum.c md5.c sha1.c sha2.c solvversion.c selection.c
+    fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c
+    userinstalled.c filelistfilter.c)
+
+SET (libsolv_HEADERS
+    bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
+    poolid.h pooltypes.h queue.h solvable.h solver.h solverdebug.h
+    repo.h repodata.h repo_solv.h repo_write.h util.h selection.h
+    strpool.h dirpool.h knownid.h transaction.h rules.h problems.h
+    chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h)
+
+SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+IF (HAVE_LINKER_VERSION_SCRIPT)
+SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver")
+ENDIF (HAVE_LINKER_VERSION_SCRIPT)
+
+IF (DISABLE_SHARED)
+ADD_LIBRARY (libsolv STATIC ${libsolv_SRCS})
+ELSE (DISABLE_SHARED)
+ADD_LIBRARY (libsolv SHARED ${libsolv_SRCS})
+ENDIF (DISABLE_SHARED)
+
+SET_TARGET_PROPERTIES(libsolv PROPERTIES OUTPUT_NAME "solv")
+SET_TARGET_PROPERTIES(libsolv PROPERTIES SOVERSION ${LIBSOLV_SOVERSION})
+SET_TARGET_PROPERTIES(libsolv PROPERTIES INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
+
+INSTALL (FILES ${libsolv_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}/solv")
+INSTALL (TARGETS libsolv LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION bin)
+
+IF (ENABLE_STATIC AND NOT DISABLE_SHARED)
+ADD_LIBRARY (libsolv_static STATIC ${libsolv_SRCS})
+SET_TARGET_PROPERTIES(libsolv_static PROPERTIES OUTPUT_NAME "solv")
+SET_TARGET_PROPERTIES(libsolv_static PROPERTIES SOVERSION ${LIBSOLV_SOVERSION})
+INSTALL (TARGETS libsolv_static LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
+ENDIF (ENABLE_STATIC AND NOT DISABLE_SHARED)
diff --git a/libsolv-0.7.2/src/bitmap.c b/libsolv-0.7.2/src/bitmap.c
new file mode 100644 (file)
index 0000000..4e8adbd
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * bitmap.c
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "bitmap.h"
+#include "util.h"
+
+/* constructor */
+void
+map_init(Map *m, int n)
+{
+  m->size = (n + 7) >> 3;
+  m->map = m->size ? solv_calloc(m->size, 1) : 0;
+}
+
+/* destructor */
+void
+map_free(Map *m)
+{
+  m->map = solv_free(m->map);
+  m->size = 0;
+}
+
+/* copy constructor target <- source */
+void
+map_init_clone(Map *target, const Map *source)
+{
+  target->size = source->size;
+  if (source->size)
+    {
+      target->map = solv_malloc(source->size);
+      memcpy(target->map, source->map, source->size);
+    }
+  else
+    target->map = 0;
+}
+
+/* grow a map */
+void
+map_grow(Map *m, int n)
+{
+  n = (n + 7) >> 3;
+  if (m->size < n)
+    {
+      m->map = solv_realloc(m->map, n);
+      memset(m->map + m->size, 0, n - m->size);
+      m->size = n;
+    }
+}
+
+/* bitwise-ands maps t and s, stores the result in t. */
+void
+map_and(Map *t, const Map *s)
+{
+  unsigned char *ti, *si, *end;
+  ti = t->map;
+  si = s->map;
+  end = ti + (t->size < s->size ? t->size : s->size);
+  while (ti < end)
+    *ti++ &= *si++;
+}
+
+/* bitwise-ors maps t and s, stores the result in t. */
+void
+map_or(Map *t, const Map *s)
+{
+  unsigned char *ti, *si, *end;
+  if (t->size < s->size)
+    map_grow(t, s->size << 3);
+  ti = t->map;
+  si = s->map;
+  end = ti + (t->size < s->size ? t->size : s->size);
+  while (ti < end)
+    *ti++ |= *si++;
+}
+
+/* remove all set bits in s from t. */
+void
+map_subtract(Map *t, const Map *s)
+{
+  unsigned char *ti, *si, *end;
+  ti = t->map;
+  si = s->map;
+  end = ti + (t->size < s->size ? t->size : s->size);
+  while (ti < end)
+    *ti++ &= ~*si++;
+}
+
+void
+map_invertall(Map *m)
+{
+  unsigned char *ti, *end;
+  ti = m->map;
+  end = ti + m->size;
+  while (ti < end)
+    *ti++ ^= 0xff;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/src/bitmap.h b/libsolv-0.7.2/src/bitmap.h
new file mode 100644 (file)
index 0000000..6609678
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007-2011, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * bitmap.h
+ *
+ */
+
+#ifndef LIBSOLV_BITMAP_H
+#define LIBSOLV_BITMAP_H
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct s_Map {
+  unsigned char *map;
+  int size;
+} Map;
+
+#define MAPZERO(m) (memset((m)->map, 0, (m)->size))
+/* set all bits */
+#define MAPSETALL(m) (memset((m)->map, 0xff, (m)->size))
+/* set bit */
+#define MAPSET(m, n) ((m)->map[(n) >> 3] |= 1 << ((n) & 7))
+/* clear bit */
+#define MAPCLR(m, n) ((m)->map[(n) >> 3] &= ~(1 << ((n) & 7)))
+/* test bit */
+#define MAPTST(m, n) ((m)->map[(n) >> 3] & (1 << ((n) & 7)))
+/* clear some bits at a position */
+#define MAPCLR_AT(m, n) ((m)->map[(n) >> 3] = 0)
+
+extern void map_init(Map *m, int n);
+extern void map_init_clone(Map *target, const Map *source);
+extern void map_grow(Map *m, int n);
+extern void map_free(Map *m);
+extern void map_and(Map *t, const Map *s);
+extern void map_or(Map *t, const Map *s);
+extern void map_subtract(Map *t, const Map *s);
+extern void map_invertall(Map *m);
+
+static inline void map_empty(Map *m)
+{
+  MAPZERO(m);
+}
+static inline void map_set(Map *m, int n)
+{
+  MAPSET(m, n);
+}
+static inline void map_setall(Map *m)
+{
+  MAPSETALL(m);
+}
+static inline void map_clr(Map *m, int n)
+{
+  MAPCLR(m, n);
+}
+static inline int map_tst(Map *m, int n)
+{
+  return MAPTST(m, n);
+}
+static inline void map_clr_at(Map *m, int n)
+{
+  MAPCLR_AT(m, n);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_BITMAP_H */
diff --git a/libsolv-0.7.2/src/chksum.c b/libsolv-0.7.2/src/chksum.c
new file mode 100644 (file)
index 0000000..df46145
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2008-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "util.h"
+#include "chksum.h"
+
+#include "md5.h"
+#include "sha1.h"
+#include "sha2.h"
+
+struct s_Chksum {
+  Id type;
+  int done;
+  unsigned char result[64];
+  union {
+    MD5_CTX md5;
+    SHA1_CTX sha1;
+    SHA224_CTX sha224;
+    SHA256_CTX sha256;
+    SHA384_CTX sha384;
+    SHA512_CTX sha512;
+  } c;
+};
+
+Chksum *
+solv_chksum_create(Id type)
+{
+  Chksum *chk;
+  chk = solv_calloc(1, sizeof(*chk));
+  chk->type = type;
+  switch(type)
+    {
+    case REPOKEY_TYPE_MD5:
+      solv_MD5_Init(&chk->c.md5);
+      return chk;
+    case REPOKEY_TYPE_SHA1:
+      solv_SHA1_Init(&chk->c.sha1);
+      return chk;
+    case REPOKEY_TYPE_SHA224:
+      solv_SHA224_Init(&chk->c.sha224);
+      return chk;
+    case REPOKEY_TYPE_SHA256:
+      solv_SHA256_Init(&chk->c.sha256);
+      return chk;
+    case REPOKEY_TYPE_SHA384:
+      solv_SHA384_Init(&chk->c.sha384);
+      return chk;
+    case REPOKEY_TYPE_SHA512:
+      solv_SHA512_Init(&chk->c.sha512);
+      return chk;
+    default:
+      break;
+    }
+  free(chk);
+  return 0;
+}
+
+Chksum *
+solv_chksum_create_clone(Chksum *chk)
+{
+  return solv_memdup(chk, sizeof(*chk));
+}
+
+int
+solv_chksum_len(Id type)
+{
+  switch (type)
+    {
+    case REPOKEY_TYPE_MD5:
+      return 16;
+    case REPOKEY_TYPE_SHA1:
+      return 20;
+    case REPOKEY_TYPE_SHA224:
+      return 28;
+    case REPOKEY_TYPE_SHA256:
+      return 32;
+    case REPOKEY_TYPE_SHA384:
+      return 48;
+    case REPOKEY_TYPE_SHA512:
+      return 64;
+    default:
+      return 0;
+    }
+}
+
+Chksum *
+solv_chksum_create_from_bin(Id type, const unsigned char *buf)
+{
+  Chksum *chk;
+  int l = solv_chksum_len(type);
+  if (buf == 0 || l == 0)
+    return 0;
+  chk = solv_calloc(1, sizeof(*chk));
+  chk->type = type;
+  chk->done = 1;
+  memcpy(chk->result, buf, l);
+  return chk;
+}
+
+void
+solv_chksum_add(Chksum *chk, const void *data, int len)
+{
+  if (chk->done)
+    return;
+  switch(chk->type)
+    {
+    case REPOKEY_TYPE_MD5:
+      solv_MD5_Update(&chk->c.md5, (void *)data, len);
+      return;
+    case REPOKEY_TYPE_SHA1:
+      solv_SHA1_Update(&chk->c.sha1, data, len);
+      return;
+    case REPOKEY_TYPE_SHA224:
+      solv_SHA224_Update(&chk->c.sha224, data, len);
+      return;
+    case REPOKEY_TYPE_SHA256:
+      solv_SHA256_Update(&chk->c.sha256, data, len);
+      return;
+    case REPOKEY_TYPE_SHA384:
+      solv_SHA384_Update(&chk->c.sha384, data, len);
+      return;
+    case REPOKEY_TYPE_SHA512:
+      solv_SHA512_Update(&chk->c.sha512, data, len);
+      return;
+    default:
+      return;
+    }
+}
+
+const unsigned char *
+solv_chksum_get(Chksum *chk, int *lenp)
+{
+  if (chk->done)
+    {
+      if (lenp)
+        *lenp = solv_chksum_len(chk->type);
+      return chk->result;
+    }
+  switch(chk->type)
+    {
+    case REPOKEY_TYPE_MD5:
+      solv_MD5_Final(chk->result, &chk->c.md5);
+      chk->done = 1;
+      if (lenp)
+       *lenp = 16;
+      return chk->result;
+    case REPOKEY_TYPE_SHA1:
+      solv_SHA1_Final(&chk->c.sha1, chk->result);
+      chk->done = 1;
+      if (lenp)
+       *lenp = 20;
+      return chk->result;
+    case REPOKEY_TYPE_SHA224:
+      solv_SHA224_Final(chk->result, &chk->c.sha224);
+      chk->done = 1;
+      if (lenp)
+       *lenp = 28;
+      return chk->result;
+    case REPOKEY_TYPE_SHA256:
+      solv_SHA256_Final(chk->result, &chk->c.sha256);
+      chk->done = 1;
+      if (lenp)
+       *lenp = 32;
+      return chk->result;
+    case REPOKEY_TYPE_SHA384:
+      solv_SHA384_Final(chk->result, &chk->c.sha384);
+      chk->done = 1;
+      if (lenp)
+       *lenp = 48;
+      return chk->result;
+    case REPOKEY_TYPE_SHA512:
+      solv_SHA512_Final(chk->result, &chk->c.sha512);
+      chk->done = 1;
+      if (lenp)
+       *lenp = 64;
+      return chk->result;
+    default:
+      if (lenp)
+       *lenp = 0;
+      return 0;
+    }
+}
+
+Id
+solv_chksum_get_type(Chksum *chk)
+{
+  return chk->type;
+}
+
+int
+solv_chksum_isfinished(Chksum *chk)
+{
+  return chk->done != 0;
+}
+
+const char *
+solv_chksum_type2str(Id type)
+{
+  switch(type)
+    {
+    case REPOKEY_TYPE_MD5:
+      return "md5";
+    case REPOKEY_TYPE_SHA1:
+      return "sha1";
+    case REPOKEY_TYPE_SHA224:
+      return "sha224";
+    case REPOKEY_TYPE_SHA256:
+      return "sha256";
+    case REPOKEY_TYPE_SHA384:
+      return "sha384";
+    case REPOKEY_TYPE_SHA512:
+      return "sha512";
+    default:
+      return 0;
+    }
+}
+
+Id
+solv_chksum_str2type(const char *str)
+{
+  if (!strcasecmp(str, "md5"))
+    return REPOKEY_TYPE_MD5;
+  if (!strcasecmp(str, "sha") || !strcasecmp(str, "sha1"))
+    return REPOKEY_TYPE_SHA1;
+  if (!strcasecmp(str, "sha224"))
+    return REPOKEY_TYPE_SHA224;
+  if (!strcasecmp(str, "sha256"))
+    return REPOKEY_TYPE_SHA256;
+  if (!strcasecmp(str, "sha384"))
+    return REPOKEY_TYPE_SHA384;
+  if (!strcasecmp(str, "sha512"))
+    return REPOKEY_TYPE_SHA512;
+  return 0;
+}
+
+void *
+solv_chksum_free(Chksum *chk, unsigned char *cp)
+{
+  if (cp)
+    {
+      const unsigned char *res;
+      int l;
+      res = solv_chksum_get(chk, &l);
+      if (l && res)
+        memcpy(cp, res, l);
+    }
+  solv_free(chk);
+  return 0;
+}
+
+int
+solv_chksum_cmp(Chksum *chk, Chksum *chk2)
+{
+  int len;
+  const unsigned char *res1, *res2;
+  if (chk == chk2)
+    return 1;
+  if (!chk || !chk2 || chk->type != chk2->type)
+    return 0;
+  res1 = solv_chksum_get(chk, &len);
+  res2 = solv_chksum_get(chk2, 0);
+  return memcmp(res1, res2, len) == 0 ? 1 : 0;
+}
diff --git a/libsolv-0.7.2/src/chksum.h b/libsolv-0.7.2/src/chksum.h
new file mode 100644 (file)
index 0000000..65b775b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef LIBSOLV_CHKSUM_H
+#define LIBSOLV_CHKSUM_H
+
+#include "pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct s_Chksum;
+typedef struct s_Chksum Chksum;
+
+Chksum *solv_chksum_create(Id type);
+Chksum *solv_chksum_create_clone(Chksum *chk);
+Chksum *solv_chksum_create_from_bin(Id type, const unsigned char *buf);
+void solv_chksum_add(Chksum *chk, const void *data, int len);
+Id solv_chksum_get_type(Chksum *chk);
+int solv_chksum_isfinished(Chksum *chk);
+const unsigned char *solv_chksum_get(Chksum *chk, int *lenp);
+void *solv_chksum_free(Chksum *chk, unsigned char *cp);
+const char *solv_chksum_type2str(Id type);
+Id solv_chksum_str2type(const char *str);
+int solv_chksum_len(Id type);
+int solv_chksum_cmp(Chksum *chk, Chksum *chk2);
+
+#ifdef LIBSOLV_INTERNAL
+
+#define case_CHKSUM_TYPES \
+    case REPOKEY_TYPE_MD5: \
+    case REPOKEY_TYPE_SHA1: \
+    case REPOKEY_TYPE_SHA224: \
+    case REPOKEY_TYPE_SHA256: \
+    case REPOKEY_TYPE_SHA384: \
+    case REPOKEY_TYPE_SHA512
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_CHKSUM_H */
diff --git a/libsolv-0.7.2/src/cleandeps.c b/libsolv-0.7.2/src/cleandeps.c
new file mode 100644 (file)
index 0000000..1da28f6
--- /dev/null
@@ -0,0 +1,1393 @@
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * cleandeps.c
+ *
+ * code to find and erase unneeded packages
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solverdebug.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "policy.h"
+#include "cplxdeps.h"
+
+#undef CLEANDEPSDEBUG
+
+/*
+ * This functions collects all packages that are looked at
+ * when a dependency is checked. We need it to "pin" installed
+ * packages when removing a supplemented package in createcleandepsmap.
+ * Here's an not uncommon example:
+ *   A contains "Supplements: packageand(B, C)"
+ *   B contains "Requires: A"
+ * Now if we remove C, the supplements is no longer true,
+ * thus we also remove A. Without the dep_pkgcheck function, we
+ * would now also remove B, but this is wrong, as adding back
+ * C doesn't make the supplements true again. Thus we "pin" B
+ * when we remove A.
+ * There's probably a better way to do this, but I haven't come
+ * up with it yet ;)
+ */
+static void
+dep_pkgcheck_slow(Solver *solv, Id dep, Map *m, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags >= 8)
+       {
+         if (rd->flags == REL_AND)
+           {
+             dep_pkgcheck_slow(solv, rd->name, m, q);
+             dep_pkgcheck_slow(solv, rd->evr, m, q);
+             return;
+           }
+         if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
+           {
+             dep_pkgcheck_slow(solv, rd->name, m, q);
+             if (ISRELDEP(rd->evr))
+               {
+                 Reldep *rd2 = GETRELDEP(pool, rd->evr);
+                 if (rd2->flags == REL_ELSE)
+                   dep_pkgcheck_slow(solv, rd2->evr, m, q);
+               }
+             return;
+           }
+         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+           return;
+       }
+    }
+  FOR_PROVIDES(p, pp, dep)
+    if (!m || MAPTST(m, p))
+      queue_push(q, p);
+}
+
+static inline void
+dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (!ISSIMPLEDEP(pool, dep))
+    {
+      dep_pkgcheck_slow(solv, dep, m, q);
+      return;
+    }
+  FOR_PROVIDES(p, pp, dep)
+    if (!m || MAPTST(m, p))
+      queue_push(q, p);
+}
+
+static int
+check_xsupp(Solver *solv, Queue *depq, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags >= 8)
+       {
+         if (rd->flags == REL_AND)
+           {
+             if (!check_xsupp(solv, depq, rd->name))
+               return 0;
+             return check_xsupp(solv, depq, rd->evr);
+           }
+         if (rd->flags == REL_OR)
+           {
+             if (check_xsupp(solv, depq, rd->name))
+               return 1;
+             return check_xsupp(solv, depq, rd->evr);
+           }
+         if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+           return 0;
+         if (depq && rd->flags == REL_NAMESPACE)
+           {
+             int i;
+             for (i = 0; i < depq->count; i++)
+               if (depq->elements[i] == dep || depq->elements[i] == rd->name)
+                return 1;
+           }
+       }
+    }
+  FOR_PROVIDES(p, pp, dep)
+    if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed)
+      return 1;
+  return 0;
+}
+
+struct trj_data {
+  Queue *edges;
+  Id *low;
+  Id idx;
+  Id nstack;
+  Id firstidx;
+};
+
+/* Tarjan's SCC algorithm, slightly modifed */
+static void
+trj_visit(struct trj_data *trj, Id node)
+{
+  Id *low = trj->low;
+  Queue *edges = trj->edges;
+  Id nnode, myidx, stackstart;
+  int i;
+
+  low[node] = myidx = trj->idx++;
+  low[(stackstart = trj->nstack++)] = node;
+  for (i = edges->elements[node]; (nnode = edges->elements[i]) != 0; i++)
+    {
+      Id l = low[nnode];
+      if (!l)
+       {
+         if (!edges->elements[edges->elements[nnode]])
+           {
+             trj->idx++;
+             low[nnode] = -1;
+             continue;
+           }
+         trj_visit(trj, nnode);
+         l = low[nnode];
+       }
+      if (l < 0)
+       continue;
+      if (l < trj->firstidx)
+       {
+         int k;
+         for (k = l; low[low[k]] == l; k++)
+           low[low[k]] = -1;
+       }
+      else if (l < low[node])
+       low[node] = l;
+    }
+  if (low[node] == myidx)
+    {
+      if (myidx != trj->firstidx)
+       myidx = -1;
+      for (i = stackstart; i < trj->nstack; i++)
+       low[low[i]] = myidx;
+      trj->nstack = stackstart;
+    }
+}
+
+#ifdef ENABLE_COMPLEX_DEPS
+static void
+complex_filter_unneeded(Pool *pool, Id ip, Id req, Queue *edges, Map *cleandepsmap, Queue *unneededq)
+{
+  int i, j;
+  Queue dq;
+  Id p;
+
+  queue_init(&dq);
+  i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    {
+      queue_free(&dq);
+      return;
+    }
+  for (i = 0; i < dq.count; i++)
+    {
+      for (; (p = dq.elements[i]) != 0; i++)
+       {
+         if (p < 0)
+           {
+             if (pool->solvables[-p].repo != pool->installed)
+               break;
+             continue;
+           }
+         if (p == ip || pool->solvables[p].repo != pool->installed || !MAPTST(cleandepsmap, p - pool->installed->start))
+           continue;
+         for (j = 0; j < unneededq->count; j++)
+           if (p == unneededq->elements[j])
+             {
+               if (edges->elements[edges->count - 1] != j + 1)
+                 queue_push(edges, j + 1);
+               break;
+             }
+       }
+      while (dq.elements[i])
+       i++;
+    }
+  queue_free(&dq);
+}
+#endif
+
+
+static void
+filter_unneeded(Solver *solv, Queue *unneededq, Map *unneededmap, int justone)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Queue edges;
+  Id *nrequires;
+  Map m, installedm;
+  int i, j, pass, count = unneededq->count;
+  Id *low;
+
+  if (unneededq->count < 2)
+    return;
+  map_init(&m, 0);
+  if (!unneededmap)
+    {
+      unneededmap = &m;
+      map_grow(unneededmap, installed->end - installed->start);
+      for (i = 0; i < count; i++)
+       MAPSET(unneededmap, unneededq->elements[i] - installed->start);
+    }
+  map_init(&installedm, pool->nsolvables);
+  for (i = installed->start; i < installed->end; i++)
+    if (pool->solvables[i].repo == installed)
+      MAPSET(&installedm, i);
+
+  nrequires = solv_calloc(count, sizeof(Id));
+  queue_init(&edges);
+  queue_prealloc(&edges, count * 4 + 10);      /* pre-size */
+
+  /*
+   * Go through the solvables in the nodes queue and create edges for
+   * all requires/recommends/supplements between the nodes.
+   * The edges are stored in the edges queue, we add 1 to the node
+   * index so that nodes in the edges queue are != 0 and we can
+   * terminate the edge list with 0.
+   * Thus for node element 5, the edges are stored starting at
+   * edges.elements[6] and are 0-terminated.
+   */
+  /* leave first element zero to make things easier */
+  /* also add trailing zero */
+  queue_insertn(&edges, 0, 1 + count + 1, 0);
+
+  /* first requires and recommends */
+  for (i = 0; i < count; i++)
+    {
+      Solvable *s = pool->solvables + unneededq->elements[i];
+      int oldcount = edges.count;
+      edges.elements[i + 1] = oldcount;
+      for (pass = 0; pass < 2; pass++)
+       {
+         unsigned int off = pass == 0 ? s->requires : s->recommends;
+         Id p, pp, dep, *dp;
+         if (off)
+           for (dp = s->repo->idarraydata + off; (dep = *dp) != 0; dp++)
+             {
+#ifdef ENABLE_COMPLEX_DEPS
+               if (pool_is_complex_dep(pool, dep))
+                 {
+                   complex_filter_unneeded(pool, s - pool->solvables, dep, &edges, unneededmap, unneededq);
+                   continue;
+                 }
+#endif
+               if (justone)
+                 {
+                   int count = 0;
+                   FOR_PROVIDES(p, pp, dep)
+                     {
+                       Solvable *sp = pool->solvables + p;
+                       if (s == sp || sp->repo != installed)
+                         continue;
+                       count++;
+                     }
+                   if (count != 1)
+                     continue;
+                 }
+               FOR_PROVIDES(p, pp, dep)
+                 {
+                   Solvable *sp = pool->solvables + p;
+                   if (s == sp || sp->repo != installed || !MAPTST(unneededmap, p - installed->start))
+                     continue;
+                   for (j = 0; j < count; j++)
+                     if (p == unneededq->elements[j])
+                       {
+                         if (edges.elements[edges.count - 1] != j + 1)
+                           queue_push(&edges, j + 1);
+                       }
+                 }
+             }
+         if (pass == 0)
+           nrequires[i] = edges.count - oldcount;
+       }
+      queue_push(&edges, 0);
+    }
+#if 0
+  printf("requires + recommends\n");
+  for (i = 0; i < count; i++)
+    {
+      int j;
+      printf("  %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]);
+      for (j = edges.elements[i + 1]; edges.elements[j]; j++)
+       printf("    - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1]));
+    }
+#endif
+
+  /* then add supplements */
+  for (i = 0; i < count; i++)
+    {
+      Solvable *s = pool->solvables + unneededq->elements[i];
+      if (s->supplements)
+       {
+         Id *dp;
+         int k;
+         for (dp = s->repo->idarraydata + s->supplements; *dp; dp++)
+           if (solver_dep_possible(solv, *dp, &installedm))
+             {
+               Queue iq;
+               Id iqbuf[16];
+               queue_init_buffer(&iq, iqbuf, sizeof(iqbuf)/sizeof(*iqbuf));
+               dep_pkgcheck(solv, *dp, 0, &iq);
+               if (justone && iq.count != 1)
+                 {
+                   queue_free(&iq);
+                   continue;
+                 }
+               for (k = 0; k < iq.count; k++)
+                 {
+                   Id p = iq.elements[k];
+                   Solvable *sp = pool->solvables + p;
+                   if (p == unneededq->elements[i] || sp->repo != installed || !MAPTST(unneededmap, p - installed->start))
+                     continue;
+                   for (j = 0; j < count; j++)
+                     if (p == unneededq->elements[j])
+                       break;
+                   /* now add edge from j + 1 to i + 1 */
+                   queue_insert(&edges, edges.elements[j + 1] + nrequires[j], i + 1);
+                   /* addapt following edge pointers */
+                   for (j = j + 2; j < count + 1; j++)
+                     edges.elements[j]++;
+                 }
+               queue_free(&iq);
+             }
+       }
+    }
+#if 0
+  /* print result */
+  printf("+ supplements\n");
+  for (i = 0; i < count; i++)
+    {
+      int j;
+      printf("  %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]);
+      for (j = edges.elements[i + 1]; edges.elements[j]; j++)
+       printf("    - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1]));
+    }
+#endif
+  map_free(&installedm);
+
+  /* now run SCC algo two times, first with requires+recommends+supplements,
+   * then again without the requires. We run it the second time to get rid
+   * of packages that got dragged in via recommends/supplements */
+  /*
+   * low will contain the result of the SCC search.
+   * it must be of at least size 2 * (count + 1) and
+   * must be zero initialized.
+   * The layout is:
+   *    0  low low ... low stack stack ...stack 0
+   *            count              count
+   */
+  low = solv_calloc(count + 1, 2 * sizeof(Id));
+  for (pass = 0; pass < 2; pass++)
+    {
+      struct trj_data trj;
+      if (pass)
+       {
+         memset(low, 0, (count + 1) * (2 * sizeof(Id)));
+         for (i = 0; i < count; i++)
+           {
+             edges.elements[i + 1] += nrequires[i];
+             if (!unneededq->elements[i])
+               low[i + 1] = -1;        /* ignore this node */
+           }
+       }
+      trj.edges = &edges;
+      trj.low = low;
+      trj.idx = count + 1;     /* stack starts here */
+      for (i = 1; i <= count; i++)
+       {
+         if (low[i])
+           continue;
+         if (edges.elements[edges.elements[i]])
+           {
+             trj.firstidx = trj.nstack = trj.idx;
+             trj_visit(&trj, i);
+           }
+         else
+           {
+             Id myidx = trj.idx++;
+             low[i] = myidx;
+             low[myidx] = i;
+           }
+       }
+      /* prune packages */
+      for (i = 0; i < count; i++)
+       if (low[i + 1] <= 0)
+         unneededq->elements[i] = 0;
+    }
+  solv_free(low);
+  solv_free(nrequires);
+  queue_free(&edges);
+
+  /* finally remove all pruned entries from unneededq */
+  for (i = j = 0; i < count; i++)
+    if (unneededq->elements[i])
+      unneededq->elements[j++] = unneededq->elements[i];
+  queue_truncate(unneededq, j);
+  map_free(&m);
+}
+
+
+#ifdef ENABLE_COMPLEX_DEPS
+static void
+complex_cleandeps_remove(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq)
+{
+  int i;
+  Queue dq;
+  Id p;
+
+  queue_init(&dq);
+  i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    {
+      queue_free(&dq);
+      return;
+    }
+  for (i = 0; i < dq.count; i++)
+    {
+      for (; (p = dq.elements[i]) != 0; i++)
+       {
+         if (p < 0)
+           {
+             if (!MAPTST(installedm, -p))
+               break;
+             continue;
+           }
+         if (p != SYSTEMSOLVABLE && MAPTST(im, p))
+           {
+#ifdef CLEANDEPSDEBUG
+             printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+             queue_push(iq, p);
+           }
+       }
+      while (dq.elements[i])
+       i++;
+    }
+  queue_free(&dq);
+}
+
+static void
+complex_cleandeps_addback(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq, Map *userinstalled)
+{
+  int i, blk;
+  Queue dq;
+  Id p;
+
+  queue_init(&dq);
+  i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    {
+      queue_free(&dq);
+      return;
+    }
+  for (i = 0; i < dq.count; i++)
+    {
+      blk = i;
+      for (; (p = dq.elements[i]) != 0; i++)
+       {
+         if (p < 0)
+           {
+             if (!MAPTST(installedm, -p))
+               break;
+           }
+         else if (p == ip)
+           break;
+       }
+      if (!p)
+       {
+         for (i = blk; (p = dq.elements[i]) != 0; i++)
+           {
+             if (p < 0)
+               continue;
+             if (MAPTST(im, p))
+               continue;
+             if (!MAPTST(installedm, p))
+               continue;
+             if (p == ip || MAPTST(userinstalled, p - pool->installed->start))
+               continue;
+#ifdef CLEANDEPSDEBUG
+             printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+             MAPSET(im, p);
+             queue_push(iq, p);
+           }
+       }
+      while (dq.elements[i])
+       i++;
+    }
+  queue_free(&dq);
+}
+
+#endif
+
+static inline int
+queue_contains(Queue *q, Id id)
+{
+  int i;
+  for (i = 0; i < q->count; i++)
+    if (q->elements[i] == id)
+      return 1;
+  return 0;
+}
+
+static void
+find_update_seeds(Solver *solv, Queue *updatepkgs_filtered, Map *userinstalled)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Queue *cleandeps_updatepkgs = solv->cleandeps_updatepkgs;
+  int i, j;
+  Id p;
+
+  queue_prealloc(updatepkgs_filtered, cleandeps_updatepkgs->count);
+  for (i = 0; i < cleandeps_updatepkgs->count; i++)
+    {
+      p = cleandeps_updatepkgs->elements[i];
+      if (pool->solvables[p].repo == installed)
+       {
+#ifdef ENABLE_LINKED_PKGS
+         const char *name = pool_id2str(pool, pool->solvables[p].name);
+         if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
+           continue;
+#endif
+         queue_push(updatepkgs_filtered, p);
+       }
+    }
+#ifdef CLEANDEPSDEBUG
+  printf("SEEDS IN (%d)\n", updatepkgs_filtered->count);
+  for (i = 0; i < updatepkgs_filtered->count; i++)
+    printf("  - %s\n", pool_solvid2str(pool, updatepkgs_filtered->elements[i]));
+#endif
+  filter_unneeded(solv, updatepkgs_filtered, 0, 1);
+#ifdef CLEANDEPSDEBUG
+  printf("SEEDS OUT (%d)\n", updatepkgs_filtered->count);
+  for (i = 0; i < updatepkgs_filtered->count; i++)
+    printf("  - %s\n", pool_solvid2str(pool, updatepkgs_filtered->elements[i]));
+#endif
+  /* make sure userinstalled packages are in the seeds */
+  for (i = j = 0; i < updatepkgs_filtered->count; i++)
+    {
+      p = updatepkgs_filtered->elements[i];
+      if (!MAPTST(userinstalled, p - installed->start))
+       updatepkgs_filtered->elements[j++] = p;
+    }
+  queue_truncate(updatepkgs_filtered, j);
+  for (i = 0; i < cleandeps_updatepkgs->count; i++)
+    {
+      p = cleandeps_updatepkgs->elements[i];
+      if (pool->solvables[p].repo == installed)
+       {
+#ifdef ENABLE_LINKED_PKGS
+         const char *name = pool_id2str(pool, pool->solvables[p].name);
+         if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
+           {
+             queue_push(updatepkgs_filtered, p);
+             continue;
+           }
+#endif
+         if (MAPTST(userinstalled, p - installed->start))
+           queue_push(updatepkgs_filtered, p);
+       }
+    }
+#ifdef CLEANDEPSDEBUG
+  printf("SEEDS FINAL\n");
+  for (i = 0; i < updatepkgs_filtered->count; i++)
+    printf("  - %s\n", pool_solvid2str(pool, updatepkgs_filtered->elements[i]));
+#endif
+}
+
+/*
+ * Find all installed packages that are no longer
+ * needed regarding the current solver job.
+ *
+ * The algorithm is:
+ * - remove pass: remove all packages that could have
+ *   been dragged in by the obsoleted packages.
+ *   i.e. if package A is obsolete and contains "Requires: B",
+ *   also remove B, as installing A will have pulled in B.
+ *   after this pass, we have a set of still installed packages
+ *   with broken dependencies.
+ * - add back pass:
+ *   now add back all packages that the still installed packages
+ *   require.
+ *
+ * The cleandeps packages are the packages removed in the first
+ * pass and not added back in the second pass.
+ *
+ * If we search for unneeded packages (unneeded is true), we
+ * simply remove all packages except the userinstalled ones in
+ * the first pass.
+ */
+void
+solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Queue *job = &solv->job;
+  Map userinstalled;
+  Map im;
+  Map installedm;
+  Rule *r;
+  Id rid, how, what, select;
+  Id p, pp, ip, jp;
+  Id req, *reqp, sup, *supp;
+  Solvable *s;
+  Queue iq, iqcopy, xsuppq;
+  Queue updatepkgs_filtered;
+  int i;
+
+  map_empty(cleandepsmap);
+  if (!installed || installed->end == installed->start)
+    return;
+  map_init(&userinstalled, installed->end - installed->start);
+  map_init(&im, pool->nsolvables);
+  map_init(&installedm, pool->nsolvables);
+  queue_init(&iq);
+  queue_init(&xsuppq);
+
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+       {
+         what = job->elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+           {
+             FOR_REPO_SOLVABLES(installed, p, s)
+               MAPSET(&userinstalled, p - installed->start);
+           }
+         FOR_JOB_SELECT(p, pp, select, what)
+           if (pool->solvables[p].repo == installed)
+             MAPSET(&userinstalled, p - installed->start);
+       }
+      if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES))
+       {
+         what = job->elements[i + 1];
+         if (ISRELDEP(what))
+           {
+             Reldep *rd = GETRELDEP(pool, what);
+             if (rd->flags != REL_NAMESPACE)
+               continue;
+             if (rd->evr == 0)
+               {
+                 queue_pushunique(&iq, rd->name);
+                 continue;
+               }
+             FOR_PROVIDES(p, pp, what)
+               if (p)
+                 break;
+             if (p)
+               continue;
+             queue_pushunique(&iq, what);
+           }
+       }
+    }
+
+  /* have special namespace cleandeps erases */
+  if (iq.count)
+    {
+      for (ip = installed->start; ip < installed->end; ip++)
+       {
+         s = pool->solvables + ip;
+         if (s->repo != installed)
+           continue;
+         if (!s->supplements)
+           continue;
+         supp = s->repo->idarraydata + s->supplements;
+         while ((sup = *supp++) != 0)
+           if (ISRELDEP(sup) && check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup))
+             {
+#ifdef CLEANDEPSDEBUG
+               printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip));
+#endif
+               queue_pushunique(&xsuppq, sup);
+             }
+       }
+      queue_empty(&iq);
+    }
+
+  /* also add visible patterns to userinstalled for openSUSE */
+  if (1)
+    {
+      Dataiterator di;
+      dataiterator_init(&di, pool, 0, 0, SOLVABLE_ISVISIBLE, 0, 0);
+      while (dataiterator_step(&di))
+       {
+         Id *dp;
+         if (di.solvid <= 0)
+           continue;
+         s = pool->solvables + di.solvid;
+         if (!s->repo || !s->requires)
+           continue;
+         if (s->repo != installed && !pool_installable(pool, s))
+           continue;
+         if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0)
+           continue;
+         dp = s->repo->idarraydata + s->requires;
+         for (dp = s->repo->idarraydata + s->requires; *dp; dp++)
+           FOR_PROVIDES(p, pp, *dp)
+             if (pool->solvables[p].repo == installed)
+               {
+                 if (strncmp(pool_id2str(pool, pool->solvables[p].name), "pattern", 7) != 0)
+                   continue;
+                 MAPSET(&userinstalled, p - installed->start);
+               }
+       }
+      dataiterator_free(&di);
+    }
+  if (1)
+    {
+      /* all products and their buddies are userinstalled */
+      for (p = installed->start; p < installed->end; p++)
+       {
+         Solvable *s = pool->solvables + p;
+         if (s->repo != installed)
+           continue;
+         if (!strncmp("product:", pool_id2str(pool, s->name), 8))
+           {
+             MAPSET(&userinstalled, p - installed->start);
+#ifdef ENABLE_LINKED_PKGS
+             if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
+               {
+                 Id buddy = solv->instbuddy[p - installed->start];
+                 if (buddy >= installed->start && buddy < installed->end)
+                   MAPSET(&userinstalled, buddy - installed->start);
+               }
+#endif
+           }
+       }
+    }
+
+  /* add all positive elements (e.g. locks) to "userinstalled" */
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->d < 0)
+       continue;
+      i = solv->ruletojob.elements[rid - solv->jobrules];
+      if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
+       continue;
+      FOR_RULELITERALS(p, jp, r)
+       if (p > 0 && pool->solvables[p].repo == installed)
+         MAPSET(&userinstalled, p - installed->start);
+    }
+
+  /* add all cleandeps candidates to iq */
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->d < 0)                            /* disabled? */
+       continue;
+      if (r->d == 0 && r->p < 0 && r->w2 == 0) /* negative assertion (erase job)? */
+       {
+         p = -r->p;
+         if (pool->solvables[p].repo != installed)
+           continue;
+         MAPCLR(&userinstalled, p - installed->start);
+         if (unneeded)
+           continue;
+         i = solv->ruletojob.elements[rid - solv->jobrules];
+         how = job->elements[i];
+         if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
+           queue_push(&iq, p);
+       }
+      else if (r->p > 0)                       /* install job */
+       {
+         if (unneeded)
+           continue;
+         i = solv->ruletojob.elements[rid - solv->jobrules];
+         if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
+           {
+             /* check if the literals all obsolete some installed package */
+             Map om;
+             int iqstart;
+
+             /* just one installed literal */
+             if (r->d == 0 && r->w2 == 0 && pool->solvables[r->p].repo == installed)
+               continue;
+             /* multiversion is bad */
+             if (solv->multiversion.size && !solv->keepexplicitobsoletes)
+               {
+                 FOR_RULELITERALS(p, jp, r)
+                   if (MAPTST(&solv->multiversion, p))
+                     break;
+                 if (p)
+                   continue;
+               }
+
+             om.size = 0;
+             iqstart = iq.count;
+             FOR_RULELITERALS(p, jp, r)
+               {
+                 if (p < 0)
+                   {
+                     queue_truncate(&iq, iqstart);     /* abort */
+                     break;
+                   }
+                 if (pool->solvables[p].repo == installed)
+                   {
+                     if (iq.count == iqstart)
+                       queue_push(&iq, p);
+                     else
+                       {
+                         for (i = iqstart; i < iq.count; i++)
+                           if (iq.elements[i] == p)
+                             break;
+                         queue_truncate(&iq, iqstart);
+                         if (i < iq.count)
+                           queue_push(&iq, p);
+                       }
+                   }
+                 else
+                   solver_intersect_obsoleted(solv, p, &iq, iqstart, &om);
+                 if (iq.count == iqstart)
+                   break;
+               }
+             if (om.size)
+               map_free(&om);
+           }
+       }
+    }
+  queue_init_clone(&iqcopy, &iq);
+
+  if (!unneeded)
+    {
+      if (solv->cleandeps_updatepkgs)
+       for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
+         queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]);
+    }
+
+  if (unneeded)
+    queue_empty(&iq);  /* just in case... */
+
+  /* clear userinstalled bit for the packages we really want to delete/update */
+  for (i = 0; i < iq.count; i++)
+    {
+      p = iq.elements[i];
+      if (pool->solvables[p].repo != installed)
+       continue;
+      MAPCLR(&userinstalled, p - installed->start);
+    }
+
+  for (p = installed->start; p < installed->end; p++)
+    {
+      if (pool->solvables[p].repo != installed)
+       continue;
+      MAPSET(&installedm, p);
+      if (pool->considered && !MAPTST(pool->considered, p))
+       MAPSET(&userinstalled, p - installed->start);   /* we may not remove those */
+      if (unneeded && !MAPTST(&userinstalled, p - installed->start))
+       continue;
+      MAPSET(&im, p);
+    }
+  MAPSET(&installedm, SYSTEMSOLVABLE);
+  MAPSET(&im, SYSTEMSOLVABLE);
+
+  if (!unneeded && solv->cleandeps_updatepkgs)
+    {
+      /* find update "seeds" */
+      queue_init(&updatepkgs_filtered);
+      find_update_seeds(solv, &updatepkgs_filtered, &userinstalled);
+    }
+
+#ifdef CLEANDEPSDEBUG
+  printf("REMOVE PASS\n");
+#endif
+
+  for (;;)
+    {
+      if (!iq.count)
+       {
+         if (unneeded)
+           break;
+         /* supplements pass */
+         for (ip = installed->start; ip < installed->end; ip++)
+           {
+             if (!MAPTST(&installedm, ip))
+               continue;
+             s = pool->solvables + ip;
+             if (!s->supplements)
+               continue;
+             if (!MAPTST(&im, ip))
+               continue;
+             if (MAPTST(&userinstalled, ip - installed->start))
+               continue;
+             supp = s->repo->idarraydata + s->supplements;
+             while ((sup = *supp++) != 0)
+               if (solver_dep_possible(solv, sup, &im))
+                 break;
+             if (!sup)
+               {
+                 supp = s->repo->idarraydata + s->supplements;
+                 while ((sup = *supp++) != 0)
+                   if (solver_dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
+                     {
+                       /* no longer supplemented, also erase */
+                       int iqcount = iq.count;
+                       /* pin packages, see comment above dep_pkgcheck */
+                       dep_pkgcheck(solv, sup, &im, &iq);
+                       for (i = iqcount; i < iq.count; i++)
+                         {
+                           Id pqp = iq.elements[i];
+                           if (pool->solvables[pqp].repo == installed)
+                             MAPSET(&userinstalled, pqp - installed->start);
+                         }
+                       queue_truncate(&iq, iqcount);
+#ifdef CLEANDEPSDEBUG
+                       printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup));
+#endif
+                       queue_push(&iq, ip);
+                     }
+               }
+           }
+         if (!iq.count)
+           break;      /* no supplementing package found, we're done */
+       }
+      ip = queue_shift(&iq);
+      s = pool->solvables + ip;
+      if (!MAPTST(&im, ip))
+       continue;
+      if (!MAPTST(&installedm, ip))
+       continue;
+      if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
+       continue;
+      MAPCLR(&im, ip);
+#ifdef CLEANDEPSDEBUG
+      printf("removing %s\n", pool_solvable2str(pool, s));
+#endif
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)
+           {
+             if (req == SOLVABLE_PREREQMARKER)
+               continue;
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, req))
+               {
+                 complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
+                   {
+#ifdef CLEANDEPSDEBUG
+                     printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+      if (s->recommends)
+       {
+         reqp = s->repo->idarraydata + s->recommends;
+         while ((req = *reqp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, req))
+               {
+                 complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
+                   {
+#ifdef CLEANDEPSDEBUG
+                     printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+    }
+
+  /* turn userinstalled into remove set for pruning */
+  map_empty(&userinstalled);
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->p >= 0 || r->d != 0 || r->w2 != 0)
+       continue;       /* disabled or not erase */
+      p = -r->p;
+      MAPCLR(&im, p);
+      if (pool->solvables[p].repo == installed)
+        MAPSET(&userinstalled, p - installed->start);
+    }
+  if (!unneeded && solv->cleandeps_updatepkgs)
+    {
+      for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
+       {
+         p = solv->cleandeps_updatepkgs->elements[i];
+         if (pool->solvables[p].repo == installed)
+           MAPSET(&userinstalled, p - installed->start);
+       }
+    }
+  MAPSET(&im, SYSTEMSOLVABLE); /* in case we cleared it above */
+  for (p = installed->start; p < installed->end; p++)
+    if (MAPTST(&im, p))
+      queue_push(&iq, p);
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->d < 0)
+       continue;
+      FOR_RULELITERALS(p, jp, r)
+       if (p > 0)
+          queue_push(&iq, p);
+    }
+  /* also put directly addressed packages on the install queue
+   * so we can mark patterns as installed */
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+       {
+         what = job->elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
+            queue_push(&iq, what);
+       }
+    }
+
+#ifdef CLEANDEPSDEBUG
+  printf("ADDBACK PASS\n");
+#endif
+  for (;;)
+    {
+      if (!iq.count)
+       {
+         /* supplements pass */
+         for (ip = installed->start; ip < installed->end; ip++)
+           {
+             if (!MAPTST(&installedm, ip))
+               continue;
+             if (MAPTST(&userinstalled, ip - installed->start))
+               continue;
+             s = pool->solvables + ip;
+             if (!s->supplements)
+               continue;
+             if (MAPTST(&im, ip))
+               continue;
+             supp = s->repo->idarraydata + s->supplements;
+             while ((sup = *supp++) != 0)
+               if (solver_dep_possible(solv, sup, &im))
+                 break;
+             if (sup)
+               {
+#ifdef CLEANDEPSDEBUG
+                 printf("%s supplemented\n", pool_solvid2str(pool, ip));
+#endif
+                 MAPSET(&im, ip);
+                 queue_push(&iq, ip);
+               }
+           }
+         if (!iq.count)
+           break;
+       }
+      ip = queue_shift(&iq);
+      s = pool->solvables + ip;
+#ifdef CLEANDEPSDEBUG
+      printf("adding back %s\n", pool_solvable2str(pool, s));
+#endif
+      if (s->repo == installed && pool->implicitobsoleteusescolors)
+       {
+         unsigned int a, bestscore = 0;
+         FOR_PROVIDES(p, pp, s->name)
+           {
+             Solvable *ps = pool->solvables + p;
+             if (ps->name != s->name || ps->repo == installed)
+               continue;
+             a = pool_arch2score(pool, ps->arch);
+             if (a && a != 1 && (!bestscore || a < bestscore))
+               bestscore = a;
+           }
+         if (bestscore && pool_arch2score(pool, s->arch) != bestscore)
+           {
+             FOR_PROVIDES(p, pp, s->name)
+               {
+                 Solvable *ps = pool->solvables + p;
+                 if (ps->repo == installed && ps->name == s->name && ps->evr == s->evr && ps->arch != s->arch && pool_arch2score(pool, ps->arch) == bestscore)
+                   if (!MAPTST(&im, p))
+                     {
+#ifdef CLEANDEPSDEBUG
+                       printf("%s lockstep %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+                       MAPSET(&im, p);
+                       queue_push(&iq, p);
+                     }
+               }
+           }
+       }
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, req))
+               {
+                 complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, req)
+               if (p == ip)
+                 break;
+             if (p)
+               continue;
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (MAPTST(&im, p))
+                   continue;
+                 if (MAPTST(&installedm, p))
+                   {
+                     if (p == ip)
+                       continue;
+                     if (MAPTST(&userinstalled, p - installed->start))
+                       continue;
+#ifdef CLEANDEPSDEBUG
+                     printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+                     MAPSET(&im, p);
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+      if (s->recommends)
+       {
+         reqp = s->repo->idarraydata + s->recommends;
+         while ((req = *reqp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, req))
+               {
+                 complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, req)
+               if (p == ip)
+                 break;
+             if (p)
+               continue;
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (MAPTST(&im, p))
+                   continue;
+                 if (MAPTST(&installedm, p))
+                   {
+                     if (p == ip)
+                       continue;
+                     if (MAPTST(&userinstalled, p - installed->start))
+                       continue;
+#ifdef CLEANDEPSDEBUG
+                     printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
+#endif
+                     MAPSET(&im, p);
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+    }
+
+  queue_free(&iq);
+  /* make sure the updatepkgs and mistakes are not in the cleandeps map */
+  if (!unneeded && solv->cleandeps_updatepkgs)
+    {
+      for (i = 0; i < updatepkgs_filtered.count; i++)
+        MAPSET(&im, updatepkgs_filtered.elements[i]);
+      queue_free(&updatepkgs_filtered);
+    }
+  if (solv->cleandeps_mistakes)
+    for (i = 0; i < solv->cleandeps_mistakes->count; i++)
+      MAPSET(&im, solv->cleandeps_mistakes->elements[i]);
+  /* also remove original iq packages */
+  for (i = 0; i < iqcopy.count; i++)
+    MAPSET(&im, iqcopy.elements[i]);
+  queue_free(&iqcopy);
+  for (p = installed->start; p < installed->end; p++)
+    {
+      if (pool->solvables[p].repo != installed)
+       continue;
+      if (pool->considered && !MAPTST(pool->considered, p))
+          continue;
+      if (!MAPTST(&im, p))
+        MAPSET(cleandepsmap, p - installed->start);
+    }
+  map_free(&im);
+  map_free(&installedm);
+  map_free(&userinstalled);
+  queue_free(&xsuppq);
+#ifdef CLEANDEPSDEBUG
+  printf("=== final cleandeps map:\n");
+  for (p = installed->start; p < installed->end; p++)
+    if (MAPTST(cleandepsmap, p - installed->start))
+      printf("  - %s\n", pool_solvid2str(pool, p));
+#endif
+}
+
+void
+solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered)
+{
+  Repo *installed = solv->installed;
+  int i;
+  Map cleandepsmap;
+
+  queue_empty(unneededq);
+  if (!installed || installed->end == installed->start)
+    return;
+
+  map_init(&cleandepsmap, installed->end - installed->start);
+  solver_createcleandepsmap(solv, &cleandepsmap, 1);
+  for (i = installed->start; i < installed->end; i++)
+    if (MAPTST(&cleandepsmap, i - installed->start))
+      queue_push(unneededq, i);
+
+  if (filtered)
+    filter_unneeded(solv, unneededq, &cleandepsmap, 0);
+  map_free(&cleandepsmap);
+}
+
+static void
+add_cleandeps_mistake(Solver *solv, Id p)
+{
+ if (!solv->cleandeps_mistakes)
+    {    
+      solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
+      queue_init(solv->cleandeps_mistakes);
+    }    
+  queue_push(solv->cleandeps_mistakes, p); 
+  MAPCLR(&solv->cleandepsmap, p - solv->installed->start);
+  solver_reenablepolicyrules_cleandeps(solv, p); 
+}
+
+static inline int
+cleandeps_rule_is_true(Solver *solv, Rule *r)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  FOR_RULELITERALS(p, pp, r)
+    if (p > 0 && solv->decisionmap[p] > 0)
+      return 1;
+  return 0;
+}
+
+int
+solver_check_cleandeps_mistakes(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Rule *fr;
+  int i, j, nj;
+  int mademistake = 0;
+
+  if (!solv->cleandepsmap.size || !installed)
+    return 0;
+  /* check for mistakes */
+  policy_update_recommendsmap(solv);
+  for (i = installed->start; i < installed->end; i++)
+    {
+      if (pool->solvables[i].repo != installed)
+       continue;
+      if (solv->decisionmap[i] > 0)
+       {
+         Id req, *reqp;
+         Solvable *s = pool->solvables + i;
+         /* kept package, check requires. we need to do this for things like requires(pre) */
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)  
+           {
+             Id p2, pp2;
+             FOR_PROVIDES(p2, pp2, req)
+               {
+                 if (pool->solvables[p2].repo != installed)
+                   continue;
+                 if (p2 == i || solv->decisionmap[p2] > 0)
+                   continue;
+                 if (!MAPTST(&solv->cleandepsmap, p2 - installed->start))
+                   continue;
+                 POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps requires mistake: %s %s %s\n", pool_solvid2str(pool, i), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
+                 add_cleandeps_mistake(solv, p2);
+                 mademistake = 1;
+               }
+           }
+       }
+      if (!MAPTST(&solv->cleandepsmap, i - installed->start))
+       continue;
+      /* a mistake is when the featurerule is true but the updaterule is false */
+      fr = solv->rules + solv->featurerules + (i - installed->start);
+      if (!fr->p)
+        fr = solv->rules + solv->updaterules + (i - installed->start);
+      if (!fr->p)
+       continue;
+      if (!cleandeps_rule_is_true(solv, fr))
+       {
+         /* feature rule is not true, thus we cleandeps erased the package */
+         /* check if the package is recommended/supplemented. if yes, we made a mistake. */
+         if (!MAPTST(&solv->recommendsmap, i) && !solver_is_supplementing(solv, pool->solvables + i))
+           continue;   /* feature rule is not true */
+         POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps recommends mistake: ");
+         solver_printruleclass(solv, SOLV_DEBUG_SOLVER, fr);
+       }
+      else
+       {
+         Rule *r = solv->rules + solv->updaterules + (i - installed->start);
+         if (!r->p || r == fr || cleandeps_rule_is_true(solv, r))
+           {
+             /* update rule is true, check best rules */
+             if (!solv->bestrules_pkg)
+               continue;
+             nj = solv->bestrules_end - solv->bestrules;
+             for (j = 0; j < nj; j++)
+               if (solv->bestrules_pkg[j] == i)
+                 {
+                   r = solv->rules + solv->bestrules + j;
+                   if (!cleandeps_rule_is_true(solv, r))
+                     break;
+                 }
+             if (j == nj)
+               continue;
+           }
+         POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
+         solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
+         POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
+         solver_printruleclass(solv, SOLV_DEBUG_SOLVER, fr);
+       }
+      add_cleandeps_mistake(solv, i);
+      mademistake = 1;
+    }
+  return mademistake;
+}
diff --git a/libsolv-0.7.2/src/cplxdeps.c b/libsolv-0.7.2/src/cplxdeps.c
new file mode 100644 (file)
index 0000000..6c40752
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2014, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * cplxdeps.c
+ *
+ * normalize complex dependencies into CNF/DNF form
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pool.h"
+#include "cplxdeps.h"
+
+#ifdef ENABLE_COMPLEX_DEPS
+
+#undef CPLXDEBUG
+
+int
+pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
+{
+  for (;;)
+    {
+      if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS)    /* those two are the complex ones */
+       return 1;
+      if (rd->flags != REL_OR)
+       return 0;
+      if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name)))
+       return 1;
+      if (!ISRELDEP(rd->evr))
+       return 0;
+      rd = GETRELDEP(pool, rd->evr);
+    }
+}
+
+/* expand simple dependencies into package lists */
+static int
+expand_simpledeps(Pool *pool, Queue *bq, int start, int split)
+{
+  int end = bq->count;
+  int i, x;
+  int newsplit = 0;
+  for (i = start; i < end; i++)
+    {
+      if (i == split)
+       newsplit = bq->count - (end - start);
+      x = bq->elements[i];
+      if (x == pool->nsolvables)
+       {
+         Id *dp = pool->whatprovidesdata + bq->elements[++i];
+         for (; *dp; dp++)
+           queue_push(bq, *dp);
+       }
+      else
+       queue_push(bq, x);
+    }
+  if (i == split)
+    newsplit = bq->count - (end - start);
+  queue_deleten(bq, start, end - start);
+  return newsplit;
+}
+
+#ifdef CPLXDEBUG
+static void
+print_depblocks(Pool *pool, Queue *bq, int start)
+{
+  int i;
+
+  for (i = start; i < bq->count; i++)
+    {
+      if (bq->elements[i] == pool->nsolvables)
+       {
+         Id *dp = pool->whatprovidesdata + bq->elements[++i];
+         printf(" (");
+         while (*dp)
+           printf(" %s", pool_solvid2str(pool, *dp++));
+         printf(" )");
+       }
+      else if (bq->elements[i] > 0)
+       printf(" %s", pool_solvid2str(pool, bq->elements[i]));
+      else if (bq->elements[i] < 0)
+       printf(" -%s", pool_solvid2str(pool, -bq->elements[i]));
+      else
+       printf(" ||");
+    }
+  printf("\n");
+}
+#endif
+
+/* invert all literals in the blocks. note that this also turns DNF into CNF and vice versa */
+static int
+invert_depblocks(Pool *pool, Queue *bq, int start, int r)
+{
+  int i, j, end;
+  if (r == 0 || r == 1)
+    return r ? 0 : 1;
+  expand_simpledeps(pool, bq, start, 0);
+  end = bq->count;
+  for (i = j = start; i < end; i++)
+    {
+      if (bq->elements[i])
+       {
+          bq->elements[i] = -bq->elements[i];
+         continue;
+       }
+      /* end of block reached, reverse */
+      if (i - 1 > j)
+       {
+         int k;
+         for (k = i - 1; j < k; j++, k--)
+           {
+             Id t = bq->elements[j];
+             bq->elements[j] = bq->elements[k];
+             bq->elements[k] = t;
+           }
+       }
+      j = i + 1;
+    }
+  return -1;
+}
+
+/* distributive property: (a1*a2 + b1*b2) * (c1*c2 + d1*d2) = 
+   a1*a2*c1*c2 + a1*a2*d1*d2 + b1*b2*c1*c2 + b1*b2*d1*d2 */
+static int
+distribute_depblocks(Pool *pool, Queue *bq, int bqcnt, int bqcnt2, int flags)
+{
+  int i, j, bqcnt3;
+#ifdef CPLXDEBUG
+  printf("COMPLEX DISTRIBUTE %d %d %d\n", bqcnt, bqcnt2, bq->count);
+#endif
+  bqcnt2 = expand_simpledeps(pool, bq, bqcnt, bqcnt2);
+  bqcnt3 = bq->count;
+  for (i = bqcnt; i < bqcnt2; i++)
+    {
+      for (j = bqcnt2; j < bqcnt3; j++)
+       {
+         int a, b;
+         int bqcnt4 = bq->count;
+         int k = i;
+
+         /* mix i block with j block, both blocks are sorted */
+         while (bq->elements[k] && bq->elements[j])
+           {
+             if (bq->elements[k] < bq->elements[j])
+               queue_push(bq, bq->elements[k++]);
+             else
+               {
+                 if (bq->elements[k] == bq->elements[j])
+                   k++;
+                 queue_push(bq, bq->elements[j++]);
+               }
+           }
+         while (bq->elements[j])
+           queue_push(bq, bq->elements[j++]);
+         while (bq->elements[k])
+           queue_push(bq, bq->elements[k++]);
+
+         /* block is finished, check for A + -A */
+         for (a = bqcnt4, b = bq->count - 1; a < b; )
+           {
+             if (-bq->elements[a] == bq->elements[b])
+               break;
+             if (-bq->elements[a] > bq->elements[b])
+               a++;
+             else
+               b--;
+           }
+         if (a < b)
+           queue_truncate(bq, bqcnt4); /* ignore this block */
+         else
+           queue_push(bq, 0);  /* finish block */
+       }
+      /* advance to next block */
+      while (bq->elements[i])
+       i++;
+    }
+  queue_deleten(bq, bqcnt, bqcnt3 - bqcnt);
+  if (bqcnt == bq->count)
+    return flags & CPLXDEPS_TODNF ? 0 : 1;
+  return -1;
+}
+
+static int normalize_dep(Pool *pool, Id dep, Queue *bq, int flags);
+
+static int
+normalize_dep_or(Pool *pool, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep(pool, dep1, bq, flags);
+  if (r1 == 1)
+    return 1;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep(pool, dep2, bq, flags ^ invflags);
+  if (invflags)
+    r2 = invert_depblocks(pool, bq, bqcnt2, r2);
+  if (r1 == 1 || r2 == 1)
+    {
+      queue_truncate(bq, bqcnt);
+      return 1;
+    }
+  if (r1 == 0)
+    return r2;
+  if (r2 == 0)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) == 0)
+    return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int
+normalize_dep_and(Pool *pool, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
+{
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep(pool, dep1, bq, flags);
+  if (r1 == 0)
+    return 0;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep(pool, dep2, bq, flags ^ invflags);
+  if (invflags)
+    r2 = invert_depblocks(pool, bq, bqcnt2, r2); 
+  if (r1 == 0 || r2 == 0)
+    {    
+      queue_truncate(bq, bqcnt);
+      return 0;
+    }    
+  if (r1 == 1)
+    return r2;
+  if (r2 == 1)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) != 0)
+    return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int
+normalize_dep_if_else(Pool *pool, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+  /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep_or(pool, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+  if (r1 == 0)
+    return 0;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep_or(pool, dep2, dep3, bq, flags, 0);
+  if (r1 == 0 || r2 == 0)
+    {
+      queue_truncate(bq, bqcnt);
+      return 0;
+    }
+  if (r1 == 1)
+    return r2;
+  if (r2 == 1)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) != 0)
+    return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+static int
+normalize_dep_unless_else(Pool *pool, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
+{
+  /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */
+  int r1, r2, bqcnt2, bqcnt = bq->count;
+  r1 = normalize_dep_and(pool, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
+  if (r1 == 1)
+    return 1;          /* early exit */
+  bqcnt2 = bq->count;
+  r2 = normalize_dep_and(pool, dep2, dep3, bq, flags, 0);
+  if (r1 == 1 || r2 == 1)
+    {
+      queue_truncate(bq, bqcnt);
+      return 1;
+    }
+  if (r1 == 0)
+    return r2;
+  if (r2 == 0)
+    return r1;
+  if ((flags & CPLXDEPS_TODNF) == 0)
+    return distribute_depblocks(pool, bq, bqcnt, bqcnt2, flags);
+  return -1;
+}
+
+/*
+ * returns:
+ *   0: no blocks
+ *   1: matches all
+ *  -1: at least one block
+ */
+static int
+normalize_dep(Pool *pool, Id dep, Queue *bq, int flags)
+{
+  Id p, dp;
+  int bqcnt;
+
+  if (pool_is_complex_dep(pool, dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND)
+       {
+         Id evr = rd->evr;
+         if (ISRELDEP(evr))
+           {
+             Reldep *rd2 = GETRELDEP(pool, evr);
+             if (rd2->flags == REL_ELSE)
+               return normalize_dep_if_else(pool, rd->name, rd2->name, rd2->evr, bq, flags);
+           }
+         return normalize_dep_or(pool, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+       }
+      if (rd->flags == REL_UNLESS)
+       {
+         Id evr = rd->evr;
+         if (ISRELDEP(evr))
+           {
+             Reldep *rd2 = GETRELDEP(pool, evr);
+             if (rd2->flags == REL_ELSE)
+               return normalize_dep_unless_else(pool, rd->name, rd2->name, rd2->evr, bq, flags);
+           }
+         return normalize_dep_and(pool, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
+       }
+      if (rd->flags == REL_OR)
+       return normalize_dep_or(pool, rd->name, rd->evr, bq, flags, 0);
+      if (rd->flags == REL_AND)
+       return normalize_dep_and(pool, rd->name, rd->evr, bq, flags, 0);
+    }
+
+  /* fallback case: just use package list */
+  dp = pool_whatprovides(pool, dep);
+  if (dp <= 2 || !pool->whatprovidesdata[dp])
+    return dp == 2 ? 1 : 0;
+  if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
+    return 1;
+  bqcnt = bq->count;
+  if ((flags & CPLXDEPS_NAME) != 0)
+    {
+      while ((p = pool->whatprovidesdata[dp++]) != 0)
+       {
+         if (!pool_match_nevr(pool, pool->solvables + p, dep))
+           continue;
+         queue_push(bq, p);
+         if ((flags & CPLXDEPS_TODNF) != 0)
+           queue_push(bq, 0);
+       }
+    }
+  else if ((flags & CPLXDEPS_TODNF) != 0)
+    {
+      while ((p = pool->whatprovidesdata[dp++]) != 0)
+        queue_push2(bq, p, 0);
+    }
+  else
+    queue_push2(bq, pool->nsolvables, dp);     /* not yet expanded marker + offset */
+  if (bq->count == bqcnt)
+    return 0;  /* no provider */
+  if (!(flags & CPLXDEPS_TODNF))
+    queue_push(bq, 0); /* finish block */
+  return -1;
+}
+
+int
+pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags)
+{
+  int i, bqcnt = bq->count;
+
+  i = normalize_dep(pool, dep, bq, flags);
+  if ((flags & CPLXDEPS_EXPAND) != 0)
+    {
+      if (i != 0 && i != 1)
+        expand_simpledeps(pool, bq, bqcnt, 0);
+    }
+  if ((flags & CPLXDEPS_INVERT) != 0)
+    i = invert_depblocks(pool, bq, bqcnt, i);
+#ifdef CPLXDEBUG
+  if (i == 0)
+    printf("NONE\n");
+  else if (i == 1)
+    printf("ALL\n");
+  else
+    print_depblocks(pool, bq, bqcnt);
+#endif
+  return i;
+}
+
+void
+pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg)
+{
+  while (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags != REL_AND && rd->flags != REL_OR && rd->flags != REL_COND && rd->flags != REL_UNLESS)
+       break;
+      pool_add_pos_literals_complex_dep(pool, rd->name, q, m, neg);
+      dep = rd->evr;
+      if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
+       {
+         neg = !neg;
+         if (ISRELDEP(dep))
+           {
+             Reldep *rd2 = GETRELDEP(pool, rd->evr);
+             if (rd2->flags == REL_ELSE)
+               {
+                 pool_add_pos_literals_complex_dep(pool, rd2->evr, q, m, !neg);
+                 dep = rd2->name;
+               }
+           }
+       }
+    }
+  if (!neg)
+    {
+      Id p, pp;
+      FOR_PROVIDES(p, pp, dep)
+       if (!MAPTST(m, p))
+         queue_push(q, p);
+    }
+}
+
+#endif /* ENABLE_COMPLEX_DEPS */
+
diff --git a/libsolv-0.7.2/src/cplxdeps.h b/libsolv-0.7.2/src/cplxdeps.h
new file mode 100644 (file)
index 0000000..7c5946a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * cplxdeps.h (internal)
+ */
+
+#ifndef LIBSOLV_CPLXDEPS_H
+#define LIBSOLV_CPLXDEPS_H
+
+extern int pool_is_complex_dep_rd(Pool *pool, Reldep *rd);
+
+static inline int 
+pool_is_complex_dep(Pool *pool, Id dep)
+{
+  if (ISRELDEP(dep))
+    {   
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags >= 8 && pool_is_complex_dep_rd(pool, rd))
+        return 1;
+    }   
+  return 0;
+}
+
+extern int pool_normalize_complex_dep(Pool *pool, Id dep, Queue *bq, int flags);
+extern void pool_add_pos_literals_complex_dep(Pool *pool, Id dep, Queue *q, Map *m, int neg);
+
+#define CPLXDEPS_TODNF   (1 << 0)
+#define CPLXDEPS_EXPAND  (1 << 1)
+#define CPLXDEPS_INVERT  (1 << 2)
+#define CPLXDEPS_NAME    (1 << 3)
+#define CPLXDEPS_DONTFIX (1 << 4)
+
+#endif
+
diff --git a/libsolv-0.7.2/src/dataiterator.h b/libsolv-0.7.2/src/dataiterator.h
new file mode 100644 (file)
index 0000000..0649258
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2007-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * dataiterator.h
+ *
+ */
+
+#ifndef LIBSOLV_DATAITERATOR_H
+#define LIBSOLV_DATAITERATOR_H
+
+#include "pooltypes.h"
+#include "pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct s_Repo;
+
+typedef struct s_KeyValue {
+  Id id;
+  const char *str;
+  unsigned int num;
+  unsigned int num2;
+
+  int entry;   /* array entry, starts with 0 */
+  int eof;     /* last entry reached */
+
+  struct s_KeyValue *parent;
+} KeyValue;
+
+#define SOLV_KV_NUM64(kv) (((unsigned long long)((kv)->num2)) << 32 | (kv)->num)
+
+/* search matcher flags */
+#define SEARCH_STRINGMASK              15
+#define SEARCH_STRING                  1
+#define SEARCH_STRINGSTART             2
+#define SEARCH_STRINGEND               3
+#define SEARCH_SUBSTRING               4
+#define SEARCH_GLOB                    5
+#define SEARCH_REGEX                   6
+#define SEARCH_ERROR                   15
+#define        SEARCH_NOCASE                   (1<<7)
+
+/* iterator control */
+#define        SEARCH_NO_STORAGE_SOLVABLE      (1<<8)
+#define SEARCH_SUB                     (1<<9)
+#define SEARCH_ARRAYSENTINEL           (1<<10)
+#define SEARCH_DISABLED_REPOS          (1<<11)
+#define SEARCH_KEEP_TYPE_DELETED       (1<<12)         /* only has effect if no keyname is given */
+
+/* stringification flags */
+#define SEARCH_SKIP_KIND               (1<<16)
+/* By default we stringify just to the basename of a file because
+   the construction of the full filename is costly.  Specify this
+   flag if you want to match full filenames */
+#define SEARCH_FILES                   (1<<17)
+#define SEARCH_CHECKSUMS               (1<<18)
+
+/* internal */
+#define SEARCH_SUBSCHEMA               (1<<30)
+#define SEARCH_THISSOLVID              (1<<31)
+
+/* obsolete */
+#define SEARCH_COMPLETE_FILELIST       0               /* ignored, this is the default */
+
+/*
+ * Datamatcher: match a string against a query
+ */
+typedef struct s_Datamatcher {
+  int flags;           /* see matcher flags above */
+  const char *match;   /* the query string */
+  void *matchdata;     /* e.g. compiled regexp */
+  int error;
+} Datamatcher;
+
+int  datamatcher_init(Datamatcher *ma, const char *match, int flags);
+void datamatcher_free(Datamatcher *ma);
+int  datamatcher_match(Datamatcher *ma, const char *str);
+int  datamatcher_checkbasename(Datamatcher *ma, const char *str);
+
+
+/*
+ * Dataiterator
+ *
+ * Iterator like interface to 'search' functionality
+ *
+ * Dataiterator is per-pool, additional filters can be applied
+ * to limit the search domain. See dataiterator_init below.
+ *
+ * Use these like:
+ *    Dataiterator di;
+ *    dataiterator_init(&di, repo->pool, repo, 0, 0, "bla", SEARCH_SUBSTRING);
+ *    while (dataiterator_step(&di))
+ *      dosomething(di.solvid, di.key, di.kv);
+ *    dataiterator_free(&di);
+ */
+typedef struct s_Dataiterator
+{
+  int state;
+  int flags;
+
+  Pool *pool;
+  struct s_Repo *repo;
+  struct s_Repodata *data;
+
+  /* data pointers */
+  unsigned char *dp;
+  unsigned char *ddp;
+  Id *idp;
+  Id *keyp;
+
+  /* the result */
+  struct s_Repokey *key;
+  KeyValue kv;
+
+  /* our matcher */
+  Datamatcher matcher;
+
+  /* iterators/filters */
+  Id keyname;
+  Id repodataid;
+  Id solvid;
+  Id repoid;
+
+  Id keynames[3 + 1];
+  int nkeynames;
+  int rootlevel;
+
+  /* recursion data */
+  struct di_parent {
+    KeyValue kv;
+    unsigned char *dp;
+    Id *keyp;
+  } parents[3];
+  int nparents;
+
+  /* vertical data */
+  unsigned char *vert_ddp;
+  Id vert_off;
+  Id vert_len;
+  Id vert_storestate;
+
+  /* strdup data */
+  char *dupstr;
+  int dupstrn;
+
+  Id *keyskip;
+  Id *oldkeyskip;
+} Dataiterator;
+
+
+/*
+ * Initialize dataiterator
+ *
+ * di:      Pointer to Dataiterator to be initialized
+ * pool:    Search domain for the iterator
+ * repo:    if non-null, limit search to this repo
+ * solvid:  if non-null, limit search to this solvable
+ * keyname: if non-null, limit search to this keyname
+ * match:   if non-null, limit search to this match
+ */
+int  dataiterator_init(Dataiterator *di, Pool *pool, struct s_Repo *repo, Id p, Id keyname, const char *match, int flags);
+void dataiterator_init_clone(Dataiterator *di, Dataiterator *from);
+void dataiterator_set_search(Dataiterator *di, struct s_Repo *repo, Id p);
+void dataiterator_set_keyname(Dataiterator *di, Id keyname);
+int  dataiterator_set_match(Dataiterator *di, const char *match, int flags);
+
+void dataiterator_prepend_keyname(Dataiterator *di, Id keyname);
+void dataiterator_free(Dataiterator *di);
+int  dataiterator_step(Dataiterator *di);
+void dataiterator_setpos(Dataiterator *di);
+void dataiterator_setpos_parent(Dataiterator *di);
+int  dataiterator_match(Dataiterator *di, Datamatcher *ma);
+void dataiterator_skip_attribute(Dataiterator *di);
+void dataiterator_skip_solvable(Dataiterator *di);
+void dataiterator_skip_repo(Dataiterator *di);
+void dataiterator_jump_to_solvid(Dataiterator *di, Id solvid);
+void dataiterator_jump_to_repo(Dataiterator *di, struct s_Repo *repo);
+void dataiterator_entersub(Dataiterator *di);
+void dataiterator_clonepos(Dataiterator *di, Dataiterator *from);
+void dataiterator_seek(Dataiterator *di, int whence);
+void dataiterator_strdup(Dataiterator *di);
+
+#define DI_SEEK_STAY    (1 << 16)
+#define DI_SEEK_CHILD   1
+#define DI_SEEK_PARENT  2
+#define DI_SEEK_REWIND  3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_DATAITERATOR_H */
diff --git a/libsolv-0.7.2/src/dirpool.c b/libsolv-0.7.2/src/dirpool.c
new file mode 100644 (file)
index 0000000..afb26ea
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pool.h"
+#include "util.h"
+#include "dirpool.h"
+
+#define DIR_BLOCK 127
+
+/* directories are stored as components,
+ * components are simple ids from the string pool
+ *   /usr/bin   ->  "", "usr", "bin"
+ *   /usr/lib   ->  "", "usr", "lib"
+ *   foo/bar    ->  "foo", "bar"
+ *   /usr/games ->  "", "usr", "games"
+ *
+ * all directories are stores in the "dirs" array
+ *   dirs[id] > 0 : component string pool id
+ *   dirs[id] <= 0 : -(parent directory id)
+ *
+ * Directories with the same parent are stored as
+ * multiple blocks. We need multiple blocks because
+ * we cannot insert entries into old blocks, as that
+ * would shift the ids of already used directories.
+ * Each block starts with (-parent_dirid) and contains
+ * component ids of the directory entries.
+ * (The (-parent_dirid) entry is not a valid directory
+ * id, it's just used internally)
+ *
+ * There is also the aux "dirtraverse" array, which
+ * is created on demand to speed things up a bit.
+ * if dirs[id] > 0, dirtravers[id] points to the first
+ * entry in the last block with parent id.
+ * if dirs[id] <= 0, dirtravers[id] points to the entry
+ * in the previous block with the same parent.
+ * (Thus it acts as a linked list that starts at the
+ * parent dirid and chains all the blocks with that
+ * parent.)
+ *
+ *  id    dirs[id]  dirtraverse[id]
+ *   0     0           8       [no parent, block#0]
+ *   1    ""           3
+ *   2    -1                   [parent 1, /, block #0]
+ *   3    "usr"       12
+ *   4    -3                   [parent 3, /usr, block #0]
+ *   5    "bin"
+ *   6    "lib"
+ *   7     0           1       [no parent, block#1]
+ *   8    "foo"       10
+ *   9    -8                   [parent 8, foo, block #0]
+ *  10    "bar"
+ *  11    -3           5       [parent 3, /usr, block #1]
+ *  12    "games"
+ *
+ * to find all children of dirid 3 ("/usr"), follow the
+ * dirtraverse link to 12 -> "games". Then follow the
+ * dirtraverse link of this block to 5 -> "bin", "lib"
+ */
+
+void
+dirpool_init(Dirpool *dp)
+{
+  memset(dp, 0, sizeof(*dp));
+}
+
+void
+dirpool_free(Dirpool *dp)
+{
+  solv_free(dp->dirs);
+  solv_free(dp->dirtraverse);
+}
+
+void
+dirpool_make_dirtraverse(Dirpool *dp)
+{
+  Id parent, i, *dirtraverse;
+  if (!dp->ndirs)
+    return;
+  dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
+  dirtraverse = solv_calloc_block(dp->ndirs, sizeof(Id), DIR_BLOCK);
+  for (parent = 0, i = 0; i < dp->ndirs; i++)
+    {
+      if (dp->dirs[i] > 0)
+       continue;
+      parent = -dp->dirs[i];
+      dirtraverse[i] = dirtraverse[parent];
+      dirtraverse[parent] = i + 1;
+    }
+  dp->dirtraverse = dirtraverse;
+}
+
+Id
+dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create)
+{
+  Id did, d, ds;
+
+  if (!dp->ndirs)
+    {
+      if (!create)
+       return 0;
+      dp->ndirs = 2;
+      dp->dirs = solv_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
+      dp->dirs[0] = 0;
+      dp->dirs[1] = 1; /* "" */
+    }
+  if (comp <= 0)
+    return 0;
+  if (parent == 0 && comp == 1)
+    return 1;
+  if (!dp->dirtraverse)
+    dirpool_make_dirtraverse(dp);
+  /* check all entries with this parent if we
+   * already have this component */
+  ds = dp->dirtraverse[parent];
+  while (ds)
+    {
+      /* ds: first component in this block
+       * ds-1: parent link */
+      for (d = ds--; d < dp->ndirs; d++)
+       {
+         if (dp->dirs[d] == comp)
+           return d;
+         if (dp->dirs[d] <= 0) /* reached end of this block */
+           break;
+       }
+      if (ds)
+        ds = dp->dirtraverse[ds];
+    }
+  if (!create)
+    return 0;
+  /* a new one, find last parent */
+  for (did = dp->ndirs - 1; did > 0; did--)
+    if (dp->dirs[did] <= 0)
+      break;
+  if (dp->dirs[did] != -parent)
+    {
+      /* make room for parent entry */
+      dp->dirs = solv_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
+      dp->dirtraverse = solv_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
+      /* new parent block, link in */
+      dp->dirs[dp->ndirs] = -parent;
+      dp->dirtraverse[dp->ndirs] = dp->dirtraverse[parent];
+      dp->dirtraverse[parent] = ++dp->ndirs;
+    }
+  /* make room for new entry */
+  dp->dirs = solv_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
+  dp->dirtraverse = solv_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
+  dp->dirs[dp->ndirs] = comp;
+  dp->dirtraverse[dp->ndirs] = 0;
+  return dp->ndirs++;
+}
diff --git a/libsolv-0.7.2/src/dirpool.h b/libsolv-0.7.2/src/dirpool.h
new file mode 100644 (file)
index 0000000..ca92954
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+#ifndef LIBSOLV_DIRPOOL_H
+#define LIBSOLV_DIRPOOL_H
+
+
+#include "pooltypes.h"
+#include "util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct s_Dirpool {
+  Id *dirs;
+  int ndirs;
+  Id *dirtraverse;
+} Dirpool;
+
+void dirpool_init(Dirpool *dp);
+void dirpool_free(Dirpool *dp);
+
+void dirpool_make_dirtraverse(Dirpool *dp);
+Id dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create);
+
+/* return the parent directory of child did */
+static inline Id dirpool_parent(Dirpool *dp, Id did)
+{
+  if (!did)
+    return 0;
+  while (dp->dirs[--did] > 0)
+    ;
+  return -dp->dirs[did];
+}
+
+/* return the next child entry of child did */
+static inline Id
+dirpool_sibling(Dirpool *dp, Id did)
+{
+  /* if this block contains another entry, simply return it */
+  if (did + 1 < dp->ndirs && dp->dirs[did + 1] > 0)
+    return did + 1;
+  /* end of block reached, rewind to get to the block's
+   * dirtraverse entry */
+  while (dp->dirs[--did] > 0)
+    ;
+  /* need to special case did == 0 to prevent looping */
+  if (!did)
+    return 0;
+  if (!dp->dirtraverse)
+    dirpool_make_dirtraverse(dp);
+  return dp->dirtraverse[did];
+}
+
+/* return the first child entry of directory did */
+static inline Id
+dirpool_child(Dirpool *dp, Id did)
+{
+  if (!dp->dirtraverse)
+    dirpool_make_dirtraverse(dp);
+  return dp->dirtraverse[did];
+}
+
+static inline void
+dirpool_free_dirtraverse(Dirpool *dp)
+{
+  solv_free(dp->dirtraverse);
+  dp->dirtraverse = 0;
+}
+
+static inline Id
+dirpool_compid(Dirpool *dp, Id did)
+{
+  return dp->dirs[did];
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_DIRPOOL_H */
diff --git a/libsolv-0.7.2/src/diskusage.c b/libsolv-0.7.2/src/diskusage.c
new file mode 100644 (file)
index 0000000..63c43bf
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2007-2016, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * diskusage.c
+ *
+ * calculate needed space on partitions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pool.h"
+#include "poolarch.h"
+#include "repo.h"
+#include "util.h"
+#include "bitmap.h"
+
+
+struct mptree {
+  Id sibling;
+  Id child;
+  const char *comp;
+  int compl;
+  Id mountpoint;
+};
+
+struct ducbdata {
+  DUChanges *mps;
+  struct mptree *mptree;
+  int addsub;
+  int hasdu;
+
+  Id *dirmap;
+  int nmap;
+  Repodata *olddata;
+};
+
+
+static int
+solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
+{
+  struct ducbdata *cbd = cbdata;
+  Id mp;
+
+  if (data != cbd->olddata)
+    {
+      Id dn, mp, comp, *dirmap, *dirs;
+      int i, compl;
+      const char *compstr;
+      struct mptree *mptree;
+
+      /* create map from dir to mptree */
+      cbd->dirmap = solv_free(cbd->dirmap);
+      cbd->nmap = 0;
+      dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id));
+      mptree = cbd->mptree;
+      mp = 0;
+      for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
+       {
+         comp = *dirs++;
+         if (comp <= 0)
+           {
+             mp = dirmap[-comp];
+             continue;
+           }
+         if (mp < 0)
+           {
+             /* unconnected */
+             dirmap[dn] = mp;
+             continue;
+           }
+         if (!mptree[mp].child)
+           {
+             dirmap[dn] = -mp;
+             continue;
+           }
+         if (data->localpool)
+           compstr = stringpool_id2str(&data->spool, comp);
+         else
+           compstr = pool_id2str(data->repo->pool, comp);
+         compl = strlen(compstr);
+         for (i = mptree[mp].child; i; i = mptree[i].sibling)
+           if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
+             break;
+         dirmap[dn] = i ? i : -mp;
+       }
+      /* change dirmap to point to mountpoint instead of mptree */
+      for (dn = 0; dn < data->dirpool.ndirs; dn++)
+       {
+         mp = dirmap[dn];
+         dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
+       }
+      cbd->dirmap = dirmap;
+      cbd->nmap = data->dirpool.ndirs;
+      cbd->olddata = data;
+    }
+  cbd->hasdu = 1;
+  if (value->id < 0 || value->id >= cbd->nmap)
+    return 0;
+  mp = cbd->dirmap[value->id];
+  if (mp < 0)
+    return 0;
+  if (cbd->addsub > 0)
+    {
+      cbd->mps[mp].kbytes += value->num;
+      cbd->mps[mp].files += value->num2;
+    }
+  else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD))
+    {
+      cbd->mps[mp].kbytes -= value->num;
+      cbd->mps[mp].files -= value->num2;
+    }
+  return 0;
+}
+
+static void
+propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
+{
+  int i;
+  if (mptree[pos].mountpoint == -1)
+    mptree[pos].mountpoint = mountpoint;
+  else
+    mountpoint = mptree[pos].mountpoint;
+  for (i = mptree[pos].child; i; i = mptree[i].sibling)
+    propagate_mountpoints(mptree, i, mountpoint);
+}
+
+#define MPTREE_BLOCK 15
+
+static struct mptree *
+create_mptree(DUChanges *mps, int nmps)
+{
+  int i, nmptree;
+  struct mptree *mptree;
+  int pos, compl;
+  int mp;
+  const char *p, *path, *compstr;
+
+  mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
+
+  /* our root node */
+  mptree[0].sibling = 0;
+  mptree[0].child = 0;
+  mptree[0].comp = 0;
+  mptree[0].compl = 0;
+  mptree[0].mountpoint = -1;
+  nmptree = 1;
+
+  /* create component tree */
+  for (mp = 0; mp < nmps; mp++)
+    {
+      mps[mp].kbytes = 0;
+      mps[mp].files = 0;
+      pos = 0;
+      path = mps[mp].path;
+      while(*path == '/')
+       path++;
+      while (*path)
+       {
+         if ((p = strchr(path, '/')) == 0)
+           {
+             compstr = path;
+             compl = strlen(compstr);
+             path += compl;
+           }
+         else
+           {
+             compstr = path;
+             compl = p - path;
+             path = p + 1;
+             while(*path == '/')
+               path++;
+           }
+          for (i = mptree[pos].child; i; i = mptree[i].sibling)
+           if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
+             break;
+         if (!i)
+           {
+             /* create new node */
+             mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
+             i = nmptree++;
+             mptree[i].sibling = mptree[pos].child;
+             mptree[i].child = 0;
+             mptree[i].comp = compstr;
+             mptree[i].compl = compl;
+             mptree[i].mountpoint = -1;
+             mptree[pos].child = i;
+           }
+         pos = i;
+       }
+      mptree[pos].mountpoint = mp;
+    }
+
+  propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
+
+#if 0
+  for (i = 0; i < nmptree; i++)
+    {
+      printf("#%d sibling: %d\n", i, mptree[i].sibling);
+      printf("#%d child: %d\n", i, mptree[i].child);
+      printf("#%d comp: %s\n", i, mptree[i].comp);
+      printf("#%d compl: %d\n", i, mptree[i].compl);
+      printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
+    }
+#endif
+
+  return mptree;
+}
+
+void
+pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
+{
+  struct mptree *mptree;
+  struct ducbdata cbd;
+  Solvable *s;
+  int i, sp;
+  Map ignoredu;
+  Repo *oldinstalled = pool->installed;
+  int haveonlyadd = 0;
+
+  map_init(&ignoredu, 0);
+  mptree = create_mptree(mps, nmps);
+
+  for (i = 0; i < nmps; i++)
+    if ((mps[i].flags & DUCHANGES_ONLYADD) != 0)
+      haveonlyadd = 1;
+  cbd.mps = mps;
+  cbd.dirmap = 0;
+  cbd.nmap = 0;
+  cbd.olddata = 0;
+  cbd.mptree = mptree;
+  cbd.addsub = 1;
+  for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
+    {
+      if (!s->repo || (oldinstalled && s->repo == oldinstalled))
+       continue;
+      if (!MAPTST(installedmap, sp))
+       continue;
+      cbd.hasdu = 0;
+      repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+      if (!cbd.hasdu && oldinstalled)
+       {
+         Id op, opp;
+         int didonlyadd = 0;
+         /* no du data available, ignore data of all installed solvables we obsolete */
+         if (!ignoredu.size)
+           map_grow(&ignoredu, oldinstalled->end - oldinstalled->start);
+         FOR_PROVIDES(op, opp, s->name)
+           {
+             Solvable *s2 = pool->solvables + op;
+             if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
+               continue;
+             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
+               continue;
+             if (op >= oldinstalled->start && op < oldinstalled->end)
+               {
+                 MAPSET(&ignoredu, op - oldinstalled->start);
+                 if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
+                   {
+                     repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                     cbd.addsub = -1;
+                     repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                     cbd.addsub = 1;
+                     didonlyadd = 1;
+                   }
+               }
+           }
+         if (s->obsoletes)
+           {
+             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+             while ((obs = *obsp++) != 0)
+               FOR_PROVIDES(op, opp, obs)
+                 {
+                   Solvable *s2 = pool->solvables + op;
+                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
+                     continue;
+                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+                     continue;
+                   if (op >= oldinstalled->start && op < oldinstalled->end)
+                     {
+                       MAPSET(&ignoredu, op - oldinstalled->start);
+                       if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
+                         {
+                           repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                           cbd.addsub = -1;
+                           repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+                           cbd.addsub = 1;
+                           didonlyadd = 1;
+                         }
+                     }
+                 }
+           }
+       }
+    }
+  cbd.addsub = -1;
+  if (oldinstalled)
+    {
+      /* assumes we allways have du data for installed solvables */
+      FOR_REPO_SOLVABLES(oldinstalled, sp, s)
+       {
+         if (MAPTST(installedmap, sp))
+           continue;
+         if (ignoredu.size && MAPTST(&ignoredu, sp - oldinstalled->start))
+           continue;
+         repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
+       }
+    }
+  map_free(&ignoredu);
+  solv_free(cbd.dirmap);
+  solv_free(mptree);
+}
+
+long long
+pool_calc_installsizechange(Pool *pool, Map *installedmap)
+{
+  Id sp;
+  Solvable *s;
+  long long change = 0; 
+  Repo *oldinstalled = pool->installed;
+
+  for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) 
+    {    
+      if (!s->repo || (oldinstalled && s->repo == oldinstalled))
+        continue;
+      if (!MAPTST(installedmap, sp)) 
+        continue;
+      change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
+    }    
+  if (oldinstalled)
+    {    
+      FOR_REPO_SOLVABLES(oldinstalled, sp, s)
+        {
+          if (MAPTST(installedmap, sp)) 
+            continue;
+          change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
+        }
+    }    
+  return change;
+}
+
diff --git a/libsolv-0.7.2/src/evr.c b/libsolv-0.7.2/src/evr.c
new file mode 100644 (file)
index 0000000..c63878e
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * evr.c
+ *
+ * version compare
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "evr.h"
+#include "pool.h"
+
+
+
+#if defined(DEBIAN) || defined(MULTI_SEMANTICS)
+
+/* debian type version compare */
+int
+solv_vercmp_deb(const char *s1, const char *q1, const char *s2, const char *q2)
+{
+  int r, c1, c2;
+  while (1)
+    {
+      c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
+      c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
+      if ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
+       {
+         while (c1 == '0')
+            c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
+         while (c2 == '0')
+            c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
+         r = 0;
+         while ((c1 >= '0' && c1 <= '9') && (c2 >= '0' && c2 <= '9'))
+           {
+             if (!r)
+               r = c1 - c2;
+              c1 = s1 < q1 ? *(const unsigned char *)s1++ : 0;
+              c2 = s2 < q2 ? *(const unsigned char *)s2++ : 0;
+           }
+         if (c1 >= '0' && c1 <= '9')
+           return 1;
+         if (c2 >= '0' && c2 <= '9')
+           return -1;
+         if (r)
+           return r < 0 ? -1 : 1;
+       }
+      c1 = c1 == '~' ? -1 : !c1 || (c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z')  ? c1 : c1 + 256;
+      c2 = c2 == '~' ? -1 : !c2 || (c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z')  ? c2 : c2 + 256;
+      r = c1 - c2;
+      if (r)
+       return r < 0 ? -1 : 1;
+      if (!c1)
+       return 0;
+    }
+}
+
+#endif
+
+#if !defined(DEBIAN) || defined(MULTI_SEMANTICS)
+
+/* rpm type version compare */
+/* note: the code assumes that *q1 and *q2 are not alphanumeric! */
+
+int
+solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
+{
+  int r = 0;
+  const char *e1, *e2;
+
+  for (;;)
+    {
+      while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
+          !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~' && *s1 != '^')
+       s1++;
+      while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
+          !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~' && *s2 != '^')
+       s2++;
+      if (s1 < q1 && *s1 == '~')
+        {
+         if (s2 < q2 && *s2 == '~')
+           {
+             s1++;
+             s2++;
+             continue;
+           }
+         return -1;
+        }
+      if (s2 < q2 && *s2 == '~')
+       return 1;
+      if (s1 < q1 && *s1 == '^')
+       {
+         if (s2 < q2 && *s2 == '^')
+           {
+             s1++;
+             s2++;
+             continue;
+           }
+         return s2 < q2 ? -1 : 1;
+       }
+      if (s2 < q2 && *s2 == '^')
+       return s1 < q1 ? 1 : -1;
+      if (s1 >= q1 || s2 >= q2)
+       break;
+      if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
+       {
+         while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
+           s1++;
+         while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
+           s2++;
+         for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
+           e1++;
+         for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
+           e2++;
+         r = (e1 - s1) - (e2 - s2);
+          if (!r)
+           r = strncmp(s1, s2, e1 - s1);
+          if (r)
+           return r > 0 ? 1 : -1;
+       }
+      else
+       {
+         for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
+           e1++;
+         for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
+           e2++;
+         r = (e1 - s1) - (e2 - s2);
+          if (r > 0)
+           {
+             r = strncmp(s1, s2, e2 - s2);
+             return r >= 0 ? 1 : -1;
+           }
+          if (r < 0)
+           {
+             r = strncmp(s1, s2, e1 - s1);
+             return r <= 0 ? -1 : 1;
+           }
+         r = strncmp(s1, s2, e1 - s1);
+         if (r)
+           return r > 0 ? 1 : -1;
+       }
+      s1 = e1;
+      s2 = e2;
+    }
+  return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
+}
+
+int
+solv_vercmp_rpm_notilde(const char *s1, const char *q1, const char *s2, const char *q2)
+{
+  int r = 0;
+  const char *e1, *e2;
+
+  while (s1 < q1 && s2 < q2)
+    {
+      while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
+          !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z'))
+       s1++;
+      while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
+          !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z'))
+       s2++;
+      if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
+       {
+         while (*s1 == '0' && s1[1] >= '0' && s1[1] <= '9')
+           s1++;
+         while (*s2 == '0' && s2[1] >= '0' && s2[1] <= '9')
+           s2++;
+         for (e1 = s1; *e1 >= '0' && *e1 <= '9'; )
+           e1++;
+         for (e2 = s2; *e2 >= '0' && *e2 <= '9'; )
+           e2++;
+         r = (e1 - s1) - (e2 - s2);
+          if (!r)
+           r = strncmp(s1, s2, e1 - s1);
+          if (r)
+           return r > 0 ? 1 : -1;
+       }
+      else
+       {
+         for (e1 = s1; (*e1 >= 'a' && *e1 <= 'z') || (*e1 >= 'A' && *e1 <= 'Z'); )
+           e1++;
+         for (e2 = s2; (*e2 >= 'a' && *e2 <= 'z') || (*e2 >= 'A' && *e2 <= 'Z'); )
+           e2++;
+         r = (e1 - s1) - (e2 - s2);
+          if (r > 0)
+           {
+             r = strncmp(s1, s2, e2 - s2);
+             return r >= 0 ? 1 : -1;
+           }
+          if (r < 0)
+           {
+             r = strncmp(s1, s2, e1 - s1);
+             return r <= 0 ? -1 : 1;
+           }
+         r = strncmp(s1, s2, e1 - s1);
+         if (r)
+           return r > 0 ? 1 : -1;
+       }
+      s1 = e1;
+      s2 = e2;
+    }
+  return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
+}
+
+#endif
+
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+
+static int
+solv_cmp_version_part_haiku(const char *s1, const char *q1, const char *s2,
+  const char *q2)
+{
+  while (s1 < q1 && s2 < q2)
+    {
+      int cmp, len1, len2;
+      const char *part1 = s1, *part2 = s2;
+
+      /* compare non-number part */
+      while (s1 < q1 && !isdigit(*s1))
+        s1++;
+      while (s2 < q2 && !isdigit(*s2))
+        s2++;
+
+      if (part1 != s1)
+        {
+          if (part2 == s2)
+            return 1;
+
+          len1 = s1 - part1;
+          len2 = s2 - part2;
+          cmp = strncmp(part1, part2, len1 < len2 ? len1 : len2);
+          if (cmp != 0)
+            return cmp;
+          if (len1 != len2)
+            return len1 - len2;
+       }
+      else if (part2 != s2)
+        return -1;
+
+      /* compare number part */
+      part1 = s1;
+      part2 = s2;
+
+      while (s1 < q1 && isdigit(*s1))
+        s1++;
+      while (s2 < q2 && isdigit(*s2))
+        s2++;
+
+      while (part1 + 1 < s1 && *part1 == '0')
+        part1++;
+      while (part2 + 1 < s2 && *part2 == '0')
+        part2++;
+
+      len1 = s1 - part1;
+      len2 = s2 - part2;
+      if (len1 != len2)
+        return len1 - len2;
+      if (len1 == 0)
+        return 0;
+
+      cmp = strncmp(part1, part2, len1);
+      if (cmp != 0)
+       return cmp;
+    }
+
+  return s1 < q1 ? 1 : s2 < q2 ? -1 : 0;
+}
+
+int
+solv_vercmp_haiku(const char *s1, const char *q1, const char *s2, const char *q2)
+{
+  const char *pre1 = s1;
+  const char *pre2 = s2;
+  int cmp;
+
+  /* find pre-release separator */
+  while (pre1 != q1 && *pre1 != '~')
+    pre1++;
+  while (pre2 != q2 && *pre2 != '~')
+    pre2++;
+
+  /* compare main versions */
+  cmp = solv_cmp_version_part_haiku(s1, pre1, s2, pre2);
+  if (cmp != 0)
+    return cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
+
+  /* main versions are equal -- compare pre-release (none is greatest) */
+  if (pre1 == q1)
+    return pre2 == q2 ? 0 : 1;
+  if (pre2 == q2)
+    return -1;
+
+  cmp = solv_cmp_version_part_haiku(pre1 + 1, q1, pre2 + 1, q2);
+  return cmp == 0 ? 0 : cmp < 0 ? -1 : 1; /* must return -1, 0, or 1 */
+}
+
+#endif /* HAIKU */
+
+
+/*
+ * the solv_vercmp variant your system uses.
+ */
+int
+solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
+{
+#if defined(DEBIAN)
+  return solv_vercmp_deb(s1, q1, s2, q2);
+#elif defined(ARCHLINUX)
+  return solv_vercmp_rpm_notilde(s1, q1, s2, q2);
+#elif defined(HAIKU)
+  return solv_vercmp_haiku(s1, q1, s2, q2);
+#else
+  return solv_vercmp_rpm(s1, q1, s2, q2);
+#endif
+}
+
+#if defined(MULTI_SEMANTICS)
+# define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \
+                        pool->disttype == DISTTYPE_HAIKU ? solv_vercmp_haiku : \
+                        &solv_ver##cmp_rpm))
+#elif defined(DEBIAN)
+# define solv_vercmp solv_vercmp_deb
+#elif defined(ARCHLINUX)
+# define solv_vercmp solv_vercmp_rpm_notilde
+#elif defined(HAIKU)
+# define solv_vercmp solv_vercmp_haiku
+#else
+# define solv_vercmp solv_vercmp_rpm
+#endif
+
+/* edition (e:v-r) compare */
+int
+pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
+{
+  int r;
+  const char *s1, *s2;
+  const char *r1, *r2;
+
+  if (evr1 == evr2)
+    return 0;
+
+#if 0
+  POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
+#endif
+  for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
+    ;
+  for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++)
+    ;
+  if (mode == EVRCMP_MATCH && (*evr1 == ':' || *evr2 == ':'))
+    {
+      /* empty epoch, skip epoch check */
+      if (*s1 == ':')
+       evr1 = s1 + 1;
+      if (*s2 == ':')
+       evr2 = s2 + 1;
+      s1 = evr1;
+      s2 = evr2;
+    }
+
+  /* compare the epoch */
+  if (s1 == evr1 || *s1 != ':')
+    s1 = 0;
+  if (s2 == evr2 || *s2 != ':')
+    s2 = 0;
+  if (s1 && s2)
+    {
+      r = solv_vercmp(evr1, s1, evr2, s2);
+      if (r)
+       return r;
+      evr1 = s1 + 1;
+      evr2 = s2 + 1;
+    }
+  else if (s1)
+    {
+      if (!pool->promoteepoch)
+       {
+         while (*evr1 == '0')
+           evr1++;
+         if (*evr1 != ':')
+           return 1;
+       }
+      evr1 = s1 + 1;
+    }
+  else if (s2)
+    {
+      while (*evr2 == '0')
+       evr2++;
+      if (*evr2 != ':')
+       return -1;
+      evr2 = s2 + 1;
+    }
+
+  /* same epoch, now split into version/release */
+  for (s1 = evr1, r1 = 0; *s1; s1++)
+    if (*s1 == '-')
+      r1 = s1;
+  for (s2 = evr2, r2 = 0; *s2; s2++)
+    if (*s2 == '-')
+      r2 = s2;
+  r = 0;
+  if (mode != EVRCMP_MATCH || (evr1 != (r1 ? r1 : s1) && evr2 != (r2 ? r2 : s2)))
+    r = solv_vercmp(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2);
+  if (r)
+    return r;
+
+  if (mode == EVRCMP_COMPARE)
+    {
+      if (!r1 && r2)
+       return -1;
+      if (r1 && !r2)
+       return 1;
+    }
+  if (mode == EVRCMP_COMPARE_EVONLY)
+    return 0;
+  if (mode == EVRCMP_MATCH_RELEASE)
+    {
+      /* rpm treats empty releases as missing, i.e "foo = 4-" is the same as "foo = 4" */
+      if (r1 && r1 + 1 == s1)
+       r1 = 0;
+      if (r2 && r2 + 1 == s2)
+       r2 = 0;
+    }
+  if (r1 && r2)
+    {
+      r1++;
+      r2++;
+      if (mode != EVRCMP_MATCH || (s1 != r1 && s2 != r2))
+       {
+         if (pool->havedistepoch)
+           {
+             const char *d1, *d2;
+             for (d1 = r1; d1 < s1; d1++)
+               if (*d1 == ':')
+                 break;
+             for (d2 = r2; d2 < s2; d2++)
+               if (*d2 == ':')
+                 break;
+             /* XXX: promote just in one direction? */
+             r = solv_vercmp(r1, d1 ? d1 : s1, r2, d2 ? d2 : s2);
+             if (r == 0 && d1 < s1 && d2 < s2)
+               r = solv_vercmp(d1 + 1, s1, d2 + 1, s2);
+           }
+         else
+            r = solv_vercmp(r1, s1, r2, s2);
+       }
+    }
+  else if (mode == EVRCMP_MATCH_RELEASE)
+    {
+      if (!r1 && r2)
+       return -2;
+      if (r1 && !r2)
+       return 2;
+    }
+  return r;
+}
+
+int
+pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode)
+{
+  const char *evr1, *evr2;
+  if (evr1id == evr2id)
+    return 0;
+  evr1 = pool_id2str(pool, evr1id);
+  evr2 = pool_id2str(pool, evr2id);
+  return pool_evrcmp_str(pool, evr1, evr2, mode);
+}
+
+int
+pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release)
+{
+  const char *evr1;
+  const char *s1;
+  const char *r1;
+  int r;
+
+  evr1 = pool_id2str(pool, evrid);
+  for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++)
+    ;
+  if (s1 != evr1 && *s1 == ':')
+    {
+      if (epoch)
+       {
+         r = solv_vercmp(evr1, s1, epoch, epoch + strlen(epoch));
+         if (r)
+           return r;
+       }
+      evr1 = s1 + 1;
+    }
+  else if (epoch)
+    {
+      while (*epoch == '0')
+       epoch++;
+      if (*epoch)
+       return -1;
+    }
+  for (s1 = evr1, r1 = 0; *s1; s1++)
+    if (*s1 == '-')
+      r1 = s1;
+  if (version)
+    {
+      r = solv_vercmp(evr1, r1 ? r1 : s1, version, version + strlen(version));
+      if (r)
+       return r;
+    }
+  if (release)
+    {
+      if (!r1)
+       return -1;
+      r = solv_vercmp(r1 + 1, s1, release, release + strlen(release));
+      if (r)
+       return r;
+    }
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/src/evr.h b/libsolv-0.7.2/src/evr.h
new file mode 100644 (file)
index 0000000..d18cc52
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * evr.h
+ *
+ */
+
+#ifndef LIBSOLV_EVR_H
+#define LIBSOLV_EVR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "pooltypes.h"
+
+#define EVRCMP_COMPARE                 0
+#define EVRCMP_MATCH_RELEASE           1
+#define EVRCMP_MATCH                   2
+#define EVRCMP_COMPARE_EVONLY          3
+
+extern int solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2);
+
+extern int pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
+extern int pool_evrcmp(const Pool *pool, Id evr1id, Id evr2id, int mode);
+extern int pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version, const char *release);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_EVR_H */
diff --git a/libsolv-0.7.2/src/filelistfilter.c b/libsolv-0.7.2/src/filelistfilter.c
new file mode 100644 (file)
index 0000000..e698d6f
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2018, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * filelistfilter.c
+ *
+ * Support repodata with a filelist filtered by a custom filter
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "repo.h"
+#include "pool.h"
+#include "util.h"
+
+static Id default_filelist_filter;
+
+#define FF_EXACT       0
+#define FF_END         1
+#define FF_START       2
+#define FF_SUB         3               /* FF_END | FF_START */
+#define FF_GLOB                4
+#define FF_START5      5
+
+void
+repodata_free_filelistfilter(Repodata *data)
+{
+  if (data->filelistfilter)
+    {
+      if (data->filelistfilter != &default_filelist_filter)
+        solv_free(data->filelistfilter);
+      data->filelistfilter = 0;
+    }
+  data->filelistfilterdata = solv_free(data->filelistfilterdata);
+}
+
+static void
+repodata_set_filelistfilter(Repodata *data)
+{
+  Id type;
+  Queue q;
+  int i, j;
+  char *filterdata;
+  int nfilterdata;
+
+  if (data->filelistfilter && data->filelistfilter != &default_filelist_filter)
+    data->filelistfilter = solv_free(data->filelistfilter);
+  data->filelistfilterdata = solv_free(data->filelistfilterdata);
+  type = repodata_lookup_type(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST);
+  if (type != REPOKEY_TYPE_IDARRAY)
+    {
+      data->filelistfilter = &default_filelist_filter;
+      return;
+    }
+  queue_init(&q);
+  repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST, &q);
+  if (q.count == 3)
+    {
+      /* check if this is the default filter */
+      int t = 0;
+      for (i = 0; i < 3; i++)
+       {
+         Id id = q.elements[i];
+         const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); 
+         if (!strcmp(g, "*bin/*"))
+           t |= 1;
+         else if (!strcmp(g, "/etc/*"))
+           t |= 2;
+         else if (!strcmp(g, "/usr/lib/sendmail"))
+           t |= 4;
+       }
+      if (t == 7)
+       {
+         queue_free(&q);
+         data->filelistfilter = &default_filelist_filter;
+         return;
+       }
+    }
+  data->filelistfilter = solv_calloc(q.count * 2 + 1, sizeof(Id));
+  filterdata = solv_calloc_block(1, 1, 255);
+  nfilterdata = 1;
+  
+  for (i = j = 0; i < q.count; i++)
+    {
+      Id id = q.elements[i];
+      const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); 
+      const char *p;
+      int t = FF_EXACT;
+      int gl;
+      if (!id || !g || !*g)
+       continue;
+      for (p = g; *p && t != FF_GLOB; p++)
+       {
+         if (*p == '*')
+           {
+             if (p == g)
+               t |= FF_END;
+             else if (!p[1])
+               t |= FF_START;
+             else
+               t = FF_GLOB;
+           }
+         else if (*p == '[' || *p == '?')
+           t = FF_GLOB;
+       }
+      gl = strlen(g);
+      if (t == FF_END) /* not supported */
+       t = FF_GLOB;
+      if (t == FF_START && gl == 5)
+       t = FF_START5;
+      filterdata = solv_extend(filterdata, nfilterdata, gl + 1, 1, 255);
+      data->filelistfilter[j++] = nfilterdata;
+      data->filelistfilter[j++] = t;
+      switch (t)
+       {
+       case FF_START:
+       case FF_START5:
+         strcpy(filterdata + nfilterdata, g);
+         filterdata[nfilterdata + gl - 1] = 0;
+         nfilterdata += gl;
+         break;
+       case FF_SUB:
+         strcpy(filterdata + nfilterdata, g + 1);
+         filterdata[nfilterdata + gl - 2] = 0;
+         nfilterdata += gl - 1;
+         break;
+       default:
+         strcpy(filterdata + nfilterdata, g);
+         nfilterdata += gl + 1;
+         break;
+       }
+    }
+  filterdata = solv_realloc(filterdata, nfilterdata);
+  data->filelistfilter[j++] = 0;
+  data->filelistfilterdata = filterdata;
+  queue_free(&q);
+}
+
+int
+repodata_filelistfilter_matches(Repodata *data, const char *str)
+{
+  Id *ff;
+  if (data && !data->filelistfilter)
+    repodata_set_filelistfilter(data);
+  if (!data || data->filelistfilter == &default_filelist_filter)
+    {
+      /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
+      if (strstr(str, "bin/"))
+       return 1;
+      if (!strncmp(str, "/etc/", 5))
+       return 1;
+      if (!strcmp(str, "/usr/lib/sendmail"))
+       return 1;
+      return 0;
+    }
+  for (ff = data->filelistfilter; *ff; ff += 2)
+    {
+      const char *g = data->filelistfilterdata + *ff;
+      switch (ff[1])
+       {
+       case FF_EXACT:
+         if (!strcmp(str, g))
+           return 1;
+         break;
+       case FF_START:
+         if (!strncmp(str, g, strlen(g)))
+           return 1;
+         break;
+       case FF_SUB:
+         if (!strstr(str, g))
+           return 1;
+         break;
+       case FF_START5:
+         if (!strncmp(str, g, 5))
+           return 1;
+         break;
+       default:
+         if (!fnmatch(g, str, 0))
+           return 1;
+         break;
+       }
+    }
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/src/fileprovides.c b/libsolv-0.7.2/src/fileprovides.c
new file mode 100644 (file)
index 0000000..ec80831
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2007-2016, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * fileprovides.c
+ *
+ * Add missing file dependencies to the package provides 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "bitmap.h"
+
+
+struct searchfiles {
+  Id *ids;
+  int nfiles;
+  Map seen;
+};
+
+#define SEARCHFILES_BLOCK 127
+
+static void
+pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
+{
+  Id dep, sid;
+  const char *s;
+  struct searchfiles *csf;
+
+  while ((dep = *ida++) != 0)
+    {
+      csf = sf;
+      while (ISRELDEP(dep))
+       {
+         Reldep *rd;
+         sid = pool->ss.nstrings + GETRELID(dep);
+         if (MAPTST(&csf->seen, sid))
+           {
+             dep = 0;
+             break;
+           }
+         MAPSET(&csf->seen, sid);
+         rd = GETRELDEP(pool, dep);
+         if (rd->flags < 8)
+           dep = rd->name;
+         else if (rd->flags == REL_NAMESPACE)
+           {
+             if (rd->name == NAMESPACE_SPLITPROVIDES)
+               {
+                 csf = isf;
+                 if (!csf || MAPTST(&csf->seen, sid))
+                   {
+                     dep = 0;
+                     break;
+                   }
+                 MAPSET(&csf->seen, sid);
+               }
+             dep = rd->evr;
+           }
+         else if (rd->flags == REL_FILECONFLICT)
+           {
+             dep = 0;
+             break;
+           }
+         else
+           {
+             Id ids[2];
+             ids[0] = rd->name;
+             ids[1] = 0;
+             pool_addfileprovides_dep(pool, ids, csf, isf);
+             dep = rd->evr;
+           }
+       }
+      if (!dep)
+       continue;
+      if (MAPTST(&csf->seen, dep))
+       continue;
+      MAPSET(&csf->seen, dep);
+      s = pool_id2str(pool, dep);
+      if (*s != '/')
+       continue;
+      if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s))
+       continue;       /* skip non-standard locations csf == isf: installed case */
+      csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
+      csf->ids[csf->nfiles++] = dep;
+    }
+}
+
+struct addfileprovides_cbdata {
+  int nfiles;
+  Id *ids;
+  char **dirs;
+  char **names;
+  Id *dids;
+
+  Map *providedids;
+  int provstart;
+  int provend;
+
+  Map *todo;
+  int todo_start;
+  int todo_end;
+};
+
+/* split filelist dep into basename and dirname */
+static void
+create_dirs_names_array(struct addfileprovides_cbdata *cbd, Pool *pool)
+{
+  int i;
+  cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *));
+  cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *));
+  for (i = 0; i < cbd->nfiles; i++)
+    {
+      char *s = solv_strdup(pool_id2str(pool, cbd->ids[i]));
+      cbd->dirs[i] = s;
+      s = strrchr(s, '/');
+      *s = 0;
+      cbd->names[i] = s + 1;
+    }
+}
+
+static void
+free_dirs_names_array(struct addfileprovides_cbdata *cbd)
+{
+  int i;
+  if (cbd->dirs)
+    {
+      for (i = 0; i < cbd->nfiles; i++)
+       solv_free(cbd->dirs[i]);
+      cbd->dirs = solv_free(cbd->dirs);
+      cbd->names = solv_free(cbd->names);
+    }
+}
+
+static void
+prune_todo_range(Repo *repo, struct addfileprovides_cbdata *cbd)
+{
+  int start = cbd->todo_start, end = cbd->todo_end;
+  while (start < end && !MAPTST(cbd->todo, start - repo->start))
+    start++;
+  while (end > start && !MAPTST(cbd->todo, end - 1 - repo->start))
+    end--;
+  cbd->todo_start = start;
+  cbd->todo_end = end;
+}
+
+static int
+repodata_intersects_todo(Repodata *data, struct addfileprovides_cbdata *cbd)
+{
+  Repo *repo;
+  int p, start = data->start, end = data->end;
+  if (start >= cbd->todo_end || end <= cbd->todo_start)
+    return 0;
+  repo = data->repo;
+  if (start < cbd->todo_start)
+    start = cbd->todo_start;
+  if (end > cbd->todo_end)
+    end = cbd->todo_end;
+  for (p = start; p < end; p++)
+    if (MAPTST(cbd->todo, p - repo->start))
+      return 1;
+  return 0;
+}
+
+/* forward declaration */
+static void repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd);
+
+/* search a subset of the todo range */
+static void
+repodata_addfileprovides_search_limited(Repodata *data, struct addfileprovides_cbdata *cbd, int start, int end)
+{
+
+  int old_todo_start = cbd->todo_start;
+  int old_todo_end = cbd->todo_end;
+  if (start < cbd->todo_start)
+    start = cbd->todo_start;
+  if (end > cbd->todo_end)
+    end = cbd->todo_end;
+  if (start >= end)
+    return;
+  cbd->todo_start = start;
+  cbd->todo_end = end;
+  repodata_addfileprovides_search(data, cbd);
+  cbd->todo_start = old_todo_start;
+  cbd->todo_end = old_todo_end;
+  prune_todo_range(data->repo, cbd);
+}
+
+static void
+repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd)
+{
+  Repo *repo = data->repo;
+  int i, p, start, end;
+  Map useddirs;
+  Map *providedids = 0;
+
+  /* make it available */
+  if (data->state == REPODATA_STUB)
+    repodata_load(data);
+  if (data->state != REPODATA_AVAILABLE)
+    return;
+  if (!data->incoredata || !data->dirpool.ndirs)
+    return;
+
+  start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
+  end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
+
+  if (start >= end)
+    return;
+
+  /* deal with provideids overlap */
+  if (cbd->providedids)
+    {
+      if (start >= cbd->provstart && end <= cbd->provend)
+       providedids = cbd->providedids; /* complete overlap */
+      else if (start < cbd->provend && end > cbd->provstart)
+       {
+         /* partial overlap, need to split search */
+         if (start < cbd->provstart)
+           {
+             repodata_addfileprovides_search_limited(data, cbd, start, cbd->provstart);
+             start = cbd->provstart;
+           }
+         if (end > cbd->provend)
+           {
+             repodata_addfileprovides_search_limited(data, cbd, cbd->provend, end);
+             end = cbd->provend;
+           }
+         if (start < end)
+           repodata_addfileprovides_search_limited(data, cbd, start, end);
+         return;
+       }
+    }
+
+  /* set up dirs and names array if not already done */
+  if (!cbd->dirs)
+    create_dirs_names_array(cbd, repo->pool);
+
+  /* set up useddirs map and the cbd->dids array */
+  map_init(&useddirs, data->dirpool.ndirs);
+  for (i = 0; i < cbd->nfiles; i++)
+    {
+      Id did;
+      if (providedids && MAPTST(providedids, cbd->ids[i]))
+       {
+         cbd->dids[i] = 0;     /* already included, do not add again */
+         continue;
+       }
+      cbd->dids[i] = did = repodata_str2dir(data, cbd->dirs[i], 0);
+      if (did)
+       MAPSET(&useddirs, did);
+    }
+  repodata_free_dircache(data);                /* repodata_str2dir created it */
+
+  for (p = start; p < end; p++)
+    {
+      const unsigned char *dp;
+      Solvable *s;
+      if (!MAPTST(cbd->todo, p - repo->start))
+       continue;
+      dp = repodata_lookup_packed_dirstrarray(data, p, SOLVABLE_FILELIST);
+      if (!dp)
+       continue;
+      /* now iterate through the packed array */
+      s = repo->pool->solvables + p;
+      MAPCLR(cbd->todo, p - repo->start);      /* this entry is done */
+      for (;;)
+       {
+         Id did = 0;
+         int c;
+         while ((c = *dp++) & 0x80)
+           did = (did << 7) ^ c ^ 0x80;
+         did = (did << 6) | (c & 0x3f);
+         if ((unsigned int)did < (unsigned int)data->dirpool.ndirs && MAPTST(&useddirs, did))
+           {
+             /* there is at least one entry with that did */
+             for (i = 0; i < cbd->nfiles; i++)
+               if (cbd->dids[i] == did && !strcmp(cbd->names[i], (const char *)dp))
+                 s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
+           }
+         if (!(c & 0x40))
+           break;
+         dp += strlen((const char *)dp) + 1;
+       }
+    }
+  map_free(&useddirs);
+  prune_todo_range(repo, cbd);
+}
+
+static void
+repo_addfileprovides_search_filtered(Repo *repo, struct addfileprovides_cbdata *cbd, int filteredid, Map *postpone)
+{
+  Repodata *data = repo->repodata + filteredid;
+  Map *providedids = cbd->providedids;
+  int rdid;
+  int start, end, p, i;
+  Map old_todo;
+  int old_todo_start, old_todo_end;
+
+  start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
+  end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
+
+  if (providedids)
+    {
+      /* check if all solvables are in the provide range */
+      if (start < cbd->provstart || end > cbd->provend)
+       {
+         /* unclear, check each solvable */
+         for (p = start; p < end; p++)
+           {
+             if (p >= cbd->provstart && p < cbd->provend)
+               continue;
+             if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start))
+               {
+                 providedids = 0;      /* nope, cannot prune with providedids */
+                 break;
+               }
+           }
+       }
+    }
+
+  /* check if the filtered files are enough */
+  for (i = 0; i < cbd->nfiles; i++)
+    {
+      if (providedids && MAPTST(providedids, cbd->ids[i]))     /* this one is already provided */
+       continue;
+      if (!repodata_filelistfilter_matches(data, pool_id2str(repo->pool, cbd->ids[i])))
+        break;
+    }
+  if (i < cbd->nfiles)
+    {
+      /* nope, need to search the extensions as well. postpone. */
+      for (p = start; p < end; p++)
+       {
+         if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start))
+           {
+             if (!postpone->size)
+               map_grow(postpone, repo->nsolvables);
+             MAPSET(postpone, p - repo->start);
+             MAPCLR(cbd->todo, p - repo->start);
+           }
+       }
+      prune_todo_range(repo, cbd);
+      return;
+    }
+
+  /* now check if there is no data marked withour EXTENSION */
+  /* limit todo to the solvables in this repodata */
+  old_todo_start = cbd->todo_start;
+  old_todo_end = cbd->todo_end;
+  old_todo = *cbd->todo;
+  map_init(cbd->todo, repo->nsolvables);
+  for (p = start; p < end; p++)
+    if (data->incoreoffset[p - data->start] && MAPTST(&old_todo, p - repo->start))
+      {
+        MAPCLR(&old_todo, p - repo->start);
+        MAPSET(cbd->todo, p - repo->start);
+      }
+  prune_todo_range(repo, cbd);
+
+  /* do the check */
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > filteredid ; rdid--, data--)
+    {
+      if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+       continue;
+      if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
+       continue;
+      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+       continue;
+      if (!repodata_intersects_todo(data, cbd))
+       continue;
+      /* oh no, this filelist data is not tagged with REPODATA_FILELIST_EXTENSION! */
+      /* postpone entries that have filelist data */
+      start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
+      end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
+      for (p = start; p < end; p++)
+       if (MAPTST(cbd->todo, p - repo->start))
+         if (repodata_lookup_type(data, p, SOLVABLE_FILELIST))
+           {
+             if (!postpone->size)
+               map_grow(postpone, repo->nsolvables);
+             MAPSET(postpone, p - repo->start);
+             MAPCLR(cbd->todo, p - repo->start);
+           }
+      prune_todo_range(repo, cbd);
+      if (cbd->todo_start >= cbd->todo_end)
+       break;
+    }
+
+  /* do the search over the filtered file list with the remaining entries*/
+  if (cbd->todo_start < cbd->todo_end)
+    repodata_addfileprovides_search(repo->repodata + filteredid, cbd);
+
+  /* restore todo map */
+  map_free(cbd->todo);
+  *cbd->todo = old_todo;
+  cbd->todo_start = old_todo_start;
+  cbd->todo_end = old_todo_end;
+  prune_todo_range(repo, cbd);
+}
+
+static void
+repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf)
+{
+  Repodata *data;
+  int rdid, p, i;
+  int provstart, provend;
+  Map todo;
+  Map providedids;
+
+  if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles)
+    return;
+
+  /* update search data if changed */
+  if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids)
+    {
+      free_dirs_names_array(cbd);
+      cbd->nfiles = sf->nfiles;
+      cbd->ids = sf->ids;
+      cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
+    }
+
+  /* create todo map and range */
+  map_init(&todo, repo->end - repo->start);
+  for (p = repo->start; p < repo->end; p++)
+    if (repo->pool->solvables[p].repo == repo)
+      MAPSET(&todo, p - repo->start);
+  cbd->todo = &todo;
+  cbd->todo_start = repo->start;
+  cbd->todo_end = repo->end;
+  prune_todo_range(repo, cbd);
+
+  provstart = provend = 0;
+  map_init(&providedids, 0);
+  data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES);
+  if (data)
+    {
+      Queue fileprovidesq;
+      queue_init(&fileprovidesq);
+      if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
+       {
+         map_grow(&providedids, repo->pool->ss.nstrings);
+         cbd->providedids = &providedids;
+         provstart = data->start;
+         provend = data->end;
+         for (i = 0; i < fileprovidesq.count; i++)
+           MAPSET(&providedids, fileprovidesq.elements[i]);
+         for (i = 0; i < cbd->nfiles; i++)
+           if (!MAPTST(&providedids, cbd->ids[i]))
+             break;
+         if (i == cbd->nfiles)
+           {
+             /* all included, clear entries from todo list */
+             if (provstart <= cbd->todo_start && provend >= cbd->todo_end)
+               cbd->todo_end = cbd->todo_start;        /* clear complete range */
+             else
+               {
+                 for (p = provstart; p < provend; p++)
+                   MAPCLR(&todo, p - repo->start);
+                 prune_todo_range(repo, cbd);
+               }
+           }
+       }
+      queue_free(&fileprovidesq);
+    }
+
+  if (cbd->todo_start >= cbd->todo_end)
+    {
+      map_free(&todo);
+      cbd->todo = 0;
+      map_free(&providedids);
+      cbd->providedids = 0;
+      return;
+    }
+
+  /* this is similar to repo_lookup_filelist_repodata in repo.c */
+
+  for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++)
+    if (data->filelisttype == REPODATA_FILELIST_FILTERED)
+      break;
+  for (; rdid < repo->nrepodata; rdid++, data++)
+    if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+      break;
+
+  if (rdid < repo->nrepodata)
+    {
+      /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */
+      Map postpone;
+      map_init(&postpone, 0);
+      for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+       {
+         if (data->filelisttype != REPODATA_FILELIST_FILTERED)
+           continue;
+         if (!repodata_intersects_todo(data, cbd))
+           continue;
+         if (data->state != REPODATA_AVAILABLE)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED)
+               continue;
+           }
+         repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone);
+       }
+      if (postpone.size)
+       {
+         /* add postponed entries back to todo */
+         map_or(&todo, &postpone);
+         cbd->todo_start = repo->start;
+         cbd->todo_end = repo->end;
+         prune_todo_range(repo, cbd);
+       }
+      map_free(&postpone);
+    }
+
+  /* search remaining entries in the standard way */
+  if (cbd->todo_start < cbd->todo_end)
+    {
+      for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+       {
+         if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
+           continue;
+         if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+           continue;
+         if (!repodata_intersects_todo(data, cbd))
+           continue;
+         repodata_addfileprovides_search(data, cbd);
+         if (cbd->todo_start >= cbd->todo_end)
+           break;
+       }
+    }
+
+  map_free(&todo);
+  cbd->todo = 0;
+  map_free(&providedids);
+  cbd->providedids = 0;
+}
+
+void
+pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
+{
+  Solvable *s;
+  Repo *installed, *repo;
+  struct searchfiles sf, isf, *isfp;
+  struct addfileprovides_cbdata cbd;
+  int i;
+  unsigned int now;
+
+  installed = pool->installed;
+  now = solv_timems(0);
+  memset(&cbd, 0, sizeof(cbd));
+  memset(&sf, 0, sizeof(sf));
+  map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
+  memset(&isf, 0, sizeof(isf));
+  map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
+  pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2;
+
+  if (idq)
+    queue_empty(idq);
+  if (idqinst)
+    queue_empty(idqinst);
+  isfp = installed ? &isf : 0;
+  for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
+    {
+      repo = s->repo;
+      if (!repo)
+       continue;
+      if (s->obsoletes)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
+      if (s->conflicts)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
+      if (s->requires)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
+      if (s->recommends)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
+      if (s->suggests)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
+      if (s->supplements)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
+      if (s->enhances)
+        pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
+    }
+
+  map_free(&sf.seen);
+  map_free(&isf.seen);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
+  if (sf.nfiles)
+    {
+#if 0
+      for (i = 0; i < sf.nfiles; i++)
+       POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
+#endif
+      FOR_REPOS(i, repo)
+        repo_addfileprovides_search(repo, &cbd, &sf);
+      if (idq)
+       queue_insertn(idq, idq->count, sf.nfiles, sf.ids);
+      if (idqinst)
+       queue_insertn(idqinst, idqinst->count, sf.nfiles, sf.ids);
+      solv_free(sf.ids);
+    }
+  if (isf.nfiles)
+    {
+#if 0
+      for (i = 0; i < isf.nfiles; i++)
+       POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
+#endif
+      if (installed)
+        repo_addfileprovides_search(installed, &cbd, &isf);
+      if (installed && idqinst)
+        for (i = 0; i < isf.nfiles; i++)
+         queue_pushunique(idqinst, isf.ids[i]);
+      solv_free(isf.ids);
+    }
+  free_dirs_names_array(&cbd);
+  solv_free(cbd.dids);
+  pool_freewhatprovides(pool); /* as we have added provides */
+  POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
+}
+
+void
+pool_addfileprovides(Pool *pool)
+{
+  pool_addfileprovides_queue(pool, 0, 0);
+}
+
diff --git a/libsolv-0.7.2/src/hash.h b/libsolv-0.7.2/src/hash.h
new file mode 100644 (file)
index 0000000..4f595bb
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * hash.h
+ * generic hash functions
+ */
+
+#ifndef LIBSOLV_HASH_H
+#define LIBSOLV_HASH_H
+
+#include "pooltypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* value of a hash */
+typedef unsigned int Hashval;
+
+/* inside the hash table, Ids are stored. Hash maps: string -> hash -> Id */
+typedef Id *Hashtable;
+
+/* hash chain */
+#define HASHCHAIN_START 7
+#define HASHCHAIN_NEXT(h, hh, mask) (((h) + (hh)++) & (mask))
+
+/* very simple hash function
+ * string -> hash
+ */
+static inline Hashval
+strhash(const char *str)
+{
+  Hashval r = 0;
+  unsigned int c;
+  while ((c = *(const unsigned char *)str++) != 0)
+    r += (r << 3) + c;
+  return r;
+}
+
+static inline Hashval
+strnhash(const char *str, unsigned len)
+{
+  Hashval r = 0;
+  unsigned int c;
+  while (len-- && (c = *(const unsigned char *)str++) != 0)
+    r += (r << 3) + c;
+  return r;
+}
+
+static inline Hashval
+strhash_cont(const char *str, Hashval r)
+{
+  unsigned int c;
+  while ((c = *(const unsigned char *)str++) != 0)
+    r += (r << 3) + c;
+  return r;
+}
+
+
+/* hash for rel
+ * rel -> hash
+ */
+static inline Hashval
+relhash(Id name, Id evr, int flags)
+{
+  return name + 7 * evr + 13 * flags;
+}
+
+
+/* compute bitmask for value
+ * returns smallest (2^n-1) > 2 * num + 3
+ *
+ * used for Hashtable 'modulo' operation
+ */
+static inline Hashval
+mkmask(unsigned int num)
+{
+  num = num * 2 + 3;
+  while (num & (num - 1))
+    num &= num - 1;
+  return num * 2 - 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_HASH_H */
diff --git a/libsolv-0.7.2/src/knownid.h b/libsolv-0.7.2/src/knownid.h
new file mode 100644 (file)
index 0000000..8e53183
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2007-2014, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * knownid.h
+ *
+ */
+
+/*
+ * Warning: you're free to append new entries, but insert/delete breaks
+ * the ABI!
+ */
+
+#ifndef LIBSOLV_KNOWNID_H
+#define LIBSOLV_KNOWNID_H
+
+#undef KNOWNID
+#ifdef KNOWNID_INITIALIZE
+# define KNOWNID(a, b) b
+static const char *initpool_data[] = {
+#else
+# define KNOWNID(a, b) a
+enum solv_knownid {
+#endif
+
+KNOWNID(ID_NULL,                       "<NULL>"),
+KNOWNID(ID_EMPTY,                      ""),
+
+/* The following Ids are stored in the solvable and must
+ * come in one block */
+KNOWNID(SOLVABLE_NAME,                 "solvable:name"),
+KNOWNID(SOLVABLE_ARCH,                 "solvable:arch"),
+KNOWNID(SOLVABLE_EVR,                  "solvable:evr"),
+KNOWNID(SOLVABLE_VENDOR,               "solvable:vendor"),
+KNOWNID(SOLVABLE_PROVIDES,             "solvable:provides"),
+KNOWNID(SOLVABLE_OBSOLETES,            "solvable:obsoletes"),
+KNOWNID(SOLVABLE_CONFLICTS,            "solvable:conflicts"),
+KNOWNID(SOLVABLE_REQUIRES,             "solvable:requires"),
+KNOWNID(SOLVABLE_RECOMMENDS,           "solvable:recommends"),
+KNOWNID(SOLVABLE_SUGGESTS,             "solvable:suggests"),
+KNOWNID(SOLVABLE_SUPPLEMENTS,          "solvable:supplements"),
+KNOWNID(SOLVABLE_ENHANCES,             "solvable:enhances"),
+KNOWNID(RPM_RPMDBID,                   "rpm:dbid"),
+
+/* normal requires before this, prereqs after this */
+KNOWNID(SOLVABLE_PREREQMARKER,         "solvable:prereqmarker"),
+/* normal provides before this, generated file provides after this */
+KNOWNID(SOLVABLE_FILEMARKER,           "solvable:filemarker"),
+
+KNOWNID(NAMESPACE_INSTALLED,           "namespace:installed"),
+KNOWNID(NAMESPACE_MODALIAS,            "namespace:modalias"),
+KNOWNID(NAMESPACE_SPLITPROVIDES,       "namespace:splitprovides"),
+KNOWNID(NAMESPACE_LANGUAGE,            "namespace:language"),
+KNOWNID(NAMESPACE_FILESYSTEM,          "namespace:filesystem"),
+KNOWNID(NAMESPACE_OTHERPROVIDERS,      "namespace:otherproviders"),
+
+KNOWNID(SYSTEM_SYSTEM,                 "system:system"),
+
+/* special solvable architectures */
+KNOWNID(ARCH_SRC,                      "src"),
+KNOWNID(ARCH_NOSRC,                    "nosrc"),
+KNOWNID(ARCH_NOARCH,                   "noarch"),
+KNOWNID(ARCH_ALL,                      "all"),
+KNOWNID(ARCH_ANY,                      "any"),
+
+/* the meta tags used in solv file storage */
+KNOWNID(REPOSITORY_SOLVABLES,          "repository:solvables"),
+KNOWNID(REPOSITORY_DELTAINFO,          "repository:deltainfo"),
+
+/* sub-repository information, they will get loaded on demand */
+KNOWNID(REPOSITORY_EXTERNAL,           "repository:external"),
+KNOWNID(REPOSITORY_KEYS,               "repository:keys"),
+KNOWNID(REPOSITORY_LOCATION,           "repository:location"),
+
+/* the known data types */
+KNOWNID(REPOKEY_TYPE_VOID,             "repokey:type:void"),
+KNOWNID(REPOKEY_TYPE_CONSTANT,         "repokey:type:constant"),
+KNOWNID(REPOKEY_TYPE_CONSTANTID,       "repokey:type:constantid"),
+KNOWNID(REPOKEY_TYPE_ID,               "repokey:type:id"),
+KNOWNID(REPOKEY_TYPE_NUM,              "repokey:type:num"),
+KNOWNID(REPOKEY_TYPE_DIR,              "repokey:type:dir"),
+KNOWNID(REPOKEY_TYPE_STR,              "repokey:type:str"),
+KNOWNID(REPOKEY_TYPE_BINARY,           "repokey:type:binary"),
+KNOWNID(REPOKEY_TYPE_IDARRAY,          "repokey:type:idarray"),
+KNOWNID(REPOKEY_TYPE_REL_IDARRAY,      "repokey:type:relidarray"),
+KNOWNID(REPOKEY_TYPE_DIRSTRARRAY,      "repokey:type:dirstrarray"),
+KNOWNID(REPOKEY_TYPE_DIRNUMNUMARRAY,   "repokey:type:dirnumnumarray"),
+KNOWNID(REPOKEY_TYPE_MD5,              "repokey:type:md5"),
+KNOWNID(REPOKEY_TYPE_SHA1,             "repokey:type:sha1"),
+KNOWNID(REPOKEY_TYPE_SHA224,           "repokey:type:sha224"),
+KNOWNID(REPOKEY_TYPE_SHA256,           "repokey:type:sha256"),
+KNOWNID(REPOKEY_TYPE_SHA384,           "repokey:type:sha384"),
+KNOWNID(REPOKEY_TYPE_SHA512,           "repokey:type:sha512"),
+KNOWNID(REPOKEY_TYPE_FIXARRAY,         "repokey:type:fixarray"),
+KNOWNID(REPOKEY_TYPE_FLEXARRAY,                "repokey:type:flexarray"),
+KNOWNID(REPOKEY_TYPE_DELETED,          "repokey:type:deleted"),        /* internal only */
+
+KNOWNID(SOLVABLE_SUMMARY,              "solvable:summary"),
+KNOWNID(SOLVABLE_DESCRIPTION,          "solvable:description"),
+KNOWNID(SOLVABLE_DISTRIBUTION,         "solvable:distribution"),
+KNOWNID(SOLVABLE_AUTHORS,              "solvable:authors"),
+KNOWNID(SOLVABLE_PACKAGER,             "solvable:packager"),
+KNOWNID(SOLVABLE_GROUP,                        "solvable:group"),
+KNOWNID(SOLVABLE_URL,                  "solvable:url"),
+KNOWNID(SOLVABLE_KEYWORDS,             "solvable:keywords"),
+KNOWNID(SOLVABLE_LICENSE,              "solvable:license"),
+KNOWNID(SOLVABLE_BUILDTIME,            "solvable:buildtime"),
+KNOWNID(SOLVABLE_BUILDHOST,            "solvable:buildhost"),
+KNOWNID(SOLVABLE_EULA,                 "solvable:eula"),
+KNOWNID(SOLVABLE_CPEID,                        "solvable:cpeid"),
+KNOWNID(SOLVABLE_MESSAGEINS,           "solvable:messageins"),
+KNOWNID(SOLVABLE_MESSAGEDEL,           "solvable:messagedel"),
+KNOWNID(SOLVABLE_INSTALLSIZE,          "solvable:installsize"),
+KNOWNID(SOLVABLE_DISKUSAGE,            "solvable:diskusage"),
+KNOWNID(SOLVABLE_FILELIST,             "solvable:filelist"),
+KNOWNID(SOLVABLE_INSTALLTIME,          "solvable:installtime"),
+KNOWNID(SOLVABLE_MEDIADIR,             "solvable:mediadir"),
+KNOWNID(SOLVABLE_MEDIAFILE,            "solvable:mediafile"),
+KNOWNID(SOLVABLE_MEDIANR,              "solvable:medianr"),
+KNOWNID(SOLVABLE_MEDIABASE,            "solvable:mediabase"),  /* <location xml:base=... > */
+KNOWNID(SOLVABLE_DOWNLOADSIZE,         "solvable:downloadsize"),
+KNOWNID(SOLVABLE_SOURCEARCH,           "solvable:sourcearch"),
+KNOWNID(SOLVABLE_SOURCENAME,           "solvable:sourcename"),
+KNOWNID(SOLVABLE_SOURCEEVR,            "solvable:sourceevr"),
+KNOWNID(SOLVABLE_ISVISIBLE,            "solvable:isvisible"),
+KNOWNID(SOLVABLE_TRIGGERS,             "solvable:triggers"),
+KNOWNID(SOLVABLE_CHECKSUM,             "solvable:checksum"),
+KNOWNID(SOLVABLE_PKGID,                        "solvable:pkgid"),      /* pkgid: md5sum over header + payload */
+KNOWNID(SOLVABLE_HDRID,                        "solvable:hdrid"),      /* hdrid: sha1sum over header only */
+KNOWNID(SOLVABLE_LEADSIGID,            "solvable:leadsigid"),  /* leadsigid: md5sum over lead + sigheader */
+
+KNOWNID(SOLVABLE_PATCHCATEGORY,                "solvable:patchcategory"),
+KNOWNID(SOLVABLE_HEADEREND,            "solvable:headerend"),
+KNOWNID(SOLVABLE_CHANGELOG,            "solvable:changelog"),
+KNOWNID(SOLVABLE_CHANGELOG_AUTHOR,     "solvable:changelog:author"),
+KNOWNID(SOLVABLE_CHANGELOG_TIME,       "solvable:changelog:time"),
+KNOWNID(SOLVABLE_CHANGELOG_TEXT,       "solvable:changelog:text"),
+KNOWNID(SOLVABLE_INSTALLSTATUS,                "solvable:installstatus"),      /* debian install status */
+KNOWNID(SOLVABLE_PREREQ_IGNOREINST,    "solvable:prereq_ignoreinst"),  /* ignore these pre-requires for installed packages */
+
+/* stuff for solvables of type pattern */
+KNOWNID(SOLVABLE_CATEGORY,             "solvable:category"),
+KNOWNID(SOLVABLE_INCLUDES,             "solvable:includes"),
+KNOWNID(SOLVABLE_EXTENDS,              "solvable:extends"),
+KNOWNID(SOLVABLE_ICON,                 "solvable:icon"),
+KNOWNID(SOLVABLE_ORDER,                        "solvable:order"),
+
+/* extra definitions for updates (i.e. patch: solvables) */
+KNOWNID(UPDATE_REBOOT,                 "update:reboot"),       /* reboot suggested (kernel update) */
+KNOWNID(UPDATE_RESTART,                        "update:restart"),      /* restart suggested (update stack update) */
+KNOWNID(UPDATE_RELOGIN,                        "update:relogin"),      /* relogin suggested */
+
+KNOWNID(UPDATE_MESSAGE,                        "update:message"),      /* informative message */
+KNOWNID(UPDATE_SEVERITY,               "update:severity"),     /* "Important", ...*/
+KNOWNID(UPDATE_RIGHTS,                 "update:rights"),       /* copyright */
+
+/* 'content' of patch, usually list of packages */
+KNOWNID(UPDATE_COLLECTION,             "update:collection"),          /*  "name evr arch" */
+KNOWNID(UPDATE_COLLECTION_NAME,                "update:collection:name"),     /*   name */
+KNOWNID(UPDATE_COLLECTION_EVR,         "update:collection:evr"),      /*   epoch:version-release */
+KNOWNID(UPDATE_COLLECTION_ARCH,                "update:collection:arch"),     /*   architecture */
+KNOWNID(UPDATE_COLLECTION_FILENAME,    "update:collection:filename"), /*   filename (of rpm) */
+KNOWNID(UPDATE_COLLECTION_FLAGS,       "update:collection:flags"),    /*   reboot(1)/restart(2) suggested if this rpm gets updated */
+
+KNOWNID(UPDATE_REFERENCE,              "update:reference"),            /* external references for the update */
+KNOWNID(UPDATE_REFERENCE_TYPE,         "update:reference:type"),       /*  type, e.g. 'bugzilla' or 'cve' */
+KNOWNID(UPDATE_REFERENCE_HREF,         "update:reference:href"),       /*  href, e.g. 'http://bugzilla...' */
+KNOWNID(UPDATE_REFERENCE_ID,           "update:reference:id"),         /*  id, e.g. bug number */
+KNOWNID(UPDATE_REFERENCE_TITLE,                "update:reference:title"),      /*  title, e.g. "the bla forz scribs on fuggle" */
+
+/* extra definitions for products */
+KNOWNID(PRODUCT_REFERENCEFILE,         "product:referencefile"),       /* installed product only */
+KNOWNID(PRODUCT_SHORTLABEL,            "product:shortlabel"),          /* not in repomd? */
+KNOWNID(PRODUCT_DISTPRODUCT,           "product:distproduct"),         /* obsolete */
+KNOWNID(PRODUCT_DISTVERSION,           "product:distversion"),         /* obsolete */
+KNOWNID(PRODUCT_TYPE,                  "product:type"),                /* e.g. 'base' */
+KNOWNID(PRODUCT_URL,                   "product:url"),
+KNOWNID(PRODUCT_URL_TYPE,              "product:url:type"),
+KNOWNID(PRODUCT_FLAGS,                 "product:flags"),               /* e.g. 'update', 'no_you' */
+KNOWNID(PRODUCT_PRODUCTLINE,           "product:productline"),         /* installed product only */
+KNOWNID(PRODUCT_REGISTER_TARGET,       "product:regtarget"),           /* installed and available product */
+KNOWNID(PRODUCT_REGISTER_FLAVOR,       "product:regflavor"),           /* installed and available product */
+KNOWNID(PRODUCT_REGISTER_RELEASE,      "product:regrelease"),          /* installed product only */
+KNOWNID(PRODUCT_UPDATES_REPOID,                "product:updates:repoid"),
+KNOWNID(PRODUCT_UPDATES,               "product:updates"),
+KNOWNID(PRODUCT_ENDOFLIFE,             "product:endoflife"),
+
+/* argh, should rename to repository and unify with REPOMD */
+KNOWNID(SUSETAGS_DATADIR,              "susetags:datadir"),
+KNOWNID(SUSETAGS_DESCRDIR,             "susetags:descrdir"),
+KNOWNID(SUSETAGS_DEFAULTVENDOR,                "susetags:defaultvendor"),
+KNOWNID(SUSETAGS_FILE,                 "susetags:file"),
+KNOWNID(SUSETAGS_FILE_NAME,            "susetags:file:name"),
+KNOWNID(SUSETAGS_FILE_TYPE,            "susetags:file:type"),
+KNOWNID(SUSETAGS_FILE_CHECKSUM,                "susetags:file:checksum"),
+KNOWNID(SUSETAGS_SHARE_NAME,           "susetags:share:name"),
+KNOWNID(SUSETAGS_SHARE_EVR,            "susetags:share:evr"),
+KNOWNID(SUSETAGS_SHARE_ARCH,           "susetags:share:arch"),
+
+KNOWNID(REPOSITORY_ADDEDFILEPROVIDES,  "repository:addedfileprovides"),        /* file provides already added to our solvables */
+KNOWNID(REPOSITORY_RPMDBCOOKIE,                "repository:rpmdbcookie"),      /* inode of the rpm database for rpm --rebuilddb detection */
+KNOWNID(REPOSITORY_FILTEREDFILELIST,   "repository:filteredfilelist"), /* filelist in repository is filtered */
+KNOWNID(REPOSITORY_TIMESTAMP,          "repository:timestamp"),        /* timestamp then the repository was generated */
+KNOWNID(REPOSITORY_EXPIRE,             "repository:expire"),           /* hint when the metadata could be outdated w/respect to generated timestamp */
+KNOWNID(REPOSITORY_UPDATES,            "repository:updates"),          /* which things does this repo provides updates for, if it does (array) (obsolete?) */
+KNOWNID(REPOSITORY_DISTROS,            "repository:distros"),          /* which products this repository is supposed to be for (array) */
+KNOWNID(REPOSITORY_PRODUCT_LABEL,       "repository:product:label"),
+KNOWNID(REPOSITORY_PRODUCT_CPEID,      "repository:product:cpeid"),
+KNOWNID(REPOSITORY_REPOID,             "repository:repoid"),           /* obsolete? */
+KNOWNID(REPOSITORY_KEYWORDS,           "repository:keywords"),         /* keyword (tags) for this repository */
+KNOWNID(REPOSITORY_REVISION,           "repository:revision"),         /* revision of the repository. arbitrary string */
+KNOWNID(REPOSITORY_TOOLVERSION,                "repository:toolversion"),
+
+KNOWNID(DELTA_PACKAGE_NAME,            "delta:pkgname"),
+KNOWNID(DELTA_PACKAGE_EVR,             "delta:pkgevr"),
+KNOWNID(DELTA_PACKAGE_ARCH,            "delta:pkgarch"),
+KNOWNID(DELTA_LOCATION_DIR,            "delta:locdir"),
+KNOWNID(DELTA_LOCATION_NAME,           "delta:locname"),
+KNOWNID(DELTA_LOCATION_EVR,            "delta:locevr"),
+KNOWNID(DELTA_LOCATION_SUFFIX,         "delta:locsuffix"),
+KNOWNID(DELTA_DOWNLOADSIZE,            "delta:downloadsize"),
+KNOWNID(DELTA_CHECKSUM,                        "delta:checksum"),
+KNOWNID(DELTA_BASE_EVR,                        "delta:baseevr"),
+KNOWNID(DELTA_SEQ_NAME,                        "delta:seqname"),
+KNOWNID(DELTA_SEQ_EVR,                 "delta:seqevr"),
+KNOWNID(DELTA_SEQ_NUM,                 "delta:seqnum"),
+KNOWNID(DELTA_LOCATION_BASE,           "delta:locbase"),       /* <location xml:base=... > */
+
+KNOWNID(REPOSITORY_REPOMD,             "repository:repomd"),
+KNOWNID(REPOSITORY_REPOMD_TYPE,                "repository:repomd:type"),
+KNOWNID(REPOSITORY_REPOMD_LOCATION,    "repository:repomd:location"),
+KNOWNID(REPOSITORY_REPOMD_TIMESTAMP,   "repository:repomd:timestamp"),
+KNOWNID(REPOSITORY_REPOMD_CHECKSUM,    "repository:repomd:checksum"),
+KNOWNID(REPOSITORY_REPOMD_OPENCHECKSUM,        "repository:repomd:openchecksum"),
+KNOWNID(REPOSITORY_REPOMD_SIZE,                "repository:repomd:size"),
+
+KNOWNID(PUBKEY_KEYID,                  "pubkey:keyid"),
+KNOWNID(PUBKEY_FINGERPRINT,            "pubkey:fingerprint"),
+KNOWNID(PUBKEY_EXPIRES,                        "pubkey:expires"),
+KNOWNID(PUBKEY_SIGNATURES,             "pubkey:signatures"),
+KNOWNID(PUBKEY_DATA,                   "pubkey:data"),
+KNOWNID(PUBKEY_SUBKEYOF,               "pubkey:subkeyof"),
+
+KNOWNID(SIGNATURE_ISSUER,              "signature:issuer"),
+KNOWNID(SIGNATURE_TIME,                        "signature:time"),
+KNOWNID(SIGNATURE_EXPIRES,             "signature:expires"),
+KNOWNID(SIGNATURE_DATA,                        "signature:data"),
+
+KNOWNID(ID_NUM_INTERNAL,               0)
+
+#ifdef KNOWNID_INITIALIZE
+};
+#else
+};
+#endif
+
+#undef KNOWNID
+
+#endif
+
+
diff --git a/libsolv-0.7.2/src/libsolv.ver b/libsolv-0.7.2/src/libsolv.ver
new file mode 100644 (file)
index 0000000..f0e86ff
--- /dev/null
@@ -0,0 +1,451 @@
+SOLV_1.0 {
+       global:
+               dataiterator_clonepos;
+               dataiterator_entersub;
+               dataiterator_free;
+               dataiterator_init;
+               dataiterator_init_clone;
+               dataiterator_jump_to_repo;
+               dataiterator_jump_to_solvid;
+               dataiterator_match;
+               dataiterator_prepend_keyname;
+               dataiterator_seek;
+               dataiterator_set_keyname;
+               dataiterator_set_match;
+               dataiterator_set_search;
+               dataiterator_setpos;
+               dataiterator_setpos_parent;
+               dataiterator_skip_attribute;
+               dataiterator_skip_repo;
+               dataiterator_skip_solvable;
+               dataiterator_step;
+               dataiterator_strdup;
+               datamatcher_free;
+               datamatcher_init;
+               datamatcher_match;
+               dirpool_add_dir;
+               dirpool_free;
+               dirpool_init;
+               dirpool_make_dirtraverse;
+               map_and;
+               map_subtract;
+               map_free;
+               map_grow;
+               map_init;
+               map_init_clone;
+               map_or;
+               policy_filter_unwanted;
+               policy_findupdatepackages;
+               policy_illegal2str;
+               policy_illegal_archchange;
+               policy_illegal_vendorchange;
+               policy_is_illegal;
+               pool_add_fileconflicts_deps;
+               pool_add_userinstalled_jobs;
+               pool_addfileprovides;
+               pool_addfileprovides_queue;
+               pool_addrelproviders;
+               pool_addvendorclass;
+               pool_alloctmpspace;
+               pool_arch2color_slow;
+               pool_bin2hex;
+               pool_calc_duchanges;
+               pool_calc_installsizechange;
+               pool_clear_pos;
+               pool_create;
+               pool_create_state_maps;
+               pool_createwhatprovides;
+               pool_debug;
+               pool_dep2str;
+               pool_error;
+               pool_errstr;
+               pool_evrcmp;
+               pool_evrcmp_str;
+               pool_evrmatch;
+               pool_flush_namespaceproviders;
+               pool_free;
+               pool_freeallrepos;
+               pool_freeidhashes;
+               pool_freetmpspace;
+               pool_freewhatprovides;
+               pool_get_flag;
+               pool_get_rootdir;
+               pool_id2evr;
+               pool_id2langid;
+               pool_id2rel;
+               pool_id2str;
+               pool_ids2whatprovides;
+               pool_intersect_evrs;
+               pool_isemptyupdatejob;
+               pool_job2solvables;
+               pool_job2str;
+               pool_lookup_bin_checksum;
+               pool_lookup_checksum;
+               pool_lookup_deltalocation;
+               pool_lookup_id;
+               pool_lookup_idarray;
+               pool_lookup_num;
+               pool_lookup_str;
+               pool_lookup_void;
+               pool_match_dep;
+               pool_match_nevr_rel;
+               pool_prepend_rootdir;
+               pool_prepend_rootdir_tmp;
+               pool_queuetowhatprovides;
+               pool_rel2id;
+               pool_search;
+               pool_selection2str;
+               pool_set_custom_vendorcheck;
+               pool_set_flag;
+               pool_set_installed;
+               pool_set_languages;
+               pool_set_rootdir;
+               pool_setarch;
+               pool_setarchpolicy;
+               pool_setdebugcallback;
+               pool_setdebuglevel;
+               pool_setdebugmask;
+               pool_setdisttype;
+               pool_setloadcallback;
+               pool_setnamespacecallback;
+               pool_setvendorclasses;
+               pool_shrink_rels;
+               pool_shrink_strings;
+               pool_solvable2str;
+               pool_str2id;
+               pool_strn2id;
+               pool_tmpappend;
+               pool_tmpjoin;
+               pool_trivial_installable;
+               pool_trivial_installable_multiversionmap;
+               pool_vendor2mask;
+               pool_whatmatchesdep;
+               pool_whatmatchessolvable;
+               pool_whatcontainsdep;
+               queue_alloc_one;
+               queue_alloc_one_head;
+               queue_delete;
+               queue_delete2;
+               queue_deleten;
+               queue_free;
+               queue_init;
+               queue_init_buffer;
+               queue_init_clone;
+               queue_insert;
+               queue_insert2;
+               queue_insertn;
+               queue_prealloc;
+               repo_add_deparray;
+               repo_add_idarray;
+               repo_add_poolstr_array;
+               repo_add_repodata;
+               repo_add_solv;
+               repo_add_solvable;
+               repo_add_solvable_block;
+               repo_add_solvable_block_before;
+               repo_addid;
+               repo_addid_dep;
+               repo_create;
+               repo_create_keyskip;
+               repo_disable_paging;
+               repo_empty;
+               repo_fix_conflicts;
+               repo_fix_supplements;
+               repo_free;
+               repo_free_solvable;
+               repo_free_solvable_block;
+               repo_id2repodata;
+               repo_internalize;
+               repo_last_repodata;
+               repo_lookup_bin_checksum;
+               repo_lookup_binary;
+               repo_lookup_checksum;
+               repo_lookup_deparray;
+               repo_lookup_id;
+               repo_lookup_idarray;
+               repo_lookup_num;
+               repo_lookup_str;
+               repo_lookup_type;
+               repo_lookup_void;
+               repo_reserve_ids;
+               repo_rewrite_suse_deps;
+               repo_search;
+               repo_set_deparray;
+               repo_set_id;
+               repo_set_idarray;
+               repo_set_num;
+               repo_set_poolstr;
+               repo_set_str;
+               repo_sidedata_create;
+               repo_unset;
+               repo_write;
+               repo_write_filtered;
+               repo_write_stdkeyfilter;
+               repodata_add_dirnumnum;
+               repodata_add_dirstr;
+               repodata_add_fixarray;
+               repodata_add_flexarray;
+               repodata_add_idarray;
+               repodata_add_poolstr_array;
+               repodata_chk2str;
+               repodata_create_stubs;
+               repodata_dir2str;
+               repodata_disable_paging;
+               repodata_empty;
+               repodata_extend;
+               repodata_extend_block;
+               repodata_free;
+               repodata_free_dircache;
+               repodata_free_schemahash;
+               repodata_freedata;
+               repodata_globalize_id;
+               repodata_initdata;
+               repodata_internalize;
+               repodata_key2id;
+               repodata_localize_id;
+               repodata_lookup_bin_checksum;
+               repodata_lookup_binary;
+               repodata_lookup_id;
+               repodata_lookup_idarray;
+               repodata_lookup_kv_uninternalized;
+               repodata_lookup_num;
+               repodata_lookup_str;
+               repodata_lookup_type;
+               repodata_lookup_void;
+               repodata_memused;
+               repodata_merge_attrs;
+               repodata_merge_some_attrs;
+               repodata_new_handle;
+               repodata_schema2id;
+               repodata_search;
+               repodata_search_arrayelement;
+               repodata_search_keyskip;
+               repodata_search_uninternalized;
+               repodata_set_binary;
+               repodata_set_bin_checksum;
+               repodata_set_checksum;
+               repodata_set_constant;
+               repodata_set_constantid;
+               repodata_set_deltalocation;
+               repodata_set_filelisttype;
+               repodata_set_id;
+               repodata_set_idarray;
+               repodata_set_location;
+               repodata_set_num;
+               repodata_set_poolstr;
+               repodata_set_sourcepkg;
+               repodata_set_str;
+               repodata_set_void;
+               repodata_setpos_kv;
+               repodata_shrink;
+               repodata_str2dir;
+               repodata_stringify;
+               repodata_swap_attrs;
+               repodata_translate_dir_slow;
+               repodata_translate_id;
+               repodata_unset;
+               repodata_unset_uninternalized;
+               repodata_write;
+               repodata_write_filtered;
+               repopagestore_compress_page;
+               repowriter_create;
+               repowriter_free;
+               repowriter_set_flags;
+               repowriter_set_keyfilter;
+               repowriter_set_keyqueue;
+               repowriter_set_repodatarange;
+               repowriter_set_solvablerange;
+               repowriter_write;
+               selection_add;
+               selection_filter;
+               selection_make;
+               selection_make_matchdepid;
+               selection_make_matchdeps;
+               selection_make_matchsolvable;
+               selection_make_matchsolvablelist;
+               selection_solvables;
+               solv_bin2hex;
+               solv_calloc;
+               solv_chksum_add;
+               solv_chksum_cmp;
+               solv_chksum_create;
+               solv_chksum_create_clone;
+               solv_chksum_create_from_bin;
+               solv_chksum_free;
+               solv_chksum_get;
+               solv_chksum_get_type;
+               solv_chksum_isfinished;
+               solv_chksum_len;
+               solv_chksum_str2type;
+               solv_chksum_type2str;
+               solv_depmarker;
+               solv_dupappend;
+               solv_dupjoin;
+               solv_extend_realloc;
+               solv_free;
+               solv_hex2bin;
+               solv_latin1toutf8;
+               solv_malloc;
+               solv_malloc2;
+               solv_oom;
+               solv_realloc;
+               solv_realloc2;
+               solv_replacebadutf8;
+               solv_sort;
+               solv_strdup;
+               solv_timems;
+               solv_validutf8;
+               solv_vercmp;
+               solv_vercmp_deb;
+               solv_vercmp_haiku;
+               solv_vercmp_rpm;
+               solv_vercmp_rpm_notilde;
+               solv_version;
+               solv_version_major;
+               solv_version_minor;
+               solv_version_patch;
+               solvable_add_deparray;
+               solvable_add_idarray;
+               solvable_add_poolstr_array;
+               solvable_get_location;
+               solvable_identical;
+               solvable_lookup_bin_checksum;
+               solvable_lookup_bool;
+               solvable_lookup_checksum;
+               solvable_lookup_deparray;
+               solvable_lookup_id;
+               solvable_lookup_idarray;
+               solvable_lookup_location;
+               solvable_lookup_num;
+               solvable_lookup_sizek;
+               solvable_lookup_sourcepkg;
+               solvable_lookup_str;
+               solvable_lookup_str_lang;
+               solvable_lookup_str_poollang;
+               solvable_lookup_type;
+               solvable_lookup_void;
+               solvable_matchesdep;
+               solvable_selfprovidedep;
+               solvable_set_deparray;
+               solvable_set_id;
+               solvable_set_idarray;
+               solvable_set_num;
+               solvable_set_poolstr;
+               solvable_set_str;
+               solvable_trivial_installable_map;
+               solvable_trivial_installable_queue;
+               solvable_trivial_installable_repo;
+               solvable_unset;
+               solver_allruleinfos;
+               solver_alternative2str;
+               solver_alternatives_count;
+               solver_calc_duchanges;
+               solver_calc_installsizechange;
+               solver_calculate_multiversionmap;
+               solver_calculate_noobsmap;
+               solver_create;
+               solver_create_state_maps;
+               solver_create_transaction;
+               solver_describe_decision;
+               solver_describe_weakdep_decision;
+               solver_findallproblemrules;
+               solver_findproblemrule;
+               solver_free;
+               solver_freedupmaps;
+               solver_get_alternative;
+               solver_get_decisionblock;
+               solver_get_decisionlevel;
+               solver_get_decisionqueue;
+               solver_get_flag;
+               solver_get_lastdecisionblocklevel;
+               solver_get_orphaned;
+               solver_get_recommendations;
+               solver_get_unneeded;
+               solver_get_userinstalled;
+               solver_next_problem;
+               solver_next_solution;
+               solver_next_solutionelement;
+               solver_prepare_solutions;
+               solver_printallsolutions;
+               solver_printcompleteprobleminfo;
+               solver_printdecisionq;
+               solver_printdecisions;
+               solver_printproblem;
+               solver_printprobleminfo;
+               solver_printproblemruleinfo;
+               solver_printrule;
+               solver_printruleclass;
+               solver_printruleelement;
+               solver_printsolution;
+               solver_printtrivial;
+               solver_printwatches;
+               solver_problem2str;
+               solver_problem_count;
+               solver_problemruleinfo2str;
+               solver_rule2job;
+               solver_rule2jobidx;
+               solver_rule2pkgrule;
+               solver_rule2rules;
+               solver_rule2solvable;
+               solver_ruleclass;
+               solver_ruleinfo;
+               solver_ruleliterals;
+               solver_rulecmp;
+               solver_select2str;
+               solver_set_flag;
+               solver_solution_count;
+               solver_solutionelement2str;
+               solver_solutionelement_count;
+               solver_solutionelement_internalid;
+               solver_solutionelement_extrajobflags;
+               solver_solve;
+               solver_take_solution;
+               solver_take_solutionelement;
+               solver_trivial_installable;
+               solver_unifyrules;
+               stringpool_clone;
+               stringpool_free;
+               stringpool_freehash;
+               stringpool_init;
+               stringpool_init_empty;
+               stringpool_shrink;
+               stringpool_str2id;
+               stringpool_strn2id;
+               transaction_add_obsoleted;
+               transaction_all_obs_pkgs;
+               transaction_calc_duchanges;
+               transaction_calc_installsizechange;
+               transaction_check_order;
+               transaction_classify;
+               transaction_classify_pkgs;
+               transaction_create;
+               transaction_create_clone;
+               transaction_create_decisionq;
+               transaction_free;
+               transaction_free_orderdata;
+               transaction_installedresult;
+               transaction_obs_pkg;
+               transaction_order;
+               transaction_order_add_choices;
+               transaction_order_get_cycle;
+               transaction_order_get_cycleids;
+               transaction_print;
+               transaction_type;
+       local:
+               *;
+};
+
+SOLV_1.1 {
+               pool_best_solvables;
+               solver_get_cleandeps;
+} SOLV_1.0;
+
+SOLV_1.2 {
+               map_invertall;
+               pool_set_whatprovides;
+               selection_subtract;
+} SOLV_1.1;
+
+SOLV_1.3 {
+               repodata_set_kv;
+} SOLV_1.2;
diff --git a/libsolv-0.7.2/src/linkedpkg.c b/libsolv-0.7.2/src/linkedpkg.c
new file mode 100644 (file)
index 0000000..5912f98
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2013, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * linkedpkg.c
+ *
+ * Linked packages are "pseudo" packages that are bound to real packages but
+ * contain different information (name/summary/description). They are normally
+ * somehow generated from the real packages, either when the repositories are
+ * created or automatically from the packages by looking at the provides.
+ *
+ * We currently support:
+ *
+ * application:
+ *   created from AppStream appdata xml in the repository (which is generated
+ *   from files in /usr/share/appdata)
+ *
+ * product:
+ *   created from product data in the repository (which is generated from files
+ *   in /etc/products.d). In the future we may switch to using product()
+ *   provides of packages.
+ *
+ * pattern:
+ *   created from pattern() provides of packages.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "solver.h"
+#include "evr.h"
+#include "bitmap.h"
+#include "linkedpkg.h"
+
+#ifdef ENABLE_LINKED_PKGS
+
+void
+find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
+{
+  Id req = 0;
+  Id prv = 0;
+  Id p, pp;
+  Id pkgname = 0, appdataid = 0;
+
+  /* find appdata requires */
+  if (s->requires)
+    {
+      Id *reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)            /* go through all requires */
+       {
+         if (ISRELDEP(req))
+           continue;
+         if (!strncmp("appdata(", pool_id2str(pool, req), 8))
+           appdataid = req;
+         else
+           pkgname = req;
+       }
+    }
+  req = appdataid ? appdataid : pkgname;
+  if (!req)
+    return;
+  /* find application-appdata provides */
+  if (s->provides)
+    {
+      Id *prvp = s->repo->idarraydata + s->provides;
+      const char *reqs = pool_id2str(pool, req);
+      const char *prvs;
+      while ((prv = *prvp++) != 0)            /* go through all provides */
+       {
+         if (ISRELDEP(prv))
+           continue;
+         prvs = pool_id2str(pool, prv);
+         if (strncmp("application-appdata(", prvs, 20))
+           continue;
+         if (appdataid)
+           {
+             if (!strcmp(prvs + 12, reqs))
+               break;
+           }
+         else
+           {
+             int reqsl = strlen(reqs);
+             if (!strncmp(prvs + 20, reqs, reqsl) && !strcmp(prvs + 20 + reqsl, ")"))
+               break;
+           }
+       }
+    }
+  if (!prv)
+    return;    /* huh, no provides found? */
+  /* now link em */
+  FOR_PROVIDES(p, pp, req)
+    if (pool->solvables[p].repo == s->repo)
+      if (!pkgname || pool->solvables[p].name == pkgname)
+        queue_push(qr, p);
+  if (!qr->count && pkgname && appdataid)
+    {
+      /* huh, no matching package? try without pkgname filter */
+      FOR_PROVIDES(p, pp, req)
+       if (pool->solvables[p].repo == s->repo)
+          queue_push(qr, p);
+    }
+  if (qp)
+    {
+      FOR_PROVIDES(p, pp, prv)
+       if (pool->solvables[p].repo == s->repo)
+         queue_push(qp, p);
+    }
+  if (reqidp)
+    *reqidp = req;
+  if (prvidp)
+    *prvidp = prv;
+}
+
+void
+find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
+{
+  Id p, pp, namerelid;
+  char *str;
+  unsigned int sbt = 0;
+
+  /* search for project requires */
+  namerelid = 0;
+  if (s->requires)
+    {
+      Id req, *reqp = s->repo->idarraydata + s->requires;
+      const char *nn = pool_id2str(pool, s->name);
+      int nnl = strlen(nn);
+      while ((req = *reqp++) != 0)            /* go through all requires */
+       if (ISRELDEP(req))
+         {
+           const char *rn;
+           Reldep *rd = GETRELDEP(pool, req);
+           if (rd->flags != REL_EQ || rd->evr != s->evr)
+             continue;
+           rn = pool_id2str(pool, rd->name);
+           if (!strncmp(rn, "product(", 8) && !strncmp(rn + 8, nn + 8, nnl - 8) && !strcmp( rn + nnl, ")"))
+             {
+               namerelid = req;
+               break;
+             }
+         }
+    }
+  if (!namerelid)
+    {
+      /* too bad. construct from scratch */
+      str = pool_tmpjoin(pool, pool_id2str(pool, s->name), ")", 0);
+      str[7] = '(';
+      namerelid = pool_rel2id(pool, pool_str2id(pool, str, 1), s->evr, REL_EQ, 1);
+    }
+  FOR_PROVIDES(p, pp, namerelid)
+    {
+      Solvable *ps = pool->solvables + p;
+      if (ps->repo != s->repo || ps->arch != s->arch)
+       continue;
+      queue_push(qr, p);
+    }
+  if (qr->count > 1)
+    {
+      /* multiple providers. try buildtime filter */
+      sbt = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
+      if (sbt)
+       {
+         unsigned int bt;
+         int i, j;
+         int filterqp = 1;
+         for (i = j = 0; i < qr->count; i++)
+           {
+             bt = solvable_lookup_num(pool->solvables + qr->elements[i], SOLVABLE_BUILDTIME, 0);
+             if (!bt)
+               filterqp = 0;   /* can't filter */
+             if (!bt || bt == sbt)
+               qr->elements[j++] = qr->elements[i];
+           }
+         if (j)
+           qr->count = j;
+         if (!j || !filterqp)
+           sbt = 0;    /* filter failed */
+       }
+    }
+  if (!qr->count && s->repo == pool->installed)
+    {
+      /* oh no! Look up reference file */
+      Dataiterator di;
+      const char *refbasename = solvable_lookup_str(s, PRODUCT_REFERENCEFILE);
+      if (refbasename)
+       {
+         dataiterator_init(&di, pool, s->repo, 0, SOLVABLE_FILELIST, refbasename, SEARCH_STRING);
+         while (dataiterator_step(&di))
+           {
+             if (di.key->type != REPOKEY_TYPE_DIRSTRARRAY)
+               continue;
+             if (strcmp(repodata_dir2str(di.data, di.kv.id, 0), "/etc/products.d") != 0)
+               continue;
+             queue_push(qr, di.solvid);
+           }
+         dataiterator_free(&di);
+         if (qp)
+           {
+             dataiterator_init(&di, pool, s->repo, 0, PRODUCT_REFERENCEFILE, refbasename, SEARCH_STRING);
+             while (dataiterator_step(&di))
+               queue_push(qp, di.solvid);
+             dataiterator_free(&di);
+           }
+       }
+    }
+  else if (qp)
+    {
+      /* find qp */
+      FOR_PROVIDES(p, pp, s->name)
+       {
+         Solvable *ps = pool->solvables + p;
+         if (s->name != ps->name || ps->repo != s->repo || ps->arch != s->arch || s->evr != ps->evr)
+           continue;
+         if (sbt && solvable_lookup_num(ps, SOLVABLE_BUILDTIME, 0) != sbt)
+           continue;
+         queue_push(qp, p);
+       }
+    }
+  if (reqidp)
+    *reqidp = namerelid;
+  if (prvidp)
+    *prvidp = solvable_selfprovidedep(s);
+}
+
+void
+find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
+{
+  Id p, pp, *pr, apevr = 0, aprel = 0;
+
+  /* check if autopattern */
+  if (!s->provides)
+    return;
+  for (pr = s->repo->idarraydata + s->provides; (p = *pr++) != 0; )
+    if (ISRELDEP(p))
+      {
+       Reldep *rd = GETRELDEP(pool, p);
+       if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
+         {
+           aprel = p;
+           apevr = rd->evr;
+           break;
+         }
+      }
+  if (!apevr)
+    return;
+  FOR_PROVIDES(p, pp, apevr)
+    {
+      Solvable *s2 = pool->solvables + p;
+      if (s2->repo == s->repo && s2->name == apevr && s2->evr == s->evr && s2->vendor == s->vendor)
+        queue_push(qr, p);
+    }
+  if (qp)
+    {
+      FOR_PROVIDES(p, pp, aprel)
+       {
+         Solvable *s2 = pool->solvables + p;
+         if (s2->repo == s->repo && s2->evr == s->evr && s2->vendor == s->vendor)
+           queue_push(qp, p);
+       }
+    }
+  if (reqidp)
+    *reqidp = apevr;
+  if (prvidp)
+    *prvidp = aprel;
+}
+
+/* the following two functions are used in solvable_lookup_str_base to do
+ * translated lookups on the product/pattern packages
+ */
+Id
+find_autopattern_name(Pool *pool, Solvable *s)
+{
+  Id prv, *prvp;
+  if (!s->provides)
+    return 0;
+  for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
+    if (ISRELDEP(prv))
+      {
+        Reldep *rd = GETRELDEP(pool, prv);
+        if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autopattern()"))
+          return strncmp(pool_id2str(pool, rd->evr), "pattern:", 8) != 0 ? rd->evr : 0;
+      }
+  return 0;
+}
+
+Id
+find_autoproduct_name(Pool *pool, Solvable *s)
+{
+  Id prv, *prvp;
+  if (!s->provides)
+    return 0;
+  for (prvp = s->repo->idarraydata + s->provides; (prv = *prvp++) != 0; )
+    if (ISRELDEP(prv))
+      {
+        Reldep *rd = GETRELDEP(pool, prv);
+        if (rd->flags == REL_EQ && !strcmp(pool_id2str(pool, rd->name), "autoproduct()"))
+          return strncmp(pool_id2str(pool, rd->evr), "product:", 8) != 0 ? rd->evr : 0;
+      }
+  return 0;
+}
+
+void
+find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp)
+{
+  const char *name = pool_id2str(pool, s->name);
+  if (name[0] == 'a' && !strncmp("application:", name, 12))
+    find_application_link(pool, s, reqidp, qr, prvidp, qp);
+  else if (name[0] == 'p' && !strncmp("pattern:", name, 7))
+    find_pattern_link(pool, s, reqidp, qr, prvidp, qp);
+  else if (name[0] == 'p' && !strncmp("product:", name, 8))
+    find_product_link(pool, s, reqidp, qr, prvidp, qp);
+}
+
+static int
+name_min_max(Pool *pool, Solvable *s, Id *namep, Id *minp, Id *maxp)
+{
+  Queue q;
+  Id qbuf[4];
+  Id name, min, max;
+  int i;
+
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  find_package_link(pool, s, 0, &q, 0, 0);
+  if (!q.count)
+    {
+      queue_free(&q);
+      return 0;
+    }
+  s = pool->solvables + q.elements[0];
+  name = s->name;
+  min = max = s->evr;
+  for (i = 1; i < q.count; i++)
+    {
+      s = pool->solvables + q.elements[i];
+      if (s->name != name)
+       {
+          queue_free(&q);
+         return 0;
+       }
+      if (s->evr == min || s->evr == max)
+       continue;
+      if (pool_evrcmp(pool, min, s->evr, EVRCMP_COMPARE) >= 0)
+       min = s->evr;
+      else if (min == max || pool_evrcmp(pool, max, s->evr, EVRCMP_COMPARE) <= 0)
+       max = s->evr;
+    }
+  queue_free(&q);
+  *namep = name;
+  *minp = min;
+  *maxp = max;
+  return 1;
+}
+
+int
+pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  Id name1, evrmin1, evrmax1;
+  Id name2, evrmin2, evrmax2;
+
+  if (s1->name != s2->name)
+    return 0;  /* can't compare */
+  if (!name_min_max(pool, s1, &name1, &evrmin1, &evrmax1))
+    return 0;
+  if (!name_min_max(pool, s2, &name2, &evrmin2, &evrmax2))
+    return 0;
+  /* compare linked names */
+  if (name1 != name2)
+    return 0;
+  if (evrmin1 == evrmin2 && evrmax1 == evrmax2)
+    return 0;
+  /* now compare evr intervals */
+  if (evrmin1 == evrmax1 && evrmin2 == evrmax2)
+    return pool_evrcmp(pool, evrmin1, evrmax2, EVRCMP_COMPARE);
+  if (evrmin1 != evrmax2 && pool_evrcmp(pool, evrmin1, evrmax2, EVRCMP_COMPARE) > 0)
+    return 1;
+  if (evrmax1 != evrmin2 && pool_evrcmp(pool, evrmax1, evrmin2, EVRCMP_COMPARE) < 0)
+    return -1;
+  return 0;
+}
+
+void
+extend_updatemap_to_buddies(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Solvable *s;
+  int p, ip;
+
+  if (!installed)
+    return;
+  if (!solv->updatemap.size || !solv->instbuddy)
+    return;
+  FOR_REPO_SOLVABLES(installed, p, s)
+    {
+      if (!MAPTST(&solv->updatemap, p - installed->start))
+       continue;
+      if ((ip = solv->instbuddy[p - installed->start]) <= 1)
+       continue;
+      if (!has_package_link(pool, s))  /* only look at pseudo -> real relations */
+       continue;
+      if (ip < installed->start || ip >= installed->end || pool->solvables[ip].repo != installed)
+       continue;                       /* just in case... */
+      MAPSET(&solv->updatemap, ip - installed->start);
+    }
+}
+
+#endif
diff --git a/libsolv-0.7.2/src/linkedpkg.h b/libsolv-0.7.2/src/linkedpkg.h
new file mode 100644 (file)
index 0000000..51b82a5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * linkedpkg.h (internal)
+ */
+
+#ifndef LIBSOLV_LINKEDPKG_H
+#define LIBSOLV_LINKEDPKG_H
+
+static inline int
+has_package_link(Pool *pool, Solvable *s)
+{
+  const char *name = pool_id2str(pool, s->name);
+  if (name[0] == 'a' && !strncmp("application:", name, 12))
+    return 1;
+  if (name[0] == 'p' && !strncmp("pattern:", name, 8))
+    return 1;
+  if (name[0] == 'p' && !strncmp("product:", name, 8))
+    return 1;
+  return 0;
+}
+
+extern void find_application_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
+extern void find_product_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
+extern void find_pattern_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
+
+extern Id find_autopattern_name(Pool *pool, Solvable *s);
+extern Id find_autoproduct_name(Pool *pool, Solvable *s);
+
+/* generic */
+extern void find_package_link(Pool *pool, Solvable *s, Id *reqidp, Queue *qr, Id *prvidp, Queue *qp);
+extern int pool_link_evrcmp(Pool *pool, Solvable *s1, Solvable *s2);
+extern void extend_updatemap_to_buddies(Solver *solv);
+
+#endif
diff --git a/libsolv-0.7.2/src/md5.c b/libsolv-0.7.2/src/md5.c
new file mode 100644 (file)
index 0000000..0431b50
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security,
+ * Inc. MD5 Message-Digest Algorithm.
+ *
+ * Written by Solar Designer <solar@openwall.com> in 2001, and placed in
+ * the public domain.
+ *
+ * This differs from Colin Plumb's older public domain implementation in
+ * that no 32-bit integer data type is required, there's no compile-time
+ * endianness configuration, and the function prototypes match OpenSSL's.
+ * The primary goals are portability and ease of use.
+ *
+ * This implementation is meant to be fast, but not as fast as possible.
+ * Some known optimizations are not included to reduce source code size
+ * and avoid compile-time configuration.
+ */
+
+#include <string.h>
+#include "md5.h"
+
+
+/*
+ * The basic MD5 functions.
+ *
+ * F is optimized compared to its RFC 1321 definition just like in Colin
+ * Plumb's implementation.
+ */
+#define F(x, y, z)                     ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)                     ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z)                     ((x) ^ (y) ^ (z))
+#define I(x, y, z)                     ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+       (a) += f((b), (c), (d)) + (x) + (t); \
+       (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+       (a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures which tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__vax__)
+#define SET(n) \
+       (*(MD5_u32plus *)&ptr[(n) * 4])
+#define GET(n) \
+       SET(n)
+#else
+#define SET(n) \
+       (ctx->block[(n)] = \
+       (MD5_u32plus)ptr[(n) * 4] | \
+       ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+       ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+       ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+       (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There're no alignment requirements.
+ */
+static void *body(MD5_CTX *ctx, void *data, unsigned long size)
+{
+       unsigned char *ptr;
+       MD5_u32plus a, b, c, d;
+       MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+       ptr = data;
+
+       a = ctx->a;
+       b = ctx->b;
+       c = ctx->c;
+       d = ctx->d;
+
+       do {
+               saved_a = a;
+               saved_b = b;
+               saved_c = c;
+               saved_d = d;
+
+/* Round 1 */
+               STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+               STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+               STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+               STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+               STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+               STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+               STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+               STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+               STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+               STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+               STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+               STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+               STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+               STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+               STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+               STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+               STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+               STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+               STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+               STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+               STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+               STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+               STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+               STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+               STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+               STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+               STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+               STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+               STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+               STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+               STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+               STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+               STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+               STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
+               STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+               STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
+               STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+               STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+               STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+               STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
+               STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+               STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
+               STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+               STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
+               STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+               STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
+               STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+               STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+               STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+               STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+               STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+               STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+               STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+               STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+               STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+               STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+               STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+               STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+               STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+               STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+               STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+               STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+               STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+               STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+               a += saved_a;
+               b += saved_b;
+               c += saved_c;
+               d += saved_d;
+
+               ptr += 64;
+       } while (size -= 64);
+
+       ctx->a = a;
+       ctx->b = b;
+       ctx->c = c;
+       ctx->d = d;
+
+       return ptr;
+}
+
+void solv_MD5_Init(MD5_CTX *ctx)
+{
+       ctx->a = 0x67452301;
+       ctx->b = 0xefcdab89;
+       ctx->c = 0x98badcfe;
+       ctx->d = 0x10325476;
+
+       ctx->lo = 0;
+       ctx->hi = 0;
+}
+
+void solv_MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
+{
+       MD5_u32plus saved_lo;
+       unsigned long used, free;
+
+       saved_lo = ctx->lo;
+       if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+               ctx->hi++;
+       ctx->hi += size >> 29;
+
+       used = saved_lo & 0x3f;
+
+       if (used) {
+               free = 64 - used;
+
+               if (size < free) {
+                       memcpy(&ctx->buffer[used], data, size);
+                       return;
+               }
+
+               memcpy(&ctx->buffer[used], data, free);
+               data = (unsigned char *)data + free;
+               size -= free;
+               body(ctx, ctx->buffer, 64);
+       }
+
+       if (size >= 64) {
+               data = body(ctx, data, size & ~(unsigned long)0x3f);
+               size &= 0x3f;
+       }
+
+       memcpy(ctx->buffer, data, size);
+}
+
+void solv_MD5_Final(unsigned char *result, MD5_CTX *ctx)
+{
+       unsigned long used, free;
+
+       used = ctx->lo & 0x3f;
+
+       ctx->buffer[used++] = 0x80;
+
+       free = 64 - used;
+
+       if (free < 8) {
+               memset(&ctx->buffer[used], 0, free);
+               body(ctx, ctx->buffer, 64);
+               used = 0;
+               free = 64;
+       }
+
+       memset(&ctx->buffer[used], 0, free - 8);
+
+       ctx->lo <<= 3;
+       ctx->buffer[56] = ctx->lo;
+       ctx->buffer[57] = ctx->lo >> 8;
+       ctx->buffer[58] = ctx->lo >> 16;
+       ctx->buffer[59] = ctx->lo >> 24;
+       ctx->buffer[60] = ctx->hi;
+       ctx->buffer[61] = ctx->hi >> 8;
+       ctx->buffer[62] = ctx->hi >> 16;
+       ctx->buffer[63] = ctx->hi >> 24;
+
+       body(ctx, ctx->buffer, 64);
+
+       result[0] = ctx->a;
+       result[1] = ctx->a >> 8;
+       result[2] = ctx->a >> 16;
+       result[3] = ctx->a >> 24;
+       result[4] = ctx->b;
+       result[5] = ctx->b >> 8;
+       result[6] = ctx->b >> 16;
+       result[7] = ctx->b >> 24;
+       result[8] = ctx->c;
+       result[9] = ctx->c >> 8;
+       result[10] = ctx->c >> 16;
+       result[11] = ctx->c >> 24;
+       result[12] = ctx->d;
+       result[13] = ctx->d >> 8;
+       result[14] = ctx->d >> 16;
+       result[15] = ctx->d >> 24;
+
+       memset(ctx, 0, sizeof(*ctx));
+}
diff --git a/libsolv-0.7.2/src/md5.h b/libsolv-0.7.2/src/md5.h
new file mode 100644 (file)
index 0000000..54533c7
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security,
+ * Inc. MD5 Message-Digest Algorithm.
+ *
+ * Written by Solar Designer <solar@openwall.com> in 2001, and placed in
+ * the public domain.  See md5.c for more information.
+ */
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned long MD5_u32plus;
+
+typedef struct {
+       MD5_u32plus lo, hi;
+       MD5_u32plus a, b, c, d;
+       unsigned char buffer[64];
+       MD5_u32plus block[16];
+} MD5_CTX;
+
+extern void solv_MD5_Init(MD5_CTX *ctx);
+extern void solv_MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);
+extern void solv_MD5_Final(unsigned char *result, MD5_CTX *ctx);
diff --git a/libsolv-0.7.2/src/order.c b/libsolv-0.7.2/src/order.c
new file mode 100644 (file)
index 0000000..c0cc07f
--- /dev/null
@@ -0,0 +1,1405 @@
+/*
+ * Copyright (c) 2007-2015, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * order.c
+ *
+ * Transaction ordering
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "transaction.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+
+struct s_TransactionElement {
+  Id p;                /* solvable id */
+  Id edges;    /* pointer into edges data */
+  Id mark;
+};
+
+struct s_TransactionOrderdata {
+  struct s_TransactionElement *tes;
+  int ntes;
+  Id *invedgedata;
+  int ninvedgedata;
+  Queue *cycles;
+};
+
+#define TYPE_BROKEN    (1<<0)
+#define TYPE_CON       (1<<1)
+
+#define TYPE_REQ_P     (1<<2)
+#define TYPE_PREREQ_P  (1<<3)
+
+#define TYPE_SUG       (1<<4)
+#define TYPE_REC       (1<<5)
+
+#define TYPE_REQ       (1<<6)
+#define TYPE_PREREQ    (1<<7)
+
+#define TYPE_CYCLETAIL  (1<<16)
+#define TYPE_CYCLEHEAD  (1<<17)
+
+#define EDGEDATA_BLOCK 127
+
+void
+transaction_clone_orderdata(Transaction *trans, Transaction *srctrans)
+{
+  struct s_TransactionOrderdata *od = srctrans->orderdata;
+  if (!od)
+    return;
+  trans->orderdata = solv_calloc(1, sizeof(*trans->orderdata));
+  trans->orderdata->tes = solv_memdup2(od->tes, od->ntes, sizeof(*od->tes));
+  trans->orderdata->ntes = od->ntes;
+  trans->orderdata->invedgedata = solv_memdup2(od->invedgedata, od->ninvedgedata, sizeof(Id));
+  trans->orderdata->ninvedgedata = od->ninvedgedata;
+  if (od->cycles)
+    {
+      trans->orderdata->cycles = solv_calloc(1, sizeof(Queue));
+      queue_init_clone(trans->orderdata->cycles, od->cycles);
+    }
+}
+
+void
+transaction_free_orderdata(Transaction *trans)
+{
+  if (trans->orderdata)
+    {
+      struct s_TransactionOrderdata *od = trans->orderdata;
+      od->tes = solv_free(od->tes);
+      od->invedgedata = solv_free(od->invedgedata);
+      if (od->cycles)
+       {
+         queue_free(od->cycles);
+         od->cycles = solv_free(od->cycles);
+       }
+      trans->orderdata = solv_free(trans->orderdata);
+    }
+}
+
+struct orderdata {
+  Transaction *trans;
+  struct s_TransactionElement *tes;
+  int ntes;
+  Id *edgedata;
+  int nedgedata;
+  Id *invedgedata;
+
+  Queue cycles;
+  Queue cyclesdata;
+  int ncycles;
+};
+
+static int
+addteedge(struct orderdata *od, int from, int to, int type)
+{
+  int i;
+  struct s_TransactionElement *te;
+
+  if (from == to)
+    return 0;
+
+  /* printf("edge %d(%s) -> %d(%s) type %x\n", from, pool_solvid2str(pool, od->tes[from].p), to, pool_solvid2str(pool, od->tes[to].p), type); */
+
+  te = od->tes + from;
+  for (i = te->edges; od->edgedata[i]; i += 2)
+    if (od->edgedata[i] == to)
+      break;
+  /* test of brokenness */
+  if (type == TYPE_BROKEN)
+    return od->edgedata[i] && (od->edgedata[i + 1] & TYPE_BROKEN) != 0 ? 1 : 0;
+  if (od->edgedata[i])
+    {
+      od->edgedata[i + 1] |= type;
+      return 0;
+    }
+  if (i + 1 == od->nedgedata)
+    {
+      /* printf("tail add %d\n", i - te->edges); */
+      if (!i)
+       te->edges = ++i;
+      od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3, sizeof(Id), EDGEDATA_BLOCK);
+    }
+  else
+    {
+      /* printf("extend %d\n", i - te->edges); */
+      od->edgedata = solv_extend(od->edgedata, od->nedgedata, 3 + (i - te->edges), sizeof(Id), EDGEDATA_BLOCK);
+      if (i > te->edges)
+       memcpy(od->edgedata + od->nedgedata, od->edgedata + te->edges, sizeof(Id) * (i - te->edges));
+      i = od->nedgedata + (i - te->edges);
+      te->edges = od->nedgedata;
+    }
+  od->edgedata[i] = to;
+  od->edgedata[i + 1] = type;
+  od->edgedata[i + 2] = 0;     /* end marker */
+  od->nedgedata = i + 3;
+  return 0;
+}
+
+static int
+addedge(struct orderdata *od, Id from, Id to, int type)
+{
+  Transaction *trans = od->trans;
+  Pool *pool = trans->pool;
+  Solvable *s;
+  struct s_TransactionElement *te;
+  int i;
+
+  /* printf("addedge %d %d type %d\n", from, to, type); */
+  s = pool->solvables + from;
+  if (s->repo == pool->installed && trans->transaction_installed[from - pool->installed->start])
+    {
+      /* obsolete, map to install */
+      if (trans->transaction_installed[from - pool->installed->start] > 0)
+       from = trans->transaction_installed[from - pool->installed->start];
+      else
+       {
+         int ret = 0;
+         Queue ti;
+         Id tibuf[5];
+
+         queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+         transaction_all_obs_pkgs(trans, from, &ti);
+         for (i = 0; i < ti.count; i++)
+           ret |= addedge(od, ti.elements[i], to, type);
+         queue_free(&ti);
+         return ret;
+       }
+    }
+  s = pool->solvables + to;
+  if (s->repo == pool->installed && trans->transaction_installed[to - pool->installed->start])
+    {
+      /* obsolete, map to install */
+      if (trans->transaction_installed[to - pool->installed->start] > 0)
+       to = trans->transaction_installed[to - pool->installed->start];
+      else
+       {
+         int ret = 0;
+         Queue ti;
+         Id tibuf[5];
+
+         queue_init_buffer(&ti, tibuf, sizeof(tibuf)/sizeof(*tibuf));
+         transaction_all_obs_pkgs(trans, to, &ti);
+         for (i = 0; i < ti.count; i++)
+           ret |= addedge(od, from, ti.elements[i], type);
+         queue_free(&ti);
+         return ret;
+       }
+    }
+
+  /* map from/to to te numbers */
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    if (te->p == to)
+      break;
+  if (i == od->ntes)
+    return 0;
+  to = i;
+
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    if (te->p == from)
+      break;
+  if (i == od->ntes)
+    return 0;
+
+  return addteedge(od, i, to, type);
+}
+
+static inline int
+havescripts(Pool *pool, Id solvid)
+{
+  Solvable *s = pool->solvables + solvid;
+  const char *dep;
+  if (s->requires)
+    {
+      Id req, *reqp;
+      int inpre = 0;
+      reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)
+       {
+          if (req == SOLVABLE_PREREQMARKER)
+           {
+             inpre = 1;
+             continue;
+           }
+         if (!inpre)
+           continue;
+         dep = pool_id2str(pool, req);
+         if (*dep == '/' && strcmp(dep, "/sbin/ldconfig") != 0)
+           return 1;
+       }
+    }
+  return 0;
+}
+
+static void
+addsolvableedges(struct orderdata *od, Solvable *s)
+{
+  Transaction *trans = od->trans;
+  Pool *pool = trans->pool;
+  Id p, p2, pp2;
+  int i, j, pre, numins;
+  Repo *installed = pool->installed;
+  Solvable *s2;
+  Queue depq;
+  int provbyinst;
+
+#if 0
+  printf("addsolvableedges %s\n", pool_solvable2str(pool, s));
+#endif
+  p = s - pool->solvables;
+  queue_init(&depq);
+  if (s->requires)
+    {
+      Id req, *reqp;
+      reqp = s->repo->idarraydata + s->requires;
+      pre = TYPE_REQ;
+      while ((req = *reqp++) != 0)
+       {
+         if (req == SOLVABLE_PREREQMARKER)
+           {
+             pre = TYPE_PREREQ;
+             continue;
+           }
+         queue_empty(&depq);
+         numins = 0;   /* number of packages to be installed providing it */
+         provbyinst = 0;       /* provided by kept package */
+         FOR_PROVIDES(p2, pp2, req)
+           {
+             s2 = pool->solvables + p2;
+             if (p2 == p)
+               {
+                 depq.count = 0;       /* self provides */
+                 break;
+               }
+             if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
+               {
+                 provbyinst = 1;
+                 continue;
+               }
+             if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
+               continue;               /* package stays uninstalled */
+
+             if (s->repo == installed)
+               {
+                 /* s gets uninstalled */
+                 queue_pushunique(&depq, p2);
+                 if (s2->repo != installed)
+                   numins++;
+               }
+             else
+               {
+                 if (s2->repo == installed)
+                   continue;   /* s2 gets uninstalled */
+                 queue_pushunique(&depq, p2);
+               }
+           }
+         if (provbyinst)
+           {
+             /* prune to harmless ->inst edges */
+             for (i = j = 0; i < depq.count; i++)
+               if (pool->solvables[depq.elements[i]].repo != installed)
+                 depq.elements[j++] = depq.elements[i];
+             depq.count = j;
+           }
+
+         if (numins && depq.count)
+           {
+             if (s->repo == installed)
+               {
+                 for (i = 0; i < depq.count; i++)
+                   {
+                     if (pool->solvables[depq.elements[i]].repo == installed)
+                       {
+                         for (j = 0; j < depq.count; j++)
+                           {
+                             if (pool->solvables[depq.elements[j]].repo != installed)
+                               {
+                                 if (trans->transaction_installed[depq.elements[i] - pool->installed->start] == depq.elements[j])
+                                   continue;   /* no self edge */
+#if 0
+                                 printf("add interrreq uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, depq.elements[i]), pool_dep2str(pool, req), pool_solvid2str(pool, depq.elements[j]));
+#endif
+                                 addedge(od, depq.elements[i], depq.elements[j], pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P);
+                               }
+                           }
+                       }
+                   }
+               }
+             /* no mixed types, remove all deps on uninstalls */
+             for (i = j = 0; i < depq.count; i++)
+               if (pool->solvables[depq.elements[i]].repo != installed)
+                 depq.elements[j++] = depq.elements[i];
+             depq.count = j;
+           }
+          for (i = 0; i < depq.count; i++)
+           {
+             p2 = depq.elements[i];
+             if (pool->solvables[p2].repo != installed)
+               {
+                 /* all elements of depq are installs, thus have different TEs */
+                 if (pool->solvables[p].repo != installed)
+                   {
+#if 0
+                     printf("add inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
+#endif
+                     addedge(od, p, p2, pre);
+                   }
+                 else
+                   {
+#if 0
+                     printf("add uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
+#endif
+                     addedge(od, p, p2, pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P);
+                   }
+               }
+             else
+               {
+                 if (s->repo != installed)
+                   continue;   /* no inst->uninst edges, please! */
+
+                 /* uninst -> uninst edge. Those make trouble. Only add if we must */
+                 if (trans->transaction_installed[p - installed->start] && !havescripts(pool, p))
+                   {
+                     /* p is obsoleted by another package and has no scripts */
+                     /* we assume that the obsoletor is good enough to replace p */
+                     continue;
+                   }
+#if 0
+                 printf("add uninst->uninst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, req), pool_solvid2str(pool, p2));
+#endif
+                 addedge(od, p2, p, pre == TYPE_PREREQ ? TYPE_PREREQ_P : TYPE_REQ_P);
+               }
+           }
+       }
+    }
+  if (s->conflicts)
+    {
+      Id con, *conp;
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+       {
+         FOR_PROVIDES(p2, pp2, con)
+           {
+             if (p2 == p)
+               continue;
+             s2 = pool->solvables + p2;
+             if (!s2->repo)
+               continue;
+             if (s->repo == installed)
+               {
+                 if (s2->repo != installed && MAPTST(&trans->transactsmap, p2))
+                   {
+                     /* deinstall p before installing p2 */
+#if 0
+                     printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, con), pool_solvid2str(pool, p));
+#endif
+                     addedge(od, p2, p, TYPE_CON);
+                   }
+               }
+             else
+               {
+                 if (s2->repo == installed && MAPTST(&trans->transactsmap, p2))
+                   {
+                     /* deinstall p2 before installing p */
+#if 0
+                     printf("add conflict uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, con), pool_solvid2str(pool, p2));
+#endif
+                     addedge(od, p, p2, TYPE_CON);
+                   }
+               }
+
+           }
+       }
+    }
+  if (s->recommends && s->repo != installed)
+    {
+      Id rec, *recp;
+      recp = s->repo->idarraydata + s->recommends;
+      while ((rec = *recp++) != 0)
+       {
+         queue_empty(&depq);
+         FOR_PROVIDES(p2, pp2, rec)
+           {
+             s2 = pool->solvables + p2;
+             if (p2 == p)
+               {
+                 depq.count = 0;       /* self provides */
+                 break;
+               }
+             if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
+               continue;
+             if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
+               continue;               /* package stays uninstalled */
+             if (s2->repo != installed)
+               queue_pushunique(&depq, p2);
+           }
+          for (i = 0; i < depq.count; i++)
+           {
+             p2 = depq.elements[i];
+             if (pool->solvables[p2].repo != installed)
+               {
+#if 0
+                 printf("add recommends inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, rec), pool_solvid2str(pool, p2));
+#endif
+                 addedge(od, p, p2, TYPE_REC);
+               }
+           }
+       }
+    }
+  if (s->suggests && s->repo != installed)
+    {
+      Id sug, *sugp;
+      sugp = s->repo->idarraydata + s->suggests;
+      while ((sug = *sugp++) != 0)
+       {
+         queue_empty(&depq);
+         FOR_PROVIDES(p2, pp2, sug)
+           {
+             s2 = pool->solvables + p2;
+             if (p2 == p)
+               {
+                 depq.count = 0;       /* self provides */
+                 break;
+               }
+             if (s2->repo == installed && !MAPTST(&trans->transactsmap, p2))
+               continue;
+             if (s2->repo != installed && !MAPTST(&trans->transactsmap, p2))
+               continue;               /* package stays uninstalled */
+             if (s2->repo != installed)
+               queue_pushunique(&depq, p2);
+           }
+          for (i = 0; i < depq.count; i++)
+           {
+             p2 = depq.elements[i];
+             if (pool->solvables[p2].repo != installed)
+               {
+#if 0
+                 printf("add suggests inst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p), pool_dep2str(pool, sug), pool_solvid2str(pool, p2));
+#endif
+                 addedge(od, p, p2, TYPE_SUG);
+               }
+           }
+       }
+    }
+  if (s->repo == installed && solvable_lookup_idarray(s, SOLVABLE_TRIGGERS, &depq) && depq.count)
+    {
+      /* we're getting deinstalled/updated. Try to do this before our
+       * triggers are hit */
+      for (i = 0; i < depq.count; i++)
+       {
+         Id tri = depq.elements[i];
+         FOR_PROVIDES(p2, pp2, tri)
+           {
+             if (p2 == p)
+               continue;
+             s2 = pool->solvables + p2;
+             if (!s2->repo)
+               continue;
+             if (s2->name == s->name)
+               continue;       /* obsoleted anyway */
+             if (s2->repo != installed && MAPTST(&trans->transactsmap, p2))
+               {
+                 /* deinstall/update p before installing p2 */
+#if 0
+                 printf("add trigger uninst->inst edge (%s -> %s -> %s)\n", pool_solvid2str(pool, p2), pool_dep2str(pool, tri), pool_solvid2str(pool, p));
+#endif
+                 addedge(od, p2, p, TYPE_CON);
+               }
+           }
+       }
+    }
+  queue_free(&depq);
+}
+
+
+/* break an edge in a cycle */
+static void
+breakcycle(struct orderdata *od, Id *cycle)
+{
+  Pool *pool = od->trans->pool;
+  Id ddegmin, ddegmax, ddeg;
+  int k, l;
+  struct s_TransactionElement *te;
+
+  l = 0;
+  ddegmin = ddegmax = 0;
+  for (k = 0; cycle[k + 1]; k += 2)
+    {
+      ddeg = od->edgedata[cycle[k + 1] + 1];
+      if (ddeg > ddegmax)
+       ddegmax = ddeg;
+      if (!k || ddeg < ddegmin)
+       {
+         l = k;
+         ddegmin = ddeg;
+         continue;
+       }
+      if (ddeg == ddegmin)
+       {
+         if (havescripts(pool, od->tes[cycle[l]].p) && !havescripts(pool, od->tes[cycle[k]].p))
+           {
+             /* prefer k, as l comes from a package with contains scriptlets */
+             l = k;
+             continue;
+           }
+         /* same edge value, check for prereq */
+       }
+    }
+
+  /* record brkoen cycle starting with the tail */
+  queue_push(&od->cycles, od->cyclesdata.count);               /* offset into data */
+  queue_push(&od->cycles, k / 2);                              /* cycle elements */
+  queue_push(&od->cycles, od->edgedata[cycle[l + 1] + 1]);     /* broken edge */
+  queue_push(&od->cycles, (ddegmax << 16) | ddegmin);          /* max/min values */
+  od->ncycles++;
+  for (k = l;;)
+    {
+      k += 2;
+      if (!cycle[k + 1])
+       k = 0;
+      queue_push(&od->cyclesdata, cycle[k]);
+      if (k == l)
+       break;
+    }
+  queue_push(&od->cyclesdata, 0);      /* mark end */
+
+  /* break that edge */
+  od->edgedata[cycle[l + 1] + 1] |= TYPE_BROKEN;
+
+#if 1
+  if (ddegmin < TYPE_REQ)
+    return;
+#endif
+
+  /* cycle recorded, print it */
+  if (ddegmin >= TYPE_REQ && (ddegmax & TYPE_PREREQ) != 0)
+    POOL_DEBUG(SOLV_DEBUG_STATS, "CRITICAL ");
+  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle: --> ");
+  for (k = 0; cycle[k + 1]; k += 2)
+    {
+      te = od->tes + cycle[k];
+      if ((od->edgedata[cycle[k + 1] + 1] & TYPE_BROKEN) != 0)
+        POOL_DEBUG(SOLV_DEBUG_STATS, "%s ##%x##> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1]);
+      else
+        POOL_DEBUG(SOLV_DEBUG_STATS, "%s --%x--> ", pool_solvid2str(pool, te->p), od->edgedata[cycle[k + 1] + 1]);
+    }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "\n");
+}
+
+static inline void
+dump_tes(struct orderdata *od)
+{
+  Pool *pool = od->trans->pool;
+  int i, j;
+  Queue obsq;
+  struct s_TransactionElement *te, *te2;
+
+  queue_init(&obsq);
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    {
+      Solvable *s = pool->solvables + te->p;
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "TE %4d: %c%s\n", i, s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
+      if (s->repo != pool->installed)
+        {
+         queue_empty(&obsq);
+         transaction_all_obs_pkgs(od->trans, te->p, &obsq);
+         for (j = 0; j < obsq.count; j++)
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "         -%s\n", pool_solvid2str(pool, obsq.elements[j]));
+       }
+      for (j = te->edges; od->edgedata[j]; j += 2)
+       {
+         te2 = od->tes + od->edgedata[j];
+         if ((od->edgedata[j + 1] & TYPE_BROKEN) == 0)
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "       --%x--> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p));
+         else
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "       ##%x##> TE %4d: %s\n", od->edgedata[j + 1], od->edgedata[j], pool_solvid2str(pool, te2->p));
+       }
+    }
+}
+
+static void
+reachable(struct orderdata *od, Id i)
+{
+  struct s_TransactionElement *te = od->tes + i;
+  int j, k;
+
+  if (te->mark != 0)
+    return;
+  te->mark = 1;
+  for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
+    {
+      if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
+       continue;
+      if (!od->tes[k].mark)
+        reachable(od, k);
+      if (od->tes[k].mark == 2)
+       {
+         te->mark = 2;
+         return;
+       }
+    }
+  te->mark = -1;
+}
+
+static void
+addcycleedges(struct orderdata *od, Id *cycle, Queue *todo)
+{
+#if 0
+  Transaction *trans = od->trans;
+  Pool *pool = trans->pool;
+#endif
+  struct s_TransactionElement *te;
+  int i, j, k, tail;
+  int head;
+
+#if 0
+  printf("addcycleedges\n");
+  for (i = 0; (j = cycle[i]) != 0; i++)
+    printf("cycle %s\n", pool_solvid2str(pool, od->tes[j].p));
+#endif
+
+  /* first add all the tail cycle edges */
+
+  /* see what we can reach from the cycle */
+  queue_empty(todo);
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    te->mark = 0;
+  for (i = 0; (j = cycle[i]) != 0; i++)
+    {
+      od->tes[j].mark = -1;
+      queue_push(todo, j);
+    }
+  while (todo->count)
+    {
+      i = queue_pop(todo);
+      te = od->tes + i;
+      if (te->mark > 0)
+       continue;
+      te->mark = te->mark < 0 ? 2 : 1;
+      for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
+       {
+         if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
+           continue;
+         if (od->tes[k].mark > 0)
+           continue;   /* no need to visit again */
+         queue_push(todo, k);
+       }
+    }
+  /* now all cycle TEs are marked with 2, all TEs reachable
+   * from the cycle are marked with 1 */
+  tail = cycle[0];
+  od->tes[tail].mark = 1;      /* no need to add edges */
+
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    {
+      if (te->mark)
+       continue;       /* reachable from cycle */
+      for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
+       {
+         if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
+           continue;
+         if (od->tes[k].mark != 2)
+           continue;
+         /* We found an edge to the cycle. Add an extra edge to the tail */
+         /* the TE was not reachable, so we're not creating a new cycle! */
+#if 0
+         printf("adding TO TAIL cycle edge %d->%d %s->%s!\n", i, tail, pool_solvid2str(pool, od->tes[i].p), pool_solvid2str(pool, od->tes[tail].p));
+#endif
+         j -= te->edges;       /* in case we move */
+         addteedge(od, i, tail, TYPE_CYCLETAIL);
+         j += te->edges;
+         break;        /* one edge is enough */
+       }
+    }
+
+  /* now add all head cycle edges */
+
+  /* reset marks */
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    te->mark = 0;
+  head = 0;
+  for (i = 0; (j = cycle[i]) != 0; i++)
+    {
+      head = j;
+      od->tes[j].mark = 2;
+    }
+  /* first the head to save some time */
+  te = od->tes + head;
+  for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
+    {
+      if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
+       continue;
+      if (!od->tes[k].mark)
+       reachable(od, k);
+      if (od->tes[k].mark == -1)
+       od->tes[k].mark = -2;   /* no need for another edge */
+    }
+  for (i = 0; cycle[i] != 0; i++)
+    {
+      if (cycle[i] == head)
+       break;
+      te = od->tes + cycle[i];
+      for (j = te->edges; (k = od->edgedata[j]) != 0; j += 2)
+       {
+         if ((od->edgedata[j + 1] & TYPE_BROKEN) != 0)
+           continue;
+         /* see if we can reach a cycle TE from k */
+         if (!od->tes[k].mark)
+           reachable(od, k);
+         if (od->tes[k].mark == -1)
+           {
+#if 0
+             printf("adding FROM HEAD cycle edge %d->%d %s->%s [%s]!\n", head, k, pool_solvid2str(pool, od->tes[head].p), pool_solvid2str(pool, od->tes[k].p), pool_solvid2str(pool, od->tes[cycle[i]].p));
+#endif
+             addteedge(od, head, k, TYPE_CYCLEHEAD);
+             od->tes[k].mark = -2;     /* no need to add that one again */
+           }
+       }
+    }
+}
+
+void
+transaction_order(Transaction *trans, int flags)
+{
+  Pool *pool = trans->pool;
+  Queue *tr = &trans->steps;
+  Repo *installed = pool->installed;
+  Id p;
+  Solvable *s;
+  int i, j, k, numte, numedge;
+  struct orderdata od;
+  struct s_TransactionElement *te;
+  Queue todo, obsq, samerepoq, uninstq;
+  int cycstart, cycel;
+  Id *cycle;
+  int oldcount;
+  int start, now;
+  Repo *lastrepo;
+  int lastmedia;
+  Id *temedianr;
+
+  start = now = solv_timems(0);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n");
+  /* free old data if present */
+  if (trans->orderdata)
+    {
+      struct s_TransactionOrderdata *od = trans->orderdata;
+      od->tes = solv_free(od->tes);
+      od->invedgedata = solv_free(od->invedgedata);
+      trans->orderdata = solv_free(trans->orderdata);
+    }
+
+  /* create a transaction element for every active component */
+  numte = 0;
+  for (i = 0; i < tr->count; i++)
+    {
+      p = tr->elements[i];
+      s = pool->solvables + p;
+      if (installed && s->repo == installed && trans->transaction_installed[p - installed->start])
+       continue;
+      numte++;
+    }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "transaction elements: %d\n", numte);
+  if (!numte)
+    return;    /* nothing to do... */
+
+  numte++;     /* leave first one zero */
+  memset(&od, 0, sizeof(od));
+  od.trans = trans;
+  od.ntes = numte;
+  od.tes = solv_calloc(numte, sizeof(*od.tes));
+  od.edgedata = solv_extend(0, 0, 1, sizeof(Id), EDGEDATA_BLOCK);
+  od.edgedata[0] = 0;
+  od.nedgedata = 1;
+  queue_init(&od.cycles);
+
+  /* initialize TEs */
+  for (i = 0, te = od.tes + 1; i < tr->count; i++)
+    {
+      p = tr->elements[i];
+      s = pool->solvables + p;
+      if (installed && s->repo == installed && trans->transaction_installed[p - installed->start])
+       continue;
+      te->p = p;
+      te++;
+    }
+
+  /* create dependency graph */
+  for (i = 0; i < tr->count; i++)
+    addsolvableedges(&od, pool->solvables + tr->elements[i]);
+
+  /* count edges */
+  numedge = 0;
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    for (j = te->edges; od.edgedata[j]; j += 2)
+      numedge++;
+  POOL_DEBUG(SOLV_DEBUG_STATS, "edges: %d, edge space: %d\n", numedge, od.nedgedata / 2);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "edge creation took %d ms\n", solv_timems(now));
+
+#if 0
+  dump_tes(&od);
+#endif
+
+  now = solv_timems(0);
+  /* kill all cycles */
+  queue_init(&todo);
+  for (i = numte - 1; i > 0; i--)
+    queue_push(&todo, i);
+
+  while (todo.count)
+    {
+      i = queue_pop(&todo);
+      /* printf("- look at TE %d\n", i); */
+      if (i < 0)
+       {
+         i = -i;
+         od.tes[i].mark = 2;   /* done with that one */
+         continue;
+       }
+      te = od.tes + i;
+      if (te->mark == 2)
+       continue;               /* already finished before */
+      if (te->mark == 0)
+       {
+         int edgestovisit = 0;
+         /* new node, visit edges */
+         for (j = te->edges; (k = od.edgedata[j]) != 0; j += 2)
+           {
+             if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
+               continue;
+             if (od.tes[k].mark == 2)
+               continue;       /* no need to visit again */
+             if (!edgestovisit++)
+               queue_push(&todo, -i);  /* end of edges marker */
+             queue_push(&todo, k);
+           }
+         if (!edgestovisit)
+           te->mark = 2;       /* no edges, done with that one */
+         else
+           te->mark = 1;       /* under investigation */
+         continue;
+       }
+      /* oh no, we found a cycle */
+      /* find start of cycle node (<0) */
+      for (j = todo.count - 1; j >= 0; j--)
+       if (todo.elements[j] == -i)
+         break;
+      assert(j >= 0);
+      cycstart = j;
+      /* build te/edge chain */
+      k = cycstart;
+      for (j = k; j < todo.count; j++)
+       if (todo.elements[j] < 0)
+         todo.elements[k++] = -todo.elements[j];
+      cycel = k - cycstart;
+      assert(cycel > 1);
+      /* make room for edges, two extra element for cycle loop + terminating 0 */
+      while (todo.count < cycstart + 2 * cycel + 2)
+       queue_push(&todo, 0);
+      cycle = todo.elements + cycstart;
+      cycle[cycel] = i;                /* close the loop */
+      cycle[2 * cycel + 1] = 0;        /* terminator */
+      for (k = cycel; k > 0; k--)
+       {
+         cycle[k * 2] = cycle[k];
+         te = od.tes + cycle[k - 1];
+         assert(te->mark == 1);
+         te->mark = 0; /* reset investigation marker */
+         /* printf("searching for edge from %d to %d\n", cycle[k - 1], cycle[k]); */
+         for (j = te->edges; od.edgedata[j]; j += 2)
+           if (od.edgedata[j] == cycle[k])
+             break;
+         assert(od.edgedata[j]);
+         cycle[k * 2 - 1] = j;
+       }
+      /* now cycle looks like this: */
+      /* te1 edge te2 edge te3 ... teN edge te1 0 */
+      breakcycle(&od, cycle);
+      /* restart with start of cycle */
+      todo.count = cycstart + 1;
+    }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "cycles broken: %d\n", od.ncycles);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle breaking took %d ms\n", solv_timems(now));
+
+  now = solv_timems(0);
+  /* now go through all broken cycles and create cycle edges to help
+     the ordering */
+   for (i = od.cycles.count - 4; i >= 0; i -= 4)
+     {
+       if (od.cycles.elements[i + 2] >= TYPE_REQ)
+         addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
+     }
+   for (i = od.cycles.count - 4; i >= 0; i -= 4)
+     {
+       if (od.cycles.elements[i + 2] < TYPE_REQ)
+         addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
+     }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
+
+#if 0
+  dump_tes(&od);
+#endif
+  /* all edges are finally set up and there are no cycles, now the easy part.
+   * Create an ordered transaction */
+  now = solv_timems(0);
+  /* first invert all edges */
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    te->mark = 1;      /* term 0 */
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    {
+      for (j = te->edges; od.edgedata[j]; j += 2)
+        {
+         if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
+           continue;
+         od.tes[od.edgedata[j]].mark++;
+       }
+    }
+  j = 1;
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    {
+      te->mark += j;
+      j = te->mark;
+    }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "invedge space: %d\n", j + 1);
+  od.invedgedata = solv_calloc(j + 1, sizeof(Id));
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    {
+      for (j = te->edges; od.edgedata[j]; j += 2)
+        {
+         if ((od.edgedata[j + 1] & TYPE_BROKEN) != 0)
+           continue;
+         od.invedgedata[--od.tes[od.edgedata[j]].mark] = i;
+       }
+    }
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    te->edges = te->mark;      /* edges now points into invedgedata */
+  od.edgedata = solv_free(od.edgedata);
+  od.nedgedata = j + 1;
+
+  /* now the final ordering */
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    te->mark = 0;
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    for (j = te->edges; od.invedgedata[j]; j++)
+      od.tes[od.invedgedata[j]].mark++;
+
+  queue_init(&samerepoq);
+  queue_init(&uninstq);
+  queue_empty(&todo);
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    if (te->mark == 0)
+      {
+       if (installed && pool->solvables[te->p].repo == installed)
+          queue_push(&uninstq, i);
+       else
+          queue_push(&todo, i);
+      }
+  assert(todo.count > 0 || uninstq.count > 0);
+  oldcount = tr->count;
+  queue_empty(tr);
+
+  queue_init(&obsq);
+
+  lastrepo = 0;
+  lastmedia = 0;
+  temedianr = solv_calloc(numte, sizeof(Id));
+  for (i = 1; i < numte; i++)
+    {
+      Solvable *s = pool->solvables + od.tes[i].p;
+      if (installed && s->repo == installed)
+       j = 1;
+      else
+        j = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1);
+      temedianr[i] = j;
+    }
+  for (;;)
+    {
+      /* select an TE i */
+      if (uninstq.count)
+       i = queue_shift(&uninstq);
+      else if (samerepoq.count)
+       i = queue_shift(&samerepoq);
+      else if (todo.count)
+       {
+         /* find next repo/media */
+         for (j = 0; j < todo.count; j++)
+           {
+             if (!j || temedianr[todo.elements[j]] < lastmedia)
+               {
+                 i = j;
+                 lastmedia = temedianr[todo.elements[j]];
+               }
+           }
+         lastrepo = pool->solvables[od.tes[todo.elements[i]].p].repo;
+
+         /* move all matching TEs to samerepoq */
+         for (i = j = 0; j < todo.count; j++)
+           {
+             int k = todo.elements[j];
+             if (temedianr[k] == lastmedia && pool->solvables[od.tes[k].p].repo == lastrepo)
+               queue_push(&samerepoq, k);
+             else
+               todo.elements[i++] = k;
+           }
+         todo.count = i;
+
+         assert(samerepoq.count);
+         i = queue_shift(&samerepoq);
+       }
+      else
+       break;
+
+      te = od.tes + i;
+      queue_push(tr, te->p);
+#if 0
+printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
+#endif
+      s = pool->solvables + te->p;
+      for (j = te->edges; od.invedgedata[j]; j++)
+       {
+         struct s_TransactionElement *te2 = od.tes + od.invedgedata[j];
+         assert(te2->mark > 0);
+         if (--te2->mark == 0)
+           {
+             Solvable *s = pool->solvables + te2->p;
+#if 0
+printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata[j]]);
+#endif
+             if (installed && s->repo == installed)
+               queue_push(&uninstq, od.invedgedata[j]);
+             else if (s->repo == lastrepo && temedianr[od.invedgedata[j]] == lastmedia)
+               queue_push(&samerepoq, od.invedgedata[j]);
+             else
+               queue_push(&todo, od.invedgedata[j]);
+           }
+       }
+    }
+  solv_free(temedianr);
+  queue_free(&todo);
+  queue_free(&samerepoq);
+  queue_free(&uninstq);
+  queue_free(&obsq);
+  for (i = 1, te = od.tes + i; i < numte; i++, te++)
+    assert(te->mark == 0);
+
+  /* add back obsoleted packages */
+  transaction_add_obsoleted(trans);
+  assert(tr->count == oldcount);
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "creating new transaction took %d ms\n", solv_timems(now));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "transaction ordering took %d ms\n", solv_timems(start));
+
+  if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES)) != 0)
+    {
+      struct s_TransactionOrderdata *tod;
+      trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata));
+      if ((flags & SOLVER_TRANSACTION_KEEP_ORDERCYCLES) != 0)
+       {
+         Queue *cycles = tod->cycles = solv_calloc(1, sizeof(Queue));
+         queue_init_clone(cycles, &od.cyclesdata);
+         /* map from tes to packages */
+         for (i = 0; i < cycles->count; i++)
+           if (cycles->elements[i])
+             cycles->elements[i] = od.tes[cycles->elements[i]].p;
+         queue_insertn(cycles, cycles->count, od.cycles.count, od.cycles.elements);
+         queue_push(cycles, od.cycles.count / 4);
+       }
+      if ((flags & SOLVER_TRANSACTION_KEEP_ORDERDATA) != 0)
+       {
+         tod->tes = od.tes;
+         tod->ntes = numte;
+         tod->invedgedata = od.invedgedata;
+         tod->ninvedgedata = od.nedgedata;
+         od.tes = 0;
+         od.invedgedata = 0;
+       }
+    }
+  solv_free(od.tes);
+  solv_free(od.invedgedata);
+  queue_free(&od.cycles);
+  queue_free(&od.cyclesdata);
+}
+
+
+int
+transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices)
+{
+  int i, j;
+  struct s_TransactionOrderdata *od = trans->orderdata;
+  struct s_TransactionElement *te;
+
+  if (!od)
+     return choices->count;
+  if (!chosen)
+    {
+      /* initialization step */
+      for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+       te->mark = 0;
+      for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+       {
+         for (j = te->edges; od->invedgedata[j]; j++)
+           od->tes[od->invedgedata[j]].mark++;
+       }
+      for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+       if (!te->mark)
+         queue_push(choices, te->p);
+      return choices->count;
+    }
+  for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
+    if (te->p == chosen)
+      break;
+  if (i == od->ntes)
+    return choices->count;
+  if (te->mark > 0)
+    {
+      /* hey! out-of-order installation! */
+      te->mark = -1;
+    }
+  for (j = te->edges; od->invedgedata[j]; j++)
+    {
+      te = od->tes + od->invedgedata[j];
+      assert(te->mark > 0 || te->mark == -1);
+      if (te->mark > 0 && --te->mark == 0)
+       queue_push(choices, te->p);
+    }
+  return choices->count;
+}
+
+void
+transaction_add_obsoleted(Transaction *trans)
+{
+  Pool *pool = trans->pool;
+  Repo *installed = pool->installed;
+  Id p;
+  Solvable *s;
+  int i, j, k, max;
+  Map done;
+  Queue obsq, *steps;
+
+  if (!installed || !trans->steps.count)
+    return;
+  /* calculate upper bound */
+  max = 0;
+  FOR_REPO_SOLVABLES(installed, p, s)
+    if (MAPTST(&trans->transactsmap, p))
+      max++;
+  if (!max)
+    return;
+  /* make room */
+  steps = &trans->steps;
+  queue_insertn(steps, 0, max, 0);
+
+  /* now add em */
+  map_init(&done, installed->end - installed->start);
+  queue_init(&obsq);
+  for (j = 0, i = max; i < steps->count; i++)
+    {
+      p = trans->steps.elements[i];
+      if (pool->solvables[p].repo == installed)
+       {
+         if (!trans->transaction_installed[p - pool->installed->start])
+           trans->steps.elements[j++] = p;
+         continue;
+       }
+      trans->steps.elements[j++] = p;
+      queue_empty(&obsq);
+      transaction_all_obs_pkgs(trans, p, &obsq);
+      for (k = 0; k < obsq.count; k++)
+       {
+         p = obsq.elements[k];
+         assert(p >= installed->start && p < installed->end);
+         if (!MAPTST(&trans->transactsmap, p)) /* just in case */
+           continue;
+         if (MAPTST(&done, p - installed->start))
+           continue;
+         MAPSET(&done, p - installed->start);
+         trans->steps.elements[j++] = p;
+       }
+    }
+
+  /* free unneeded space */
+  queue_truncate(steps, j);
+  map_free(&done);
+  queue_free(&obsq);
+}
+
+static void
+transaction_check_pkg(Transaction *trans, Id tepkg, Id pkg, Map *ins, Map *seen, int onlyprereq, Id noconfpkg, int depth)
+{
+  Pool *pool = trans->pool;
+  Id p, pp;
+  Solvable *s;
+  int good;
+
+  if (MAPTST(seen, pkg))
+    return;
+  MAPSET(seen, pkg);
+  s = pool->solvables + pkg;
+#if 0
+  printf("- %*s%c%s\n", depth * 2, "", s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
+#endif
+  if (s->requires)
+    {
+      Id req, *reqp;
+      int inpre = 0;
+      reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)
+       {
+          if (req == SOLVABLE_PREREQMARKER)
+           {
+             inpre = 1;
+             continue;
+           }
+         if (onlyprereq && !inpre)
+           continue;
+         if (!strncmp(pool_id2str(pool, req), "rpmlib(", 7))
+           continue;
+         good = 0;
+         /* first check kept packages, then freshly installed, then not yet uninstalled */
+         FOR_PROVIDES(p, pp, req)
+           {
+             if (!MAPTST(ins, p))
+               continue;
+             if (MAPTST(&trans->transactsmap, p))
+               continue;
+             good++;
+             transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
+           }
+         if (!good)
+           {
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (!MAPTST(ins, p))
+                   continue;
+                 if (pool->solvables[p].repo == pool->installed)
+                   continue;
+                 good++;
+                 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
+               }
+           }
+         if (!good)
+           {
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (!MAPTST(ins, p))
+                   continue;
+                 good++;
+                 transaction_check_pkg(trans, tepkg, p, ins, seen, 0, noconfpkg, depth + 1);
+               }
+           }
+         if (!good)
+           {
+             POOL_DEBUG(SOLV_DEBUG_RESULT, "  %c%s: nothing provides %s needed by %c%s\n", pool->solvables[tepkg].repo == pool->installed ? '-' : '+', pool_solvid2str(pool, tepkg), pool_dep2str(pool, req), s->repo == pool->installed ? '-' : '+', pool_solvable2str(pool, s));
+           }
+       }
+    }
+}
+
+void
+transaction_check_order(Transaction *trans)
+{
+  Pool *pool = trans->pool;
+  Solvable *s;
+  Id p, lastins;
+  Map ins, seen;
+  int i;
+
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "\nchecking transaction order...\n");
+  map_init(&ins, pool->nsolvables);
+  map_init(&seen, pool->nsolvables);
+  if (pool->installed)
+    {
+      FOR_REPO_SOLVABLES(pool->installed, p, s)
+        MAPSET(&ins, p);
+    }
+  lastins = 0;
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      p = trans->steps.elements[i];
+      s = pool->solvables + p;
+      if (s->repo != pool->installed)
+       lastins = p;
+      if (s->repo != pool->installed)
+       MAPSET(&ins, p);
+      if (havescripts(pool, p))
+       {
+         MAPZERO(&seen);
+         transaction_check_pkg(trans, p, p, &ins, &seen, 1, lastins, 0);
+       }
+      if (s->repo == pool->installed)
+       MAPCLR(&ins, p);
+    }
+  map_free(&seen);
+  map_free(&ins);
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "transaction order check done.\n");
+}
+
+void
+transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity)
+{
+  struct s_TransactionOrderdata *od = trans->orderdata;
+  Queue *cq;
+  int i, cid, ncycles;
+
+  queue_empty(q);
+  if (!od || !od->cycles || !od->cycles->count)
+    return;
+  cq = od->cycles;
+  ncycles = cq->elements[cq->count - 1];
+  i = cq->count - 1 - ncycles * 4;
+  for (cid = 1; cid <= ncycles; cid++, i += 4)
+    {
+      if (minseverity)
+       {
+         int cmin = cq->elements[i + 3] & 0xffff;
+         int cmax = (cq->elements[i + 3] >> 16) & 0xffff;
+         if (minseverity >= SOLVER_ORDERCYCLE_NORMAL && cmin < TYPE_REQ)
+           continue;
+         if (minseverity >= SOLVER_ORDERCYCLE_CRITICAL && (cmax & TYPE_PREREQ) == 0)
+           continue;
+       }
+      queue_push(q, cid);
+    }
+}
+
+int
+transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q)
+{
+  struct s_TransactionOrderdata *od = trans->orderdata;
+  Queue *cq;
+  int cmin, cmax, severity;
+  int ncycles;
+
+  queue_empty(q);
+  if (!od || !od->cycles || !od->cycles->count)
+    return SOLVER_ORDERCYCLE_HARMLESS;
+  cq = od->cycles;
+  ncycles = cq->elements[cq->count - 1];
+  if (cid < 1 || cid > ncycles)
+    return SOLVER_ORDERCYCLE_HARMLESS;
+  cid =  cq->count - 1 - 4 * (ncycles - cid + 1);
+  cmin = cq->elements[cid + 3] & 0xffff;
+  cmax = (cq->elements[cid + 3] >> 16) & 0xffff;
+  if (cmin < TYPE_REQ)
+    severity = SOLVER_ORDERCYCLE_HARMLESS;
+  else if ((cmax & TYPE_PREREQ) == 0)
+    severity = SOLVER_ORDERCYCLE_NORMAL;
+  else
+    severity = SOLVER_ORDERCYCLE_CRITICAL;
+  if (q)
+    queue_insertn(q, 0, cq->elements[cid + 1], cq->elements + cq->elements[cid]);
+  return severity;
+}
+
diff --git a/libsolv-0.7.2/src/policy.c b/libsolv-0.7.2/src/policy.c
new file mode 100644 (file)
index 0000000..191327a
--- /dev/null
@@ -0,0 +1,1682 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * Generic policy interface for SAT solver
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "evr.h"
+#include "policy.h"
+#include "poolvendor.h"
+#include "poolarch.h"
+#include "linkedpkg.h"
+#include "cplxdeps.h"
+
+
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * prep for prune_best_version
+ *   sort by name
+ */
+
+static int
+prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  int r;
+  Id a = *(Id *)ap;
+  Id b = *(Id *)bp;
+  Solvable *sa, *sb;
+
+  sa = pool->solvables + a;
+  sb = pool->solvables + b;
+  r = sa->name - sb->name;
+  if (r)
+    {
+      const char *na, *nb;
+      /* different names. We use real strcmp here so that the result
+       * is not depending on some random solvable order */
+      na = pool_id2str(pool, sa->name);
+      nb = pool_id2str(pool, sb->name);
+      return strcmp(na, nb);
+    }
+  if (sa->arch != sb->arch)
+    {
+      unsigned int aa, ab;
+      aa = pool_arch2score(pool, sa->arch);
+      ab = pool_arch2score(pool, sb->arch);
+      if (aa != ab && aa > 1 && ab > 1)
+       return aa < ab ? -1 : 1;        /* lowest score first */
+    }
+
+  /* the same name, bring installed solvables to the front */
+  if (pool->installed)
+    {
+      if (sa->repo == pool->installed)
+       {
+         if (sb->repo != pool->installed)
+           return -1;
+       }
+      else if (sb->repo == pool->installed)
+       return 1;       
+    }
+  /* sort by repository sub-prio (installed repo handled above) */
+  r = (sb->repo ? sb->repo->subpriority : 0) - (sa->repo ? sa->repo->subpriority : 0);
+  if (r)
+    return r;
+  /* no idea about the order, sort by id */
+  return a - b;
+}
+
+
+/*
+ * prune to repository with highest priority.
+ * does not prune installed solvables.
+ */
+
+static void
+prune_to_highest_prio(Pool *pool, Queue *plist)
+{
+  int i, j;
+  Solvable *s;
+  int bestprio = 0, bestprioset = 0;
+
+  /* prune to highest priority */
+  for (i = 0; i < plist->count; i++)  /* find highest prio in queue */
+    {
+      s = pool->solvables + plist->elements[i];
+      if (pool->installed && s->repo == pool->installed)
+       continue;
+      if (!bestprioset || s->repo->priority > bestprio)
+       {
+         bestprio = s->repo->priority;
+         bestprioset = 1;
+       }
+    }
+  if (!bestprioset)
+    return;
+  for (i = j = 0; i < plist->count; i++) /* remove all with lower prio */
+    {
+      s = pool->solvables + plist->elements[i];
+      if (s->repo->priority == bestprio || (pool->installed && s->repo == pool->installed))
+       plist->elements[j++] = plist->elements[i];
+    }
+  plist->count = j;
+}
+
+
+/* installed packages involed in a dup operation can only be kept
+ * if they are identical to a non-installed one */
+static void
+solver_prune_installed_dup_packages(Solver *solv, Queue *plist)
+{
+  Pool *pool = solv->pool;
+  int i, j, bestprio = 0;
+
+  /* find bestprio (again) */
+  for (i = 0; i < plist->count; i++)
+    {
+      Solvable *s = pool->solvables + plist->elements[i];
+      if (s->repo != pool->installed)
+       {
+         bestprio = s->repo->priority;
+         break;
+       }
+    }
+  if (i == plist->count)
+    return;    /* only installed packages, could not find prio */
+  for (i = j = 0; i < plist->count; i++)
+    {
+      Id p = plist->elements[i];
+      Solvable *s = pool->solvables + p;
+      if (s->repo != pool->installed && s->repo->priority < bestprio)
+       continue;
+      if (s->repo == pool->installed && (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
+       {
+         Id p2, pp2;
+         int keepit = 0;
+         FOR_PROVIDES(p2, pp2, s->name)
+           {
+             Solvable *s2 = pool->solvables + p2;
+             if (s2->repo == pool->installed || s2->evr != s->evr || s2->repo->priority < bestprio)
+               continue;
+             if (!solvable_identical(s, s2))
+               continue;
+             keepit = 1;
+             if (s2->repo->priority > bestprio)
+               {
+                 /* new max prio! */
+                 bestprio = s2->repo->priority;
+                 j = 0;
+               }
+           }
+         if (!keepit)
+           continue;   /* no identical package found, ignore installed package */
+       }
+      plist->elements[j++] = p;
+    }
+  if (j)
+    plist->count = j;
+}
+
+/*
+ * like prune_to_highest_prio, but calls solver prune_installed_dup_packages
+ * when there are dup packages
+ */
+static inline void
+solver_prune_to_highest_prio(Solver *solv, Queue *plist)
+{
+  prune_to_highest_prio(solv->pool, plist);
+  if (plist->count > 1 && solv->pool->installed && (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size))
+    solver_prune_installed_dup_packages(solv, plist);
+}
+
+
+static void
+solver_prune_to_highest_prio_per_name(Solver *solv, Queue *plist)
+{
+  Pool *pool = solv->pool;
+  Queue pq;
+  int i, j, k;
+  Id name;
+
+  queue_init(&pq);
+  solv_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
+  queue_push(&pq, plist->elements[0]);
+  name = pool->solvables[pq.elements[0]].name;
+  for (i = 1, j = 0; i < plist->count; i++)
+    {
+      if (pool->solvables[plist->elements[i]].name != name)
+       {
+         name = pool->solvables[plist->elements[i]].name;
+         if (pq.count > 2)
+           solver_prune_to_highest_prio(solv, &pq);
+         for (k = 0; k < pq.count; k++)
+           plist->elements[j++] = pq.elements[k];
+         queue_empty(&pq);
+       }
+      queue_push(&pq, plist->elements[i]);
+    }
+  if (pq.count > 2)
+    solver_prune_to_highest_prio(solv, &pq);
+  for (k = 0; k < pq.count; k++)
+    plist->elements[j++] = pq.elements[k];
+  queue_free(&pq);
+  plist->count = j;
+}
+
+
+#ifdef ENABLE_COMPLEX_DEPS
+
+/* simple fixed-size hash for package ids */
+#define CPLXDEPHASH_EMPTY(elements) (memset(elements, 0, sizeof(Id) * 256))
+#define CPLXDEPHASH_SET(elements, p) (elements[(p) & 255] |= (1 << ((p) >> 8 & 31)))
+#define CPLXDEPHASH_TST(elements, p) (elements[(p) & 255] && (elements[(p) & 255] & (1 << ((p) >> 8 & 31))))
+
+static void
+check_complex_dep(Solver *solv, Id dep, Map *m, Queue **cqp)
+{
+  Pool *pool = solv->pool;
+  Queue q;
+  queue_init(&q);
+  Id p;
+  int i, qcnt;
+
+#if 0
+  printf("check_complex_dep %s\n", pool_dep2str(pool, dep));
+#endif
+  i = pool_normalize_complex_dep(pool, dep, &q, CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    {
+      queue_free(&q);
+      return;
+    }
+  qcnt = q.count;
+  for (i = 0; i < qcnt; i++)
+    {
+      /* we rely on the fact that blocks are ordered here.
+       * if we reach a positive element, we know that we
+       * saw all negative ones */
+      for (; (p = q.elements[i]) < 0; i++)
+       {
+         if (solv->decisionmap[-p] < 0)
+           break;
+         if (solv->decisionmap[-p] == 0)
+           queue_push(&q, -p);         /* undecided negative literal */
+       }
+      if (p <= 0)
+       {
+#if 0
+         printf("complex dep block cannot be true or no pos literals\n");
+#endif
+         while (q.elements[i])
+           i++;
+         if (qcnt != q.count)
+           queue_truncate(&q, qcnt);
+         continue;
+       }
+      if (qcnt == q.count)
+       {
+         /* all negative literals installed, add positive literals to map */
+         for (; (p = q.elements[i]) != 0; i++)
+           MAPSET(m, p);
+       }
+      else
+       {
+         /* at least one undecided negative literal, postpone */
+         int j, k;
+         Queue *cq;
+#if 0
+         printf("add new complex dep block\n");
+         for (j = qcnt; j < q.count; j++)
+           printf("  - %s\n", pool_solvid2str(pool, q.elements[j]));
+#endif
+         while (q.elements[i])
+           i++;
+         if (!(cq = *cqp))
+           {
+             cq = solv_calloc(1, sizeof(Queue));
+             queue_init(cq);
+             queue_insertn(cq, 0, 256, 0);     /* allocate hash area */
+             *cqp = cq;
+           }
+         for (j = qcnt; j < q.count; j++)
+           {
+             p = q.elements[j];
+             /* check if we already have this (dep, p) entry */
+             for (k = 256; k < cq->count; k += 2)
+               if (cq->elements[k + 1] == dep && cq->elements[k] == p)
+                 break;
+             if (k == cq->count)
+               {
+                 /* a new one. add to cq and hash */
+                 queue_push2(cq, p, dep);
+                 CPLXDEPHASH_SET(cq->elements, p);
+               }
+           }
+         queue_truncate(&q, qcnt);
+       }
+    }
+  queue_free(&q);
+}
+
+static void
+recheck_complex_deps(Solver *solv, Id p, Map *m, Queue **cqp)
+{
+  Queue *cq = *cqp;
+  Id pp;
+  int i;
+#if 0
+  printf("recheck_complex_deps for package %s\n", pool_solvid2str(solv->pool, p));
+#endif
+  /* make sure that we don't have a false hit */
+  for (i = 256; i < cq->count; i += 2)
+    if (cq->elements[i] == p)
+      break;
+  if (i == cq->count)
+    return;    /* false alert */
+  if (solv->decisionmap[p] <= 0)
+    return;    /* just in case... */
+
+  /* rebuild the hash, call check_complex_dep for our package */
+  CPLXDEPHASH_EMPTY(cq->elements);
+  for (i = 256; i < cq->count; i += 2)
+    if ((pp = cq->elements[i]) == p)
+      {
+       Id dep = cq->elements[i + 1];
+       queue_deleten(cq, i, 2);
+       i -= 2;
+        check_complex_dep(solv, dep, m, &cq);
+      }
+    else
+      CPLXDEPHASH_SET(cq->elements, pp);
+}
+
+#endif
+
+
+void
+policy_update_recommendsmap(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  Id p, pp, rec, *recp, sug, *sugp;
+
+  if (solv->recommends_index < 0)
+    {
+      MAPZERO(&solv->recommendsmap);
+      MAPZERO(&solv->suggestsmap);
+#ifdef ENABLE_COMPLEX_DEPS
+      if (solv->recommendscplxq)
+       {
+         queue_free(solv->recommendscplxq);
+         solv->recommendscplxq = solv_free(solv->recommendscplxq);
+       }
+      if (solv->suggestscplxq)
+       {
+         queue_free(solv->suggestscplxq);
+         solv->suggestscplxq = solv_free(solv->suggestscplxq);
+       }
+#endif
+      solv->recommends_index = 0;
+    }
+  while (solv->recommends_index < solv->decisionq.count)
+    {
+      p = solv->decisionq.elements[solv->recommends_index++];
+      if (p < 0)
+       continue;
+      s = pool->solvables + p;
+#ifdef ENABLE_COMPLEX_DEPS
+      /* re-check postponed complex blocks */
+      if (solv->recommendscplxq && CPLXDEPHASH_TST(solv->recommendscplxq->elements, p))
+        recheck_complex_deps(solv, p, &solv->recommendsmap, &solv->recommendscplxq);
+      if (solv->suggestscplxq && CPLXDEPHASH_TST(solv->suggestscplxq->elements, p))
+        recheck_complex_deps(solv, p, &solv->suggestsmap, &solv->suggestscplxq);
+#endif
+      if (s->recommends)
+       {
+         recp = s->repo->idarraydata + s->recommends;
+          while ((rec = *recp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, rec))
+               {
+                 check_complex_dep(solv, rec, &solv->recommendsmap, &solv->recommendscplxq);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, rec)
+               MAPSET(&solv->recommendsmap, p);
+           }
+       }
+      if (s->suggests)
+       {
+         sugp = s->repo->idarraydata + s->suggests;
+          while ((sug = *sugp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, sug))
+               {
+                 check_complex_dep(solv, sug, &solv->suggestsmap, &solv->suggestscplxq);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, sug)
+               MAPSET(&solv->suggestsmap, p);
+           }
+       }
+    }
+}
+
+/* bring suggested/enhanced packages to front
+ * installed packages count as suggested */
+static void
+prefer_suggested(Solver *solv, Queue *plist)
+{
+  Pool *pool = solv->pool;
+  int i, count;
+
+  /* update our recommendsmap/suggestsmap */
+  if (solv->recommends_index < solv->decisionq.count)
+    policy_update_recommendsmap(solv);
+
+  for (i = 0, count = plist->count; i < count; i++)
+    {
+      Id p = plist->elements[i];
+      Solvable *s = pool->solvables + p;
+      if ((pool->installed && s->repo == pool->installed) ||
+          MAPTST(&solv->suggestsmap, p) ||
+          solver_is_enhancing(solv, s))
+       continue;       /* good package */
+      /* bring to back */
+     if (i < plist->count - 1)
+       {
+         memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
+         plist->elements[plist->count - 1] = p;
+       }
+      i--;
+      count--;
+    }
+}
+
+static int
+sort_by_favorq_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap, *b = bp, *d = dp;
+  return d[b[0]] - d[a[0]];
+}
+
+static void
+sort_by_favorq(Queue *favorq, Id *el, int cnt)
+{
+  int i;
+  /* map to offsets into favorq */
+  for (i = 0; i < cnt; i++)
+    {
+      Id p = el[i];
+      /* lookup p in sorted favorq */
+      int med = 0, low = 0;
+      int high = favorq->count / 2;
+      while (low != high)
+       {
+         med = (low + high) / 2;
+         Id pp = favorq->elements[2 * med];
+         if (pp < p)
+           low = med;
+         else if (pp > p)
+           high = med;
+         else
+           break;
+       }
+      while(med && favorq->elements[2 * med - 2] == p)
+       med--;
+      if (favorq->elements[2 * med] == p)
+        el[i] = 2 * med + 1;
+      else
+        el[i] = 0;     /* hmm */
+    }
+  /* sort by position */
+  solv_sort(el, cnt, sizeof(Id), sort_by_favorq_cmp, favorq->elements);
+  /* map back */
+  for (i = 0; i < cnt; i++)
+    if (el[i])
+      el[i] = favorq->elements[el[i] - 1];
+}
+
+/* bring favored packages to front and disfavored packages to back */
+void
+policy_prefer_favored(Solver *solv, Queue *plist)
+{
+  int i, fav, disfav, count;
+  if (!solv->favormap.size)
+    return;
+  for (i = fav = disfav = 0, count = plist->count; i < count; i++)
+    {
+      Id p = plist->elements[i];
+      if (!MAPTST(&solv->favormap, p))
+       continue;
+      if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
+       {
+         /* disfavored package. bring to back */
+        if (i < plist->count - 1)
+           {
+             memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
+             plist->elements[plist->count - 1] = p;
+           }
+         i--;
+         count--;
+         disfav++;
+       }
+      else
+       {
+         /* favored package. bring to front */
+         if (i > fav)
+           memmove(plist->elements + fav + 1, plist->elements + fav, (i - fav) * sizeof(Id));
+         plist->elements[fav++] = p;
+       }
+    }
+  /* if we have multiple favored/disfavored packages, sort by favorq index */
+  if (fav > 1)
+    sort_by_favorq(solv->favorq, plist->elements, fav);
+  if (disfav > 1)
+    sort_by_favorq(solv->favorq, plist->elements + plist->count - disfav, disfav);
+}
+
+/*
+ * prune to recommended/suggested packages.
+ * does not prune installed packages (they are also somewhat recommended).
+ */
+static void
+prune_to_recommended(Solver *solv, Queue *plist)
+{
+  Pool *pool = solv->pool;
+  int i, j, k, ninst;
+  Solvable *s;
+  Id p;
+
+  ninst = 0;
+  if (pool->installed)
+    {
+      for (i = 0; i < plist->count; i++)
+       {
+         p = plist->elements[i];
+         s = pool->solvables + p;
+         if (pool->installed && s->repo == pool->installed)
+           ninst++;
+       }
+    }
+  if (plist->count - ninst < 2)
+    return;
+
+  /* update our recommendsmap/suggestsmap */
+  if (solv->recommends_index < solv->decisionq.count)
+    policy_update_recommendsmap(solv);
+
+  /* prune to recommended/supplemented */
+  ninst = 0;
+  for (i = j = 0; i < plist->count; i++)
+    {
+      p = plist->elements[i];
+      s = pool->solvables + p;
+      if (pool->installed && s->repo == pool->installed)
+       {
+         ninst++;
+         if (j)
+           plist->elements[j++] = p;
+         continue;
+       }
+      if (!MAPTST(&solv->recommendsmap, p))
+       if (!solver_is_supplementing(solv, s))
+         continue;
+      if (!j && ninst)
+       {
+         for (k = 0; j < ninst; k++)
+           {
+             s = pool->solvables + plist->elements[k];
+             if (pool->installed && s->repo == pool->installed)
+               plist->elements[j++] = plist->elements[k];
+           }
+       }
+      plist->elements[j++] = p;
+    }
+  if (j)
+    plist->count = j;
+
+#if 0
+  /* anything left to prune? */
+  if (plist->count - ninst < 2)
+    return;
+
+  /* prune to suggested/enhanced */
+  ninst = 0;
+  for (i = j = 0; i < plist->count; i++)
+    {
+      p = plist->elements[i];
+      s = pool->solvables + p;
+      if (pool->installed && s->repo == pool->installed)
+       {
+         ninst++;
+         if (j)
+           plist->elements[j++] = p;
+         continue;
+       }
+      if (!MAPTST(&solv->suggestsmap, p))
+        if (!solver_is_enhancing(solv, s))
+         continue;
+      if (!j && ninst)
+       {
+         for (k = 0; j < ninst; k++)
+           {
+             s = pool->solvables + plist->elements[k];
+             if (pool->installed && s->repo == pool->installed)
+               plist->elements[j++] = plist->elements[k];
+           }
+       }
+      plist->elements[j++] = p;
+    }
+  if (j)
+    plist->count = j;
+#endif
+}
+
+static void
+prune_to_best_arch(const Pool *pool, Queue *plist)
+{
+  Id a, bestscore;
+  Solvable *s;
+  int i, j;
+
+  if (!pool->id2arch || plist->count < 2)
+    return;
+  bestscore = 0;
+  for (i = 0; i < plist->count; i++)
+    {
+      s = pool->solvables + plist->elements[i];
+      a = pool_arch2score(pool, s->arch);
+      if (a && a != 1 && (!bestscore || a < bestscore))
+       bestscore = a;
+    }
+  if (!bestscore)
+    return;
+  for (i = j = 0; i < plist->count; i++)
+    {
+      s = pool->solvables + plist->elements[i];
+      a = pool_arch2score(pool, s->arch);
+      if (!a)
+       continue;
+      /* a == 1 -> noarch */
+      if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
+       continue;
+      plist->elements[j++] = plist->elements[i];
+    }
+  if (j)
+    plist->count = j;
+}
+
+
+struct trj_data {
+  Pool *pool;
+  Queue *plist;
+  Id *stack;
+  Id nstack;
+  Id *low;
+  Id firstidx;
+  Id idx;
+};
+
+/* This is Tarjan's SCC algorithm, slightly modified */
+static void
+trj_visit(struct trj_data *trj, Id node)
+{
+  Id *low = trj->low;
+  Pool *pool = trj->pool;
+  Queue *plist = trj->plist;
+  Id myidx, stackstart;
+  Solvable *s;
+  int i;
+  Id p, pp, obs, *obsp;
+
+  low[node] = myidx = trj->idx++;
+  trj->stack[(stackstart = trj->nstack++)] = node;
+
+  s = pool->solvables + plist->elements[node];
+  if (s->obsoletes)
+    {
+      obsp = s->repo->idarraydata + s->obsoletes;
+      while ((obs = *obsp++) != 0)
+       {
+         FOR_PROVIDES(p, pp, obs)
+           {
+             Solvable *ps = pool->solvables + p;
+             if (ps->name == s->name)
+               continue;
+             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             /* hmm, expensive. should use hash if plist is big */
+             for (i = 0; i < plist->count; i++)
+               {
+                 if (node != i && plist->elements[i] == p)
+                   {
+                     Id l = low[i];
+                     if (!l)
+                       {
+                         if (!ps->obsoletes)
+                           {
+                             /* don't bother */
+                             trj->idx++;
+                             low[i] = -1;
+                             continue;
+                           }
+                         trj_visit(trj, i);
+                         l = low[i];
+                       }
+                     if (l < 0)
+                       continue;
+                     if (l < trj->firstidx)
+                       {
+                         int k;
+                         /* this means we have reached an old SCC found earlier.
+                          * delete it as we obsolete it */
+                         for (k = l; ; k++)
+                           {
+                             if (low[trj->stack[k]] == l)
+                               low[trj->stack[k]] = -1;
+                             else
+                               break;
+                           }
+                       }
+                     else if (l < low[node])
+                       low[node] = l;
+                   }
+               }
+           }
+       }
+    }
+  if (low[node] == myidx)      /* found a SCC? */
+    {
+      /* we're only interested in SCCs that contain the first node,
+       * as all others are "obsoleted" */
+      if (myidx != trj->firstidx)
+       myidx = -1;
+      for (i = stackstart; i < trj->nstack; i++)
+       low[trj->stack[i]] = myidx;
+      trj->nstack = stackstart;        /* empty stack */
+    }
+}
+
+/*
+ * remove entries from plist that are obsoleted by other entries
+ * with different name.
+ */
+static void
+prune_obsoleted(Pool *pool, Queue *plist)
+{
+  Id data_buf[2 * 16], *data;
+  struct trj_data trj;
+  int i, j;
+  Solvable *s;
+
+  if (plist->count <= 16)
+    {
+      memset(data_buf, 0, sizeof(data_buf));
+      data = data_buf;
+    }
+  else
+    data = solv_calloc(plist->count, 2 * sizeof(Id));
+  trj.pool = pool;
+  trj.plist = plist;
+  trj.low = data;
+  trj.idx = 1;
+  trj.stack = data + plist->count - 1; /* -1 so we can index with idx (which starts with 1) */
+  for (i = 0; i < plist->count; i++)
+    {
+      if (trj.low[i])
+       continue;
+      s = pool->solvables + plist->elements[i];
+      if (s->obsoletes)
+       {
+         trj.firstidx = trj.nstack = trj.idx;
+          trj_visit(&trj, i);
+       }
+      else
+        {
+          Id myidx = trj.idx++;
+          trj.low[i] = myidx;
+          trj.stack[myidx] = i;
+        }
+    }
+  for (i = j = 0; i < plist->count; i++)
+    if (trj.low[i] >= 0)
+      plist->elements[j++] = plist->elements[i];
+  plist->count = j;
+  if (data != data_buf)
+    solv_free(data);
+}
+
+/* this is prune_obsoleted special-cased for two elements */
+static void
+prune_obsoleted_2(Pool *pool, Queue *plist)
+{
+  int i;
+  Solvable *s;
+  Id p, pp, obs, *obsp;
+  Id other;
+  int obmap = 0;
+
+  for (i = 0; i < 2; i++)
+    {
+      s = pool->solvables + plist->elements[i];
+      other = plist->elements[1 - i];
+      if (s->obsoletes)
+       {
+         obsp = s->repo->idarraydata + s->obsoletes;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, obs)
+               {
+                 Solvable *ps;
+                 if (p != other)
+                   continue;
+                 ps = pool->solvables + p;
+                 if (ps->name == s->name)
+                   continue;
+                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+                   continue;
+                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+                   continue;
+                 obmap |= 1 << i;
+                 break;
+               }
+             if (p)
+               break;
+           }
+       }
+    }
+  if (obmap == 0 || obmap == 3)
+    return;
+  if (obmap == 2)
+    plist->elements[0] = plist->elements[1];
+  plist->count = 1;
+}
+
+/*
+ * bring those elements to the front of the queue that
+ * have a installed solvable with the same name
+ */
+static void
+move_installed_to_front(Pool *pool, Queue *plist)
+{
+  int i, j;
+  Solvable *s;
+  Id p, pp;
+
+  for (i = j = 0; i < plist->count; i++)
+    {
+      s = pool->solvables + plist->elements[i];
+      if (s->repo != pool->installed)
+        {
+          FOR_PROVIDES(p, pp, s->name)
+           {
+             Solvable *ps = pool->solvables + p;
+             if (s->name == ps->name && ps->repo == pool->installed)
+               {
+                 s = ps;
+                 break;
+               }
+           }
+        }
+      if (s->repo == pool->installed)
+       {
+         if (i != j)
+           {
+             p = plist->elements[i];
+              if (i - j == 1)
+               plist->elements[i] = plist->elements[j];
+             else
+               memmove(plist->elements + j + 1, plist->elements + j, (i - j) * sizeof(Id));
+             plist->elements[j] = p;
+           }
+         else if (j + 2 == plist->count)
+           break;      /* no need to check last element if all prev ones are installed */
+         j++;
+       }
+    }
+}
+
+/*
+ * prune_to_best_version
+ *
+ * sort list of packages (given through plist) by name and evr
+ * return result through plist
+ */
+void
+prune_to_best_version(Pool *pool, Queue *plist)
+{
+  int i, j, r;
+  Solvable *s, *best;
+
+  if (plist->count < 2)                /* no need to prune for a single entry */
+    return;
+  POOL_DEBUG(SOLV_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
+
+  /* sort by name first, prefer installed */
+  solv_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
+
+  /* now find best 'per name' */
+  best = 0;
+  for (i = j = 0; i < plist->count; i++)
+    {
+      s = pool->solvables + plist->elements[i];
+
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
+                pool_solvable2str(pool, s),
+                (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
+
+      if (!best)               /* if no best yet, the current is best */
+        {
+          best = s;
+          continue;
+        }
+
+      /* name switch: finish group, re-init */
+      if (best->name != s->name)   /* new name */
+        {
+          plist->elements[j++] = best - pool->solvables; /* move old best to front */
+          best = s;            /* take current as new best */
+          continue;
+        }
+      r = best->evr != s->evr ? pool_evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) : 0;
+#ifdef ENABLE_LINKED_PKGS
+      if (r == 0 && has_package_link(pool, s))
+        r = pool_link_evrcmp(pool, best, s);
+#endif
+      if (r < 0)
+       best = s;
+    }
+  plist->elements[j++] = best - pool->solvables;       /* finish last group */
+  plist->count = j;
+
+  /* we reduced the list to one package per name, now look at
+   * package obsoletes */
+  if (plist->count > 1)
+    {
+      if (plist->count == 2)
+        prune_obsoleted_2(pool, plist);
+      else
+        prune_obsoleted(pool, plist);
+    }
+  if (plist->count > 1 && pool->installed)
+    move_installed_to_front(pool, plist);
+}
+
+
+static int
+sort_by_name_evr_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  Id a, *aa = (Id *)ap;
+  Id b, *bb = (Id *)bp;
+  Id r = aa[1] - bb[1];
+  if (r)
+    return r < 0 ? -1 : 1;
+  if (aa[2] == bb[2])
+    return 0;
+  a = aa[2] < 0 ? -aa[2] : aa[2];
+  b = bb[2] < 0 ? -bb[2] : bb[2];
+  r = pool_evrcmp(pool, b, a, pool->disttype != DISTTYPE_DEB ? EVRCMP_MATCH_RELEASE : EVRCMP_COMPARE);
+  if (!r && (aa[2] < 0 || bb[2] < 0))
+    {
+      if (bb[2] >= 0)
+       return 1;
+      if (aa[2] >= 0)
+       return -1;
+    }
+  return r;
+}
+
+/* common end of sort_by_srcversion and sort_by_common_dep */
+static void
+sort_by_name_evr_array(Pool *pool, Queue *plist, int count, int ent)
+{
+  Id lastname;
+  int i, j, bad, havebad;
+  Id *pp, *elements = plist->elements;
+
+  if (ent < 2)
+    {
+      queue_truncate(plist, count);
+      return;
+    }
+  solv_sort(elements + count * 2, ent, sizeof(Id) * 3, sort_by_name_evr_sortcmp, pool);
+  lastname = 0;
+  bad = havebad = 0;
+  for (i = 0, pp = elements + count * 2; i < ent; i++, pp += 3)
+    {
+      if (lastname && pp[1] == lastname)
+       {
+          if (pp[0] != pp[-3] && sort_by_name_evr_sortcmp(pp - 3, pp, pool) == -1)
+           {
+#if 0
+             printf("%s - %s: bad %s %s - %s\n", pool_solvid2str(pool, elements[pp[-3]]), pool_solvid2str(pool, elements[pp[0]]), pool_dep2str(pool, lastname), pool_id2str(pool, pp[-1] < 0 ? -pp[-1] : pp[-1]), pool_id2str(pool, pp[2] < 0 ? -pp[2] : pp[2]));
+#endif
+             bad++;
+             havebad = 1;
+           }
+       }
+      else
+       {
+         bad = 0;
+         lastname = pp[1];
+       }
+      elements[count + pp[0]] += bad;
+    }
+
+#if 0
+for (i = 0; i < count; i++)
+  printf("%s badness %d\n", pool_solvid2str(pool, elements[i]), elements[count + i]);
+#endif
+
+  if (havebad)
+    {
+      /* simple stable insertion sort */
+      if (pool->installed)
+       for (i = 0; i < count; i++)
+         if (pool->solvables[elements[i]].repo == pool->installed)
+           elements[i + count] = 0;
+      for (i = 1; i < count; i++)
+       for (j = i, pp = elements + count + j; j > 0; j--, pp--)
+         if (pp[-1] > pp[0])
+           {
+             Id *pp2 = pp - count;
+             Id p = pp[-1];
+             pp[-1] = pp[0];
+             pp[0] = p;
+             p = pp2[-1];
+             pp2[-1] = pp2[0];
+             pp2[0] = p;
+           }
+         else
+           break;
+    }
+  queue_truncate(plist, count);
+}
+
+#if 0
+static void
+sort_by_srcversion(Pool *pool, Queue *plist)
+{
+  int i, count = plist->count, ent = 0;
+  queue_insertn(plist, count, count, 0);
+  for (i = 0; i < count; i++)
+    {
+      Id name, evr, p = plist->elements[i];
+      Solvable *s = pool->solvables + p;
+      if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
+       name = s->name;
+      else
+        name = solvable_lookup_id(s, SOLVABLE_SOURCENAME);
+      if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
+       evr = s->evr;
+      else
+        evr = solvable_lookup_id(s, SOLVABLE_SOURCEEVR);
+      if (!name || !evr || ISRELDEP(evr))
+       continue;
+      queue_push(plist, i);
+      queue_push2(plist, name, evr);
+      ent++;
+    }
+  sort_by_name_evr_array(pool, plist, count, ent);
+}
+#endif
+
+static void
+sort_by_common_dep(Pool *pool, Queue *plist)
+{
+  int i, count = plist->count, ent = 0;
+  Id id, *dp;
+  queue_insertn(plist, count, count, 0);
+  for (i = 0; i < count; i++)
+    {
+      Id p = plist->elements[i];
+      Solvable *s = pool->solvables + p;
+      if (!s->provides)
+       continue;
+      for (dp = s->repo->idarraydata + s->provides; (id = *dp++) != 0; )
+       {
+         Reldep *rd;
+         if (!ISRELDEP(id))
+           continue;
+         rd = GETRELDEP(pool, id);
+         if ((rd->flags == REL_EQ || rd->flags == (REL_EQ | REL_LT) || rd->flags == REL_LT) && !ISRELDEP(rd->evr))
+           {
+             if (rd->flags == REL_EQ)
+               {
+                 /* ignore hashes */
+                 const char *s = pool_id2str(pool, rd->evr);
+                 if (strlen(s) >= 4)
+                   {
+                     while ((*s >= 'a' && *s <= 'f') || (*s >= '0' && *s <= '9'))
+                       s++;
+                     if (!*s)
+                       continue;
+                   }
+               }
+             queue_push(plist, i);
+             queue_push2(plist, rd->name, rd->flags == REL_LT ? -rd->evr : rd->evr);
+             ent++;
+           }
+       }
+    }
+  sort_by_name_evr_array(pool, plist, count, ent);
+}
+
+/* check if we have an update candidate */
+static void
+dislike_old_versions(Pool *pool, Queue *plist)
+{
+  int i, count;
+
+  for (i = 0, count = plist->count; i < count; i++)
+    {
+      Id p = plist->elements[i];
+      Solvable *s = pool->solvables + p;
+      Repo *repo = s->repo;
+      Id q, qq;
+      int bad = 0;
+
+      if (!repo || repo == pool->installed)
+       continue;
+      FOR_PROVIDES(q, qq, s->name)
+       {
+         Solvable *qs = pool->solvables + q;
+         if (q == p)
+           continue;
+         if (s->name != qs->name || s->arch != qs->arch)
+           continue;
+         if (repo->priority != qs->repo->priority)
+           {
+             if (repo->priority > qs->repo->priority)
+               continue;
+             bad = 1;
+             break;
+           }
+         if (pool_evrcmp(pool, qs->evr, s->evr, EVRCMP_COMPARE) > 0)
+           {
+             bad = 1;
+             break;
+           }
+       }
+      if (!bad)
+       continue;
+      /* bring to back */
+      if (i < plist->count - 1)
+       {
+         memmove(plist->elements + i, plist->elements + i + 1, (plist->count - 1 - i) * sizeof(Id));
+         plist->elements[plist->count - 1] = p;
+       }
+      i--;
+      count--;
+    }
+}
+
+
+/* special lang package handling for urpm */
+/* see https://bugs.mageia.org/show_bug.cgi?id=18315 */
+
+static int
+urpm_reorder_cmp(const void *ap, const void *bp, void *dp)
+{
+  return ((Id *)bp)[1] - ((Id *)ap)[1];
+}
+
+static void
+urpm_reorder(Solver *solv, Queue *plist)
+{
+  Pool *pool = solv->pool;
+  int i, count = plist->count;
+  /* add locale score to packages */
+  queue_insertn(plist, count, count, 0);
+  for (i = count - 1; i >= 0; i--)
+    {
+      Solvable *s = pool->solvables + plist->elements[i];
+      int score = 1;
+      const char *sn = pool_id2str(pool, s->name);
+
+      if (!strncmp(sn, "kernel-", 7))
+       {
+         const char *devel = strstr(sn, "-devel-");
+         if (devel && strlen(sn) < 256)
+           {
+             char kn[256];
+             Id p, pp, knid;
+             memcpy(kn, sn, devel - sn);
+             strcpy(kn + (devel - sn), devel + 6);
+             knid = pool_str2id(pool, kn, 0);
+             if (knid)
+               {
+                 FOR_PROVIDES(p, pp, knid)
+                   {
+                     if (solv->decisionmap[p] > 0)
+                       {
+                         score = 4;
+                         break;
+                       }
+                     else if (pool->installed && pool->solvables[p].repo == pool->installed)
+                       score = 3;
+                   }
+               }
+           }
+       }
+      else if ((sn = strstr(sn, "-kernel-")) != 0)
+       {
+         sn += 8;
+         if (strlen(sn) < 256 - 8 && *sn >= '0' && *sn <= '9' && sn[1] == '.')
+           {
+             const char *flavor = strchr(sn, '-');
+             if (flavor)
+               {
+                 const char *release = strchr(flavor + 1, '-');
+                 if (release)
+                   {
+                     char kn[256];
+                     Id p, pp, knid;
+                     memcpy(kn, "kernel", 7);
+                     memcpy(kn + 6, flavor, release - flavor + 1);
+                     memcpy(kn + 6 + (release - flavor) + 1, sn, flavor - sn);
+                     strcpy(kn + 6 + (release + 1 - sn), release);
+                     knid = pool_str2id(pool, kn, 0);
+                     if (knid)
+                       {
+                         FOR_PROVIDES(p, pp, knid)
+                           {
+                             if (solv->decisionmap[p] > 0)
+                               {
+                                 score = 4;
+                                 break;
+                               }
+                             if (pool->installed && pool->solvables[p].repo == pool->installed)
+                               score = 3;
+                           }
+                       }
+                   }
+               }
+           }
+       }
+      if (score == 1 && s->requires)
+       {
+         Id id, *idp, p, pp;
+         const char *deps;
+         for (idp = s->repo->idarraydata + s->requires; (id = *idp) != 0; idp++)
+           {
+             while (ISRELDEP(id))
+               {
+                 Reldep *rd = GETRELDEP(pool, id);
+                 id = rd->name;
+               }
+             deps = strstr(pool_id2str(pool, id), "locales-");
+             if (!deps)
+               continue;
+             if (!strncmp(deps + 8, "en", 2))
+               score = 2;
+             else
+               {
+                 score = 0;
+                 FOR_PROVIDES(p, pp, id)
+                   {
+                     if (solv->decisionmap[p] > 0)
+                       {
+                         score = 4;
+                         break;
+                       }
+                     if (pool->installed && pool->solvables[p].repo == pool->installed)
+                       score = 3;
+                   }
+                 break;
+               }
+           }
+       }
+      plist->elements[i * 2] = plist->elements[i];
+      plist->elements[i * 2 + 1] = score;
+    }
+  solv_sort(plist->elements, count, sizeof(Id) * 2, urpm_reorder_cmp, pool);
+  for (i = 0; i < count; i++)
+    plist->elements[i] = plist->elements[2 * i];
+  queue_truncate(plist, count);
+}
+
+
+/*
+ *  POLICY_MODE_CHOOSE:     default, do all pruning steps
+ *  POLICY_MODE_RECOMMEND:  leave out prune_to_recommended
+ *  POLICY_MODE_SUGGEST:    leave out prune_to_recommended, do prio pruning just per name
+ */
+void
+policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
+{
+  Pool *pool = solv->pool;
+  if (mode == POLICY_MODE_SUPPLEMENT)
+    {
+      /* reorder only */
+      dislike_old_versions(pool, plist);
+      sort_by_common_dep(pool, plist);
+      if (solv->urpmreorder)
+        urpm_reorder(solv, plist);
+      prefer_suggested(solv, plist);
+      policy_prefer_favored(solv, plist);
+      return;
+    }
+  if (plist->count > 1)
+    {
+      if (mode != POLICY_MODE_SUGGEST)
+        solver_prune_to_highest_prio(solv, plist);
+      else
+        solver_prune_to_highest_prio_per_name(solv, plist);
+    }
+  if (plist->count > 1)
+    prune_to_best_arch(pool, plist);
+  if (plist->count > 1)
+    prune_to_best_version(pool, plist);
+  if (plist->count > 1 && (mode == POLICY_MODE_CHOOSE || mode == POLICY_MODE_CHOOSE_NOREORDER))
+    {
+      prune_to_recommended(solv, plist);
+      if (plist->count > 1 && mode != POLICY_MODE_CHOOSE_NOREORDER)
+       {
+         /* do some fancy reordering */
+#if 0
+         sort_by_srcversion(pool, plist);
+#endif
+         dislike_old_versions(pool, plist);
+         sort_by_common_dep(pool, plist);
+         if (solv->urpmreorder)
+           urpm_reorder(solv, plist);
+         prefer_suggested(solv, plist);
+         policy_prefer_favored(solv, plist);
+       }
+    }
+}
+
+void
+pool_best_solvables(Pool *pool, Queue *plist, int flags)
+{
+  if (plist->count > 1)
+    prune_to_highest_prio(pool, plist);
+  if (plist->count > 1)
+    prune_to_best_arch(pool, plist);
+  if (plist->count > 1)
+    prune_to_best_version(pool, plist);
+  if (plist->count > 1)
+    {
+      dislike_old_versions(pool, plist);
+      sort_by_common_dep(pool, plist);
+    }
+}
+
+
+/* check if there is an illegal architecture change if
+ * installed solvable s1 is replaced by s2 */
+int
+policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
+{
+  Pool *pool = solv->pool;
+  Id a1 = s1->arch, a2 = s2->arch;
+
+  /* we allow changes to/from noarch */
+  if (a1 == a2 || a1 == pool->noarchid || a2 == pool->noarchid)
+    return 0;
+  if (!pool->id2arch)
+    return 0;
+  a1 = pool_arch2score(pool, a1);
+  a2 = pool_arch2score(pool, a2);
+  if (((a1 ^ a2) & 0xffff0000) != 0)
+    return 1;
+  return 0;
+}
+
+/* check if there is an illegal vendor change if
+ * installed solvable s1 is replaced by s2 */
+int
+policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
+{
+  Pool *pool = solv->pool;
+  Id v1, v2;
+  Id vendormask1, vendormask2;
+
+  if (pool->custom_vendorcheck)
+     return pool->custom_vendorcheck(pool, s1, s2);
+
+  /* treat a missing vendor as empty string */
+  v1 = s1->vendor ? s1->vendor : ID_EMPTY;
+  v2 = s2->vendor ? s2->vendor : ID_EMPTY;
+  if (v1 == v2)
+    return 0;
+  vendormask1 = pool_vendor2mask(pool, v1);
+  if (!vendormask1)
+    return 1;  /* can't match */
+  vendormask2 = pool_vendor2mask(pool, v2);
+  if ((vendormask1 & vendormask2) != 0)
+    return 0;
+  return 1;    /* no class matches */
+}
+
+/* check if it is illegal to replace installed
+ * package "is" with package "s" (which must obsolete "is")
+ */
+int
+policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
+{
+  Pool *pool = solv->pool;
+  int ret = 0;
+  int duppkg = solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, is - pool->solvables));
+  if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !(duppkg ? solv->dup_allowdowngrade : solv->allowdowngrade))
+    {
+      if (is->name == s->name && pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
+       ret |= POLICY_ILLEGAL_DOWNGRADE;
+    }
+  if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !(duppkg ? solv->dup_allowarchchange : solv->allowarchchange))
+    {
+      if (is->arch != s->arch && policy_illegal_archchange(solv, is, s))
+       ret |= POLICY_ILLEGAL_ARCHCHANGE;
+    }
+  if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !(duppkg ? solv->dup_allowvendorchange : solv->allowvendorchange))
+    {
+      if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, is, s))
+       ret |= POLICY_ILLEGAL_VENDORCHANGE;
+    }
+  if (!(ignore & POLICY_ILLEGAL_NAMECHANGE) && !(duppkg ? solv->dup_allownamechange : solv->allownamechange))
+    {
+      if (is->name != s->name)
+       ret |= POLICY_ILLEGAL_NAMECHANGE;
+    }
+  return ret;
+}
+
+/*-------------------------------------------------------------------
+ *
+ * create reverse obsoletes map for installed solvables
+ *
+ * For each installed solvable find which packages with *different* names
+ * obsolete the solvable.
+ * This index is used in policy_findupdatepackages() below.
+ */
+void
+policy_create_obsolete_index(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  Repo *installed = solv->installed;
+  Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
+  int i, n, cnt;
+
+  solv->obsoletes = solv_free(solv->obsoletes);
+  solv->obsoletes_data = solv_free(solv->obsoletes_data);
+  if (!installed || installed->start == installed->end)
+    return;
+  cnt = installed->end - installed->start;
+  solv->obsoletes = obsoletes = solv_calloc(cnt, sizeof(Id));
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      s = pool->solvables + i;
+      if (!s->obsoletes)
+       continue;
+      if (!pool_installable(pool, s))
+       continue;
+      obsp = s->repo->idarraydata + s->obsoletes;
+      while ((obs = *obsp++) != 0)
+       {
+         FOR_PROVIDES(p, pp, obs)
+           {
+             Solvable *ps = pool->solvables + p;;
+             if (ps->repo != installed)
+               continue;
+             if (ps->name == s->name)
+               continue;
+             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             obsoletes[p - installed->start]++;
+           }
+       }
+    }
+  n = 0;
+  for (i = 0; i < cnt; i++)
+    if (obsoletes[i])
+      {
+        n += obsoletes[i] + 1;
+        obsoletes[i] = n;
+      }
+  solv->obsoletes_data = obsoletes_data = solv_calloc(n + 1, sizeof(Id));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
+  for (i = pool->nsolvables - 1; i > 0; i--)
+    {
+      s = pool->solvables + i;
+      if (!s->obsoletes)
+       continue;
+      if (!pool_installable(pool, s))
+       continue;
+      obsp = s->repo->idarraydata + s->obsoletes;
+      while ((obs = *obsp++) != 0)
+       {
+         FOR_PROVIDES(p, pp, obs)
+           {
+             Solvable *ps = pool->solvables + p;;
+             if (ps->repo != installed)
+               continue;
+             if (ps->name == s->name)
+               continue;
+             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             if (obsoletes_data[obsoletes[p - installed->start]] != i)
+               obsoletes_data[--obsoletes[p - installed->start]] = i;
+           }
+       }
+    }
+}
+
+
+/*
+ * find update candidates
+ *
+ * s: installed solvable to be updated
+ * qs: [out] queue to hold Ids of candidates
+ * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
+ *            2 = dup mode
+ *
+ */
+void
+policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
+{
+  /* installed packages get a special upgrade allowed rule */
+  Pool *pool = solv->pool;
+  Id p, pp, n, p2, pp2;
+  Id obs, *obsp;
+  Solvable *ps;
+  int haveprovobs = 0;
+  int allowdowngrade = allow_all ? 1 : solv->allowdowngrade;
+  int allownamechange = allow_all ? 1 : solv->allownamechange;
+  int allowarchchange = allow_all ? 1 : solv->allowarchchange;
+  int allowvendorchange = allow_all ? 1 : solv->allowvendorchange;
+  if (allow_all == 2)
+    {
+      allowdowngrade = solv->dup_allowdowngrade;
+      allownamechange = solv->dup_allownamechange;
+      allowarchchange = solv->dup_allowarchchange;
+      allowvendorchange = solv->dup_allowvendorchange;
+    }
+
+  queue_empty(qs);
+
+  n = s - pool->solvables;
+
+  /*
+   * look for updates for s
+   */
+  FOR_PROVIDES(p, pp, s->name) /* every provider of s' name */
+    {
+      if (p == n)              /* skip itself */
+       continue;
+
+      ps = pool->solvables + p;
+      if (s->name == ps->name) /* name match */
+       {
+         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+           continue;
+         if (!allowdowngrade && pool_evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0)
+           continue;
+       }
+      else if (!allownamechange)
+       continue;
+      else if ((!solv->noupdateprovide || solv->needupdateprovide) && ps->obsoletes)   /* provides/obsoletes combination ? */
+       {
+         /* check if package ps obsoletes installed package s */
+         /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
+          * use it to limit our update candidates */
+         if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, ps))
+           continue;
+         obsp = ps->repo->idarraydata + ps->obsoletes;
+         while ((obs = *obsp++) != 0)  /* for all obsoletes */
+           {
+             FOR_PROVIDES(p2, pp2, obs)   /* and all matching providers of the obsoletes */
+               {
+                 Solvable *ps2 = pool->solvables + p2;
+                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
+                   continue;
+                 if (p2 == n)          /* match ! */
+                   break;
+               }
+             if (p2)                   /* match! */
+               break;
+           }
+         if (!obs)                     /* continue if no match */
+           continue;
+         /* here we have 'p' with a matching provides/obsoletes combination
+          * thus flagging p as a valid update candidate for s
+          */
+         haveprovobs = 1;
+       }
+      else
+        continue;
+      if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
+       continue;
+      if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
+       continue;
+      queue_push(qs, p);
+    }
+  if (!allownamechange)
+    return;
+  /* if we have found some valid candidates and noupdateprovide is not set, we're
+     done. otherwise we fallback to all obsoletes */
+  if (solv->needupdateprovide || (!solv->noupdateprovide && haveprovobs))
+    return;
+  if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
+    {
+      Id *opp;
+      for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
+       {
+         ps = pool->solvables + p;
+         if (!allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
+           continue;
+         if (!allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
+           continue;
+         /* implicitobsoleteusescolors is somewhat wrong here, but we nevertheless
+          * use it to limit our update candidates */
+         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+           continue;
+         queue_push(qs, p);
+       }
+    }
+}
+
+const char *
+policy_illegal2str(Solver *solv, int illegal, Solvable *s, Solvable *rs)
+{
+  Pool *pool = solv->pool;
+  const char *str;
+  if (illegal == POLICY_ILLEGAL_DOWNGRADE)
+    {
+      str = pool_tmpjoin(pool, "downgrade of ", pool_solvable2str(pool, s), 0);
+      return pool_tmpappend(pool, str, " to ", pool_solvable2str(pool, rs));
+    }
+  if (illegal == POLICY_ILLEGAL_NAMECHANGE)
+    {
+      str = pool_tmpjoin(pool, "name change of ", pool_solvable2str(pool, s), 0);
+      return pool_tmpappend(pool, str, " to ", pool_solvable2str(pool, rs));
+    }
+  if (illegal == POLICY_ILLEGAL_ARCHCHANGE)
+    {
+      str = pool_tmpjoin(pool, "architecture change of ", pool_solvable2str(pool, s), 0);
+      return pool_tmpappend(pool, str, " to ", pool_solvable2str(pool, rs));
+    }
+  if (illegal == POLICY_ILLEGAL_VENDORCHANGE)
+    {
+      str = pool_tmpjoin(pool, "vendor change from '", pool_id2str(pool, s->vendor), "' (");
+      if (rs->vendor)
+       {
+          str = pool_tmpappend(pool, str, pool_solvable2str(pool, s), ") to '");
+          str = pool_tmpappend(pool, str, pool_id2str(pool, rs->vendor), "' (");
+       }
+      else
+        str = pool_tmpappend(pool, str, pool_solvable2str(pool, s), ") to no vendor (");
+      return pool_tmpappend(pool, str, pool_solvable2str(pool, rs), ")");
+    }
+  return "unknown illegal change";
+}
+
diff --git a/libsolv-0.7.2/src/policy.h b/libsolv-0.7.2/src/policy.h
new file mode 100644 (file)
index 0000000..68f4db9
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * Generic policy interface for SAT solver
+ * The policy* function can be "overloaded" by defining a callback in the solver struct.
+ */
+
+#include "solver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define POLICY_MODE_CHOOSE     0
+#define POLICY_MODE_RECOMMEND  1
+#define POLICY_MODE_SUGGEST    2
+#define POLICY_MODE_CHOOSE_NOREORDER   3       /* internal, do not use */
+#define POLICY_MODE_SUPPLEMENT 4       /* internal, do not use */
+
+
+#define POLICY_ILLEGAL_DOWNGRADE       1
+#define POLICY_ILLEGAL_ARCHCHANGE      2
+#define POLICY_ILLEGAL_VENDORCHANGE    4
+#define POLICY_ILLEGAL_NAMECHANGE      8
+
+extern void policy_filter_unwanted(Solver *solv, Queue *plist, int mode);
+extern int  policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2);
+extern int  policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2);
+extern int  policy_is_illegal(Solver *solv, Solvable *s1, Solvable *s2, int ignore);
+extern void policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allowall);
+extern const char *policy_illegal2str(Solver *solv, int illegal, Solvable *s, Solvable *rs);
+extern void policy_update_recommendsmap(Solver *solv);
+
+extern void policy_create_obsolete_index(Solver *solv);
+
+extern void pool_best_solvables(Pool *pool, Queue *plist, int flags);
+
+/* internal, do not use */
+extern void prune_to_best_version(Pool *pool, Queue *plist);
+extern void policy_prefer_favored(Solver *solv, Queue *plist);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libsolv-0.7.2/src/pool.c b/libsolv-0.7.2/src/pool.c
new file mode 100644 (file)
index 0000000..383edb2
--- /dev/null
@@ -0,0 +1,2048 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * pool.c
+ *
+ * The pool contains information about solvables
+ * stored optimized for memory consumption and fast retrieval.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pool.h"
+#include "poolvendor.h"
+#include "repo.h"
+#include "poolid.h"
+#include "poolid_private.h"
+#include "poolarch.h"
+#include "util.h"
+#include "bitmap.h"
+#include "evr.h"
+
+#define SOLVABLE_BLOCK 255
+
+#undef LIBSOLV_KNOWNID_H
+#define KNOWNID_INITIALIZE
+#include "knownid.h"
+#undef KNOWNID_INITIALIZE
+
+/* create pool */
+Pool *
+pool_create(void)
+{
+  Pool *pool;
+  Solvable *s;
+
+  pool = (Pool *)solv_calloc(1, sizeof(*pool));
+
+  stringpool_init(&pool->ss, initpool_data);
+
+  /* alloc space for RelDep 0 */
+  pool->rels = solv_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
+  pool->nrels = 1;
+  memset(pool->rels, 0, sizeof(Reldep));
+
+  /* alloc space for Solvable 0 and system solvable */
+  pool->solvables = solv_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
+  pool->nsolvables = 2;
+  memset(pool->solvables, 0, 2 * sizeof(Solvable));
+
+  queue_init(&pool->vendormap);
+  queue_init(&pool->pooljobs);
+  queue_init(&pool->lazywhatprovidesq);
+
+#if defined(DEBIAN)
+  pool->disttype = DISTTYPE_DEB;
+  pool->noarchid = ARCH_ALL;
+#elif defined(ARCHLINUX)
+  pool->disttype = DISTTYPE_ARCH;
+  pool->noarchid = ARCH_ANY;
+#elif defined(HAIKU)
+  pool->disttype = DISTTYPE_HAIKU;
+  pool->noarchid = ARCH_ANY;
+  pool->obsoleteusesprovides = 1;
+#else
+  pool->disttype = DISTTYPE_RPM;
+  pool->noarchid = ARCH_NOARCH;
+#endif
+
+  /* initialize the system solvable */
+  s = pool->solvables + SYSTEMSOLVABLE;
+  s->name = SYSTEM_SYSTEM;
+  s->arch = pool->noarchid;
+  s->evr = ID_EMPTY;
+
+  pool->debugmask = SOLV_DEBUG_RESULT; /* FIXME */
+#if defined(FEDORA) || defined(MAGEIA)
+  pool->implicitobsoleteusescolors = 1;
+#endif
+#ifdef RPM5
+  pool->noobsoletesmultiversion = 1;
+  pool->forbidselfconflicts = 1;
+  pool->obsoleteusesprovides = 1;
+  pool->implicitobsoleteusesprovides = 1;
+  pool->havedistepoch = 1;
+#endif
+  return pool;
+}
+
+
+/* free all the resources of our pool */
+void
+pool_free(Pool *pool)
+{
+  int i;
+
+  pool_freewhatprovides(pool);
+  pool_freeidhashes(pool);
+  pool_freeallrepos(pool, 1);
+  solv_free(pool->id2arch);
+  solv_free(pool->id2color);
+  solv_free(pool->solvables);
+  stringpool_free(&pool->ss);
+  solv_free(pool->rels);
+  pool_setvendorclasses(pool, 0);
+  queue_free(&pool->vendormap);
+  queue_free(&pool->pooljobs);
+  queue_free(&pool->lazywhatprovidesq);
+  for (i = 0; i < POOL_TMPSPACEBUF; i++)
+    solv_free(pool->tmpspace.buf[i]);
+  for (i = 0; i < pool->nlanguages; i++)
+    free((char *)pool->languages[i]);
+  solv_free((void *)pool->languages);
+  solv_free(pool->languagecache);
+  solv_free(pool->errstr);
+  solv_free(pool->rootdir);
+  solv_free(pool);
+}
+
+void
+pool_freeallrepos(Pool *pool, int reuseids)
+{
+  int i;
+
+  pool_freewhatprovides(pool);
+  for (i = 1; i < pool->nrepos; i++)
+    if (pool->repos[i])
+      repo_freedata(pool->repos[i]);
+  pool->repos = solv_free(pool->repos);
+  pool->nrepos = 0;
+  pool->urepos = 0;
+  /* the first two solvables don't belong to a repo */
+  pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
+}
+
+int
+pool_setdisttype(Pool *pool, int disttype)
+{
+#ifdef MULTI_SEMANTICS
+  int olddisttype = pool->disttype;
+  switch(disttype)
+    {
+    case DISTTYPE_RPM:
+      pool->noarchid = ARCH_NOARCH;
+      break;
+    case DISTTYPE_DEB:
+      pool->noarchid = ARCH_ALL;
+      break;
+    case DISTTYPE_ARCH:
+    case DISTTYPE_HAIKU:
+      pool->noarchid = ARCH_ANY;
+      break;
+    default:
+      return -1;
+    }
+  pool->disttype = disttype;
+  pool->solvables[SYSTEMSOLVABLE].arch = pool->noarchid;
+  return olddisttype;
+#else
+  return pool->disttype == disttype ? disttype : -1;
+#endif
+}
+
+int
+pool_get_flag(Pool *pool, int flag)
+{
+  switch (flag)
+    {
+    case POOL_FLAG_PROMOTEEPOCH:
+      return pool->promoteepoch;
+    case POOL_FLAG_FORBIDSELFCONFLICTS:
+      return pool->forbidselfconflicts;
+    case POOL_FLAG_OBSOLETEUSESPROVIDES:
+      return pool->obsoleteusesprovides;
+    case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
+      return pool->implicitobsoleteusesprovides;
+    case POOL_FLAG_OBSOLETEUSESCOLORS:
+      return pool->obsoleteusescolors;
+    case POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS:
+      return pool->implicitobsoleteusescolors;
+    case POOL_FLAG_NOINSTALLEDOBSOLETES:
+      return pool->noinstalledobsoletes;
+    case POOL_FLAG_HAVEDISTEPOCH:
+      return pool->havedistepoch;
+    case POOL_FLAG_NOOBSOLETESMULTIVERSION:
+      return pool->noobsoletesmultiversion;
+    case POOL_FLAG_ADDFILEPROVIDESFILTERED:
+      return pool->addfileprovidesfiltered;
+    case POOL_FLAG_NOWHATPROVIDESAUX:
+      return pool->nowhatprovidesaux;
+    default:
+      break;
+    }
+  return -1;
+}
+
+int
+pool_set_flag(Pool *pool, int flag, int value)
+{
+  int old = pool_get_flag(pool, flag);
+  switch (flag)
+    {
+    case POOL_FLAG_PROMOTEEPOCH:
+      pool->promoteepoch = value;
+      break;
+    case POOL_FLAG_FORBIDSELFCONFLICTS:
+      pool->forbidselfconflicts = value;
+      break;
+    case POOL_FLAG_OBSOLETEUSESPROVIDES:
+      pool->obsoleteusesprovides = value;
+      break;
+    case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
+      pool->implicitobsoleteusesprovides = value;
+      break;
+    case POOL_FLAG_OBSOLETEUSESCOLORS:
+      pool->obsoleteusescolors = value;
+      break;
+    case POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS:
+      pool->implicitobsoleteusescolors = value;
+      break;
+    case POOL_FLAG_NOINSTALLEDOBSOLETES:
+      pool->noinstalledobsoletes = value;
+      break;
+    case POOL_FLAG_HAVEDISTEPOCH:
+      pool->havedistepoch = value;
+      break;
+    case POOL_FLAG_NOOBSOLETESMULTIVERSION:
+      pool->noobsoletesmultiversion = value;
+      break;
+    case POOL_FLAG_ADDFILEPROVIDESFILTERED:
+      pool->addfileprovidesfiltered = value;
+      break;
+    case POOL_FLAG_NOWHATPROVIDESAUX:
+      pool->nowhatprovidesaux = value;
+      break;
+    default:
+      break;
+    }
+  return old;
+}
+
+
+Id
+pool_add_solvable(Pool *pool)
+{
+  pool->solvables = solv_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
+  memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
+  return pool->nsolvables++;
+}
+
+Id
+pool_add_solvable_block(Pool *pool, int count)
+{
+  Id nsolvables = pool->nsolvables;
+  if (!count)
+    return nsolvables;
+  pool->solvables = solv_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
+  memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
+  pool->nsolvables += count;
+  return nsolvables;
+}
+
+void
+pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
+{
+  if (!count)
+    return;
+  if (reuseids && start + count == pool->nsolvables)
+    {
+      /* might want to shrink solvable array */
+      pool->nsolvables = start;
+      return;
+    }
+  memset(pool->solvables + start, 0, sizeof(Solvable) * count);
+}
+
+
+void
+pool_set_installed(Pool *pool, Repo *installed)
+{
+  if (pool->installed == installed)
+    return;
+  pool->installed = installed;
+  pool_freewhatprovides(pool);
+}
+
+static int
+pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  int r;
+  Pool *pool = dp;
+  Id oa, ob, *da, *db;
+  oa = pool->whatprovides[*(Id *)ap];
+  ob = pool->whatprovides[*(Id *)bp];
+  if (oa == ob)
+    return *(Id *)ap - *(Id *)bp;
+  da = pool->whatprovidesdata + oa;
+  db = pool->whatprovidesdata + ob;
+  while (*db)
+    if ((r = (*da++ - *db++)) != 0)
+      return r;
+  if (*da)
+    return *da;
+  return *(Id *)ap - *(Id *)bp;
+}
+
+/*
+ * pool_shrink_whatprovides  - unify whatprovides data
+ *
+ * whatprovides_rel must be empty for this to work!
+ *
+ */
+static void
+pool_shrink_whatprovides(Pool *pool)
+{
+  Id i, n, id;
+  Id *sorted;
+  Id lastid, *last, *dp, *lp;
+  Offset o;
+  int r;
+
+  if (pool->ss.nstrings < 3)
+    return;
+  sorted = solv_malloc2(pool->ss.nstrings, sizeof(Id));
+  for (i = id = 0; id < pool->ss.nstrings; id++)
+    if (pool->whatprovides[id] >= 4)
+      sorted[i++] = id;
+  n = i;
+  solv_sort(sorted, n, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool);
+  last = 0;
+  lastid = 0;
+  for (i = 0; i < n; i++)
+    {
+      id = sorted[i];
+      o = pool->whatprovides[id];
+      dp = pool->whatprovidesdata + o;
+      if (last)
+       {
+         lp = last;
+         while (*dp)   
+           if (*dp++ != *lp++)
+             {
+               last = 0;
+               break;
+             }
+         if (last && *lp)
+           last = 0;
+         if (last)
+           {
+             pool->whatprovides[id] = -lastid;
+             continue;
+           }
+       }
+      last = pool->whatprovidesdata + o;
+      lastid = id;
+    }
+  solv_free(sorted);
+  dp = pool->whatprovidesdata + 4;
+  for (id = 1; id < pool->ss.nstrings; id++)
+    {
+      o = pool->whatprovides[id];
+      if (!o)
+       continue;
+      if ((Id)o < 0)
+       {
+         i = -(Id)o;
+         if (i >= id)
+           abort();
+         pool->whatprovides[id] = pool->whatprovides[i];
+         continue;
+       }
+      if (o < 4)
+       continue;
+      lp = pool->whatprovidesdata + o;
+      if (lp < dp)
+       abort();
+      pool->whatprovides[id] = dp - pool->whatprovidesdata;
+      while ((*dp++ = *lp++) != 0)
+       ;
+    }
+  o = dp - pool->whatprovidesdata;
+  POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
+  if (pool->whatprovidesdataoff == o)
+    return;
+  r = pool->whatprovidesdataoff - o;
+  pool->whatprovidesdataoff = o;
+  pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
+  if (r > pool->whatprovidesdataleft)
+    r = pool->whatprovidesdataleft;
+  memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
+}
+
+/* this gets rid of all the zeros in the aux */
+static void
+pool_shrink_whatprovidesaux(Pool *pool)
+{
+  int num = pool->whatprovidesauxoff;
+  Id id;
+  Offset newoff;
+  Id *op, *wp = pool->whatprovidesauxdata + 1;
+  int i;
+
+  for (i = 0; i < num; i++)
+    {
+      Offset o = pool->whatprovidesaux[i];
+      if (o < 2)
+       continue;
+      op = pool->whatprovidesauxdata + o;
+      pool->whatprovidesaux[i] = wp - pool->whatprovidesauxdata;
+      if (op < wp)
+       abort();
+      while ((id = *op++) != 0)
+       *wp++ = id;
+    }
+  newoff = wp - pool->whatprovidesauxdata;
+  pool->whatprovidesauxdata = solv_realloc(pool->whatprovidesauxdata, newoff * sizeof(Id));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesauxdata from %d to %d\n", pool->whatprovidesauxdataoff, newoff);
+  pool->whatprovidesauxdataoff = newoff;
+}
+
+
+/*
+ * pool_createwhatprovides()
+ *
+ * create hashes over pool of solvables to ease provide lookups
+ *
+ */
+void
+pool_createwhatprovides(Pool *pool)
+{
+  int i, num, np, extra;
+  Offset off;
+  Solvable *s;
+  Id id;
+  Offset *idp, n;
+  Offset *whatprovides;
+  Id *whatprovidesdata, *dp, *whatprovidesauxdata;
+  Offset *whatprovidesaux;
+  Repo *installed = pool->installed;
+  unsigned int now;
+
+  now = solv_timems(0);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "number of solvables: %d, memory used: %d K\n", pool->nsolvables, pool->nsolvables * (int)sizeof(Solvable) / 1024);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "string memory used: %d K array + %d K data,  rel memory used: %d K array\n", pool->ss.nstrings / (1024 / (int)sizeof(Id)), pool->ss.sstrings / 1024, pool->nrels * (int)sizeof(Reldep) / 1024);
+  if (pool->ss.stringhashmask || pool->relhashmask)
+    POOL_DEBUG(SOLV_DEBUG_STATS, "string hash memory: %d K, rel hash memory : %d K\n", (pool->ss.stringhashmask + 1) / (int)(1024/sizeof(Id)), (pool->relhashmask + 1) / (int)(1024/sizeof(Id)));
+
+  pool_freeidhashes(pool);     /* XXX: should not be here! */
+  pool_freewhatprovides(pool);
+  num = pool->ss.nstrings;
+  pool->whatprovides = whatprovides = solv_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
+  pool->whatprovides_rel = solv_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
+
+  /* count providers for each name */
+  for (i = pool->nsolvables - 1; i > 0; i--)
+    {
+      Id *pp;
+      s = pool->solvables + i;
+      if (!s->provides || !s->repo || s->repo->disabled)
+       continue;
+      /* we always need the installed solvable in the whatprovides data,
+         otherwise obsoletes/conflicts on them won't work */
+      if (s->repo != installed && !pool_installable(pool, s))
+       continue;
+      pp = s->repo->idarraydata + s->provides;
+      while ((id = *pp++) != 0)
+       {
+         while (ISRELDEP(id))
+           {
+             Reldep *rd = GETRELDEP(pool, id);
+             id = rd->name;
+           }
+         whatprovides[id]++;          /* inc count of providers */
+       }
+    }
+
+  off = 4;     /* first entry is undef, second is empty list, third is system solvable  */
+  np = 0;                             /* number of names provided */
+  for (i = 0, idp = whatprovides; i < num; i++, idp++)
+    {
+      n = *idp;
+      if (!n)                          /* no providers */
+       {
+         *idp = 1;                     /* offset for empty list */
+         continue;
+       }
+      off += n;                                /* make space for all providers */
+      *idp = off++;                    /* now idp points to terminating zero */
+      np++;                            /* inc # of provider 'slots' for stats */
+    }
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "provide ids: %d\n", np);
+
+  /* reserve some space for relation data */
+  extra = 2 * pool->nrels;
+  if (extra < 256)
+    extra = 256;
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
+
+  /* alloc space for all providers + extra */
+  whatprovidesdata = solv_calloc(off + extra, sizeof(Id));
+  whatprovidesdata[2] = SYSTEMSOLVABLE;
+
+  /* alloc aux vector */
+  whatprovidesauxdata = 0;
+  if (!pool->nowhatprovidesaux)
+    {
+      pool->whatprovidesaux = whatprovidesaux = solv_calloc(num, sizeof(Offset));
+      pool->whatprovidesauxoff = num;
+      pool->whatprovidesauxdataoff = off;
+      pool->whatprovidesauxdata = whatprovidesauxdata = solv_calloc(pool->whatprovidesauxdataoff, sizeof(Id));
+    }
+
+  /* now fill data for all provides */
+  for (i = pool->nsolvables - 1; i > 0; i--)
+    {
+      Id *pp;
+      s = pool->solvables + i;
+      if (!s->provides || !s->repo || s->repo->disabled)
+       continue;
+      if (s->repo != installed && !pool_installable(pool, s))
+       continue;
+
+      /* for all provides of this solvable */
+      pp = s->repo->idarraydata + s->provides;
+      while ((id = *pp++) != 0)
+       {
+         Id auxid = id;
+         while (ISRELDEP(id))
+           {
+             Reldep *rd = GETRELDEP(pool, id);
+             id = rd->name;
+           }
+         dp = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
+         if (*dp != i)         /* don't add same solvable twice */
+           {
+             dp[-1] = i;
+             whatprovides[id]--;
+           }
+         else
+           auxid = 1;
+         if (whatprovidesauxdata)
+           whatprovidesauxdata[whatprovides[id]] = auxid;
+       }
+    }
+  if (pool->whatprovidesaux)
+    memcpy(pool->whatprovidesaux, pool->whatprovides, num * sizeof(Id));
+  pool->whatprovidesdata = whatprovidesdata;
+  pool->whatprovidesdataoff = off;
+  pool->whatprovidesdataleft = extra;
+  pool_shrink_whatprovides(pool);
+  if (pool->whatprovidesaux)
+    pool_shrink_whatprovidesaux(pool);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id)));
+  if (pool->whatprovidesaux)
+    POOL_DEBUG(SOLV_DEBUG_STATS, "whatprovidesaux memory used: %d K id array, %d K data\n", pool->whatprovidesauxoff / (int)(1024/sizeof(Id)), pool->whatprovidesauxdataoff / (int)(1024/sizeof(Id)));
+
+  queue_empty(&pool->lazywhatprovidesq);
+  if ((!pool->addedfileprovides && pool->disttype == DISTTYPE_RPM) || pool->addedfileprovides == 1)
+    {
+      if (!pool->addedfileprovides)
+       POOL_DEBUG(SOLV_DEBUG_STATS, "WARNING: pool_addfileprovides was not called, this may result in slow operation\n");
+      /* lazyly add file provides */
+      for (i = 1; i < num; i++)
+       {
+         const char *str = pool->ss.stringspace + pool->ss.strings[i];
+         if (str[0] != '/')
+           continue;
+         if (pool->addedfileprovides == 1 && repodata_filelistfilter_matches(0, str))
+           continue;
+         /* setup lazy adding, but remember old value */
+         if (pool->whatprovides[i] > 1)
+           queue_push2(&pool->lazywhatprovidesq, i, pool->whatprovides[i]);
+         pool->whatprovides[i] = 0;
+         if (pool->whatprovidesaux)
+           pool->whatprovidesaux[i] = 0;       /* sorry */
+       }
+      POOL_DEBUG(SOLV_DEBUG_STATS, "lazywhatprovidesq size: %d entries\n", pool->lazywhatprovidesq.count / 2);
+    }
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "createwhatprovides took %d ms\n", solv_timems(now));
+}
+
+/*
+ * free all of our whatprovides data
+ * be careful, everything internalized with pool_queuetowhatprovides is
+ * gone, too
+ */
+void
+pool_freewhatprovides(Pool *pool)
+{
+  pool->whatprovides = solv_free(pool->whatprovides);
+  pool->whatprovides_rel = solv_free(pool->whatprovides_rel);
+  pool->whatprovidesdata = solv_free(pool->whatprovidesdata);
+  pool->whatprovidesdataoff = 0;
+  pool->whatprovidesdataleft = 0;
+  pool->whatprovidesaux = solv_free(pool->whatprovidesaux);
+  pool->whatprovidesauxdata = solv_free(pool->whatprovidesauxdata);
+  pool->whatprovidesauxoff = 0;
+  pool->whatprovidesauxdataoff = 0;
+}
+
+
+/******************************************************************************/
+
+/*
+ * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
+ *
+ * used for whatprovides, jobs, learnt rules, selections
+ * input: q: queue of Ids
+ * returns: Offset into whatprovidesdata
+ *
+ */
+
+Id
+pool_ids2whatprovides(Pool *pool, Id *ids, int count)
+{
+  Offset off;
+
+  if (count == 0)                     /* queue empty -> 1 */
+    return 1;
+  if (count == 1 && *ids == SYSTEMSOLVABLE)
+    return 2;
+
+  /* extend whatprovidesdata if needed, +1 for 0-termination */
+  if (pool->whatprovidesdataleft < count + 1)
+    {
+      POOL_DEBUG(SOLV_DEBUG_STATS, "growing provides hash data...\n");
+      pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
+      pool->whatprovidesdataleft = count + 4096;
+    }
+
+  /* copy queue to next free slot */
+  off = pool->whatprovidesdataoff;
+  memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, ids, count * sizeof(Id));
+
+  /* adapt count and 0-terminate */
+  pool->whatprovidesdataoff += count;
+  pool->whatprovidesdata[pool->whatprovidesdataoff++] = 0;
+  pool->whatprovidesdataleft -= count + 1;
+
+  return (Id)off;
+}
+
+Id
+pool_queuetowhatprovides(Pool *pool, Queue *q)
+{
+  int count = q->count;
+  if (count == 0)                     /* queue empty -> 1 */
+    return 1;
+  if (count == 1 && q->elements[0] == SYSTEMSOLVABLE)
+    return 2;
+  return pool_ids2whatprovides(pool, q->elements, count);
+}
+
+
+/*************************************************************************/
+
+#if defined(MULTI_SEMANTICS)
+# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
+#elif defined(DEBIAN)
+# define EVRCMP_DEPCMP EVRCMP_COMPARE
+#else
+# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
+#endif
+
+/* check if a package's nevr matches a dependency */
+/* semi-private, called from public pool_match_nevr */
+
+int
+pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
+{
+  Reldep *rd = GETRELDEP(pool, d);
+  Id name = rd->name;
+  Id evr = rd->evr;
+  int flags = rd->flags;
+
+  if (flags > 7)
+    {
+      switch (flags)
+       {
+       case REL_ARCH:
+         if (s->arch != evr)
+           {
+             if (evr != ARCH_SRC || s->arch != ARCH_NOSRC)
+               return 0;
+           }
+         return pool_match_nevr(pool, s, name);
+       case REL_OR:
+         if (pool_match_nevr(pool, s, name))
+           return 1;
+         return pool_match_nevr(pool, s, evr);
+       case REL_AND:
+       case REL_WITH:
+         if (!pool_match_nevr(pool, s, name))
+           return 0;
+         return pool_match_nevr(pool, s, evr);
+       case REL_WITHOUT:
+         if (!pool_match_nevr(pool, s, name))
+           return 0;
+         return !pool_match_nevr(pool, s, evr);
+       case REL_MULTIARCH:
+         if (evr != ARCH_ANY)
+           return 0;
+         /* XXX : need to check for Multi-Arch: allowed! */
+         return pool_match_nevr(pool, s, name);
+       default:
+         return 0;
+       }
+    }
+  if (!pool_match_nevr(pool, s, name))
+    return 0;
+  if (evr == s->evr)
+    return (flags & REL_EQ) ? 1 : 0;
+  if (!flags)
+    return 0;
+  if (flags == 7)
+    return 1;
+  switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP))
+    {
+    case -2:
+      return 1;
+    case -1:
+      return (flags & REL_LT) ? 1 : 0;
+    case 0:
+      return (flags & REL_EQ) ? 1 : 0;
+    case 1:
+      return (flags & REL_GT) ? 1 : 0;
+    case 2:
+      return (flags & REL_EQ) ? 1 : 0;
+    default:
+      break;
+    }
+  return 0;
+}
+
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+/* forward declaration */
+static int pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr);
+#endif
+
+/* match (flags, evr) against provider (pflags, pevr) */
+static inline int
+pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
+{
+  if (!pflags || !flags || pflags >= 8 || flags >= 8)
+    return 0;
+  if (flags == 7 || pflags == 7)
+    return 1;          /* rel provides every version */
+  if ((pflags & flags & (REL_LT | REL_GT)) != 0)
+    return 1;          /* both rels show in the same direction */
+  if (pevr == evr)
+    return (flags & pflags & REL_EQ) ? 1 : 0;
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+  if (ISRELDEP(pevr))
+    {
+      Reldep *rd = GETRELDEP(pool, pevr);
+      if (rd->flags == REL_COMPAT)
+       return pool_match_flags_evr_rel_compat(pool, rd, flags, evr);
+    }
+#endif
+  switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP))
+    {
+    case -2:
+      return (pflags & REL_EQ) ? 1 : 0;
+    case -1:
+      return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0;
+    case 0:
+      return (flags & pflags & REL_EQ) ? 1 : 0;
+    case 1:
+      return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0;
+    case 2:
+      return (flags & REL_EQ) ? 1 : 0;
+    default:
+      break;
+    }
+  return 0;
+}
+
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+static int
+pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr)
+{
+  /* range->name is the actual version, range->evr the backwards compatibility
+     version. If flags are '>=' or '>', we match the compatibility version
+     as well, otherwise only the actual version. */
+  if (!(flags & REL_GT) || (flags & REL_LT))
+    return pool_match_flags_evr(pool, REL_EQ, range->name, flags, evr);
+  return pool_match_flags_evr(pool, REL_LT | REL_EQ, range->name, flags, evr) &&
+         pool_match_flags_evr(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr);
+}
+#endif
+
+/* public (i.e. not inlined) version of pool_match_flags_evr */
+int
+pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, Id evr)
+{
+  return pool_match_flags_evr(pool, pflags, pevr, flags, evr);
+}
+
+/* match two dependencies (d1 = provider) */
+
+int
+pool_match_dep(Pool *pool, Id d1, Id d2)
+{
+  Reldep *rd1, *rd2;
+
+  if (d1 == d2)
+    return 1;
+
+  if (ISRELDEP(d1))
+    {
+      /* we use potentially matches for complex deps */
+      rd1 = GETRELDEP(pool, d1);
+      if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_WITHOUT || rd1->flags == REL_COND || rd1->flags == REL_UNLESS)
+       {
+         if (pool_match_dep(pool, rd1->name, d2))
+           return 1;
+         if ((rd1->flags == REL_COND || rd1->flags == REL_UNLESS) && ISRELDEP(rd1->evr))
+           {
+             rd1 = GETRELDEP(pool, rd1->evr);
+             if (rd1->flags != REL_ELSE)
+               return 0;
+           }
+         if (rd1->flags != REL_COND && rd1->flags != REL_UNLESS && rd1->flags != REL_WITHOUT && pool_match_dep(pool, rd1->evr, d2))
+           return 1;
+         return 0;
+       }
+    }
+  if (ISRELDEP(d2))
+    {
+      /* we use potentially matches for complex deps */
+      rd2 = GETRELDEP(pool, d2);
+      if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_WITHOUT || rd2->flags == REL_COND || rd2->flags == REL_UNLESS)
+       {
+         if (pool_match_dep(pool, d1, rd2->name))
+           return 1;
+         if ((rd2->flags == REL_COND || rd2->flags == REL_UNLESS) && ISRELDEP(rd2->evr))
+           {
+             rd2 = GETRELDEP(pool, rd2->evr);
+             if (rd2->flags != REL_ELSE)
+               return 0;
+           }
+         if (rd2->flags != REL_COND && rd2->flags != REL_UNLESS && rd2->flags != REL_WITHOUT && pool_match_dep(pool, d1, rd2->evr))
+           return 1;
+         return 0;
+       }
+    }
+  if (!ISRELDEP(d1))
+    {
+      if (!ISRELDEP(d2))
+       return 0;       /* cannot match as d1 != d2 */
+      rd2 = GETRELDEP(pool, d2);
+      return pool_match_dep(pool, d1, rd2->name);
+    }
+  rd1 = GETRELDEP(pool, d1);
+  if (!ISRELDEP(d2))
+    {
+      return pool_match_dep(pool, rd1->name, d2);
+    }
+  rd2 = GETRELDEP(pool, d2);
+  /* first match name */
+  if (!pool_match_dep(pool, rd1->name, rd2->name))
+    return 0;
+  /* name matches, check flags and evr */
+  return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
+}
+
+Id
+pool_searchlazywhatprovidesq(Pool *pool, Id d)
+{
+  int start = 0;
+  int end = pool->lazywhatprovidesq.count;
+  Id *elements;
+  if (!end)
+    return 0;
+  elements = pool->lazywhatprovidesq.elements;
+  while (end - start > 16)
+    {
+      int mid = (start + end) / 2 & ~1;
+      if (elements[mid] == d)
+       return elements[mid + 1];
+      if (elements[mid] < d)
+       start = mid + 2;
+      else
+       end = mid;
+    }
+  for (; start < end; start += 2)
+    if (elements[start] == d)
+      return elements[start + 1];
+  return 0;
+}
+
+/*
+ * addstdproviders
+ *
+ * lazy populating of the whatprovides array, non relation case
+ */
+static Id
+pool_addstdproviders(Pool *pool, Id d)
+{
+  const char *str;
+  Queue q;
+  Id qbuf[16];
+  Dataiterator di;
+  Id oldoffset;
+
+  if (pool->addedfileprovides == 2)
+    {
+      pool->whatprovides[d] = 1;
+      return 1;
+    }
+  str =  pool->ss.stringspace + pool->ss.strings[d];
+  if (*str != '/')
+    {
+      pool->whatprovides[d] = 1;
+      return 1;
+    }
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES);
+  for (; dataiterator_step(&di); dataiterator_skip_solvable(&di))
+    {
+      Solvable *s = pool->solvables + di.solvid;
+      /* XXX: maybe should add a provides dependency to the solvables
+       * OTOH this is only needed for rel deps that filter the provides,
+       * and those should not use filelist entries */
+      if (s->repo->disabled)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;
+      queue_push(&q, di.solvid);
+    }
+  dataiterator_free(&di);
+  oldoffset = pool_searchlazywhatprovidesq(pool, d);
+  if (!q.count)
+    pool->whatprovides[d] = oldoffset ? oldoffset : 1;
+  else
+    {
+      if (oldoffset)
+       {
+         Id *oo = pool->whatprovidesdata + oldoffset;
+         int i;
+         /* unify both queues. easy, as we know both are sorted */
+         for (i = 0; i < q.count; i++)
+           {
+             if (*oo > q.elements[i])
+               continue;
+             if (*oo < q.elements[i])
+               queue_insert(&q, i, *oo);
+             oo++;
+             if (!*oo)
+               break;
+           }
+         while (*oo)
+           queue_push(&q, *oo++);
+         if (q.count == oo - (pool->whatprovidesdata + oldoffset))
+           {
+             /* end result has same size as oldoffset -> no new entries */
+             queue_free(&q);
+             pool->whatprovides[d] = oldoffset;
+             return oldoffset;
+           }
+       }
+      pool->whatprovides[d] = pool_queuetowhatprovides(pool, &q);
+    }
+  queue_free(&q);
+  return pool->whatprovides[d];
+}
+
+
+static inline int
+pool_is_kind(Pool *pool, Id name, Id kind)
+{
+  const char *n;
+  if (!kind)
+    return 1;
+  n = pool_id2str(pool, name);
+  if (kind != 1)
+    {
+      const char *kn = pool_id2str(pool, kind);
+      int knl = strlen(kn);
+      return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
+    }
+  else
+    {
+      if (*n == ':')
+       return 1;
+      while(*n >= 'a' && *n <= 'z')
+       n++;
+      return *n == ':' ? 0 : 1;
+    }
+}
+
+/*
+ * rpm eq magic:
+ *
+ * some dependencies are of the from "foo = md5sum", like the
+ * buildid provides. There's not much we can do to speed up
+ * getting the providers, because rpm's complex evr comparison
+ * rules get in the way. But we can use the first character(s)
+ * of the md5sum to do a simple pre-check.
+ */
+static inline int
+rpmeqmagic(Pool *pool, Id evr)
+{
+  const char *s = pool_id2str(pool, evr);
+  if (*s == '0')
+    {
+      while (*s == '0' && s[1] >= '0' && s[1] <= '9')
+       s++;
+      /* ignore epoch 0 */
+      if (*s == '0' && s[1] == ':')
+       {
+         s += 2;
+         while (*s == '0' && s[1] >= '0' && s[1] <= '9')
+           s++;
+       }
+    }
+  if (*s >= '0' && *s <= '9')
+    {
+      if (s[1] >= '0' && s[1] <= '9')
+        return *s + (s[1] << 8);
+      return *s;
+    }
+  if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z'))
+    {
+      if ((s[1] >= 'a' && s[1] <= 'z') || (s[1] >= 'A' && s[1] <= 'Z'))
+        return *s + (s[1] << 8);
+      return *s;
+    }
+  return -1;
+}
+
+static inline int
+rpmeqmagic_init(Pool *pool, int flags, Id evr)
+{
+  if (flags != REL_EQ || pool->disttype != DISTTYPE_RPM || pool->promoteepoch || ISRELDEP(evr))
+    return -1;
+  else
+    return rpmeqmagic(pool, evr);
+}
+
+static inline int
+rpmeqmagic_cantmatch(Pool *pool, int flags, Id evr, int eqmagic)
+{
+  int peqmagic = rpmeqmagic(pool, evr);
+  if (peqmagic > 0 && peqmagic != eqmagic)
+    return 1;
+  return 0;
+}
+
+/*
+ * addrelproviders
+ *
+ * add packages fulfilling the relation to whatprovides array
+ *
+ * some words about REL_AND and REL_IF: we assume the best case
+ * here, so that you get a "potential" result if you ask for a match.
+ * E.g. if you ask for "whatrequires A" and package X contains
+ * "Requires: A & B", you'll get "X" as an answer.
+ */
+Id
+pool_addrelproviders(Pool *pool, Id d)
+{
+  Reldep *rd;
+  Reldep *prd;
+  Queue plist;
+  Id buf[16];
+  Id name, evr, flags;
+  Id pid, *pidp;
+  Id p, *pp;
+
+  if (!ISRELDEP(d))
+    return pool_addstdproviders(pool, d);
+  rd = GETRELDEP(pool, d);
+  name = rd->name;
+  evr = rd->evr;
+  flags = rd->flags;
+  d = GETRELID(d);
+  queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
+
+  if (flags >= 8)
+    {
+      /* special relation */
+      Id wp = 0;
+      Id *pp2, *pp3;
+
+      switch (flags)
+       {
+       case REL_WITH:
+         wp = pool_whatprovides(pool, name);
+         pp2 = pool_whatprovides_ptr(pool, evr);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
+           {
+             for (pp3 = pp2; *pp3; pp3++)
+               if (*pp3 == p)
+                 break;
+             if (*pp3)
+               queue_push(&plist, p);  /* found it */
+             else
+               wp = 0;
+           }
+         break;
+       case REL_WITHOUT:
+         wp = pool_whatprovides(pool, name);
+         pp2 = pool_whatprovides_ptr(pool, evr);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
+           {
+             for (pp3 = pp2; *pp3; pp3++)
+               if (*pp3 == p)
+                 break;
+             if (!*pp3)
+               queue_push(&plist, p);  /* use it */
+             else
+               wp = 0;
+           }
+         break;
+       case REL_AND:
+       case REL_OR:
+       case REL_COND:
+       case REL_UNLESS:
+         if (flags == REL_COND || flags == REL_UNLESS)
+           {
+             if (ISRELDEP(evr))
+               {
+                 Reldep *rd2 = GETRELDEP(pool, evr);
+                 evr = rd2->flags == REL_ELSE ? rd2->evr : 0;
+               }
+             else
+               evr = 0;        /* assume cond is true */
+           }
+         wp = pool_whatprovides(pool, name);
+         if (!pool->whatprovidesdata[wp])
+           wp = evr ? pool_whatprovides(pool, evr) : 1;
+         else if (evr)
+           {
+             /* sorted merge */
+             pp2 = pool_whatprovides_ptr(pool, evr);
+             pp = pool->whatprovidesdata + wp;
+             while (*pp && *pp2)
+               {
+                 if (*pp < *pp2)
+                   queue_push(&plist, *pp++);
+                 else
+                   {
+                     if (*pp == *pp2)
+                       pp++;
+                     queue_push(&plist, *pp2++);
+                   }
+               }
+             while (*pp)
+               queue_push(&plist, *pp++);
+             while (*pp2)
+               queue_push(&plist, *pp2++);
+             /* if the number of elements did not change, we can reuse wp */
+             if (pp - (pool->whatprovidesdata + wp) != plist.count)
+               wp = 0;
+           }
+         break;
+
+       case REL_NAMESPACE:
+         if (name == NAMESPACE_OTHERPROVIDERS)
+           {
+             wp = pool_whatprovides(pool, evr);
+             break;
+           }
+         if (pool->nscallback)
+           {
+             /* ask callback which packages provide the dependency
+              * 0:  none
+              * 1:  the system (aka SYSTEMSOLVABLE)
+              * >1: set of packages, stored as offset on whatprovidesdata
+              */
+             p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
+             if (p > 1)
+               wp = p;
+             if (p == 1)
+               queue_push(&plist, SYSTEMSOLVABLE);
+           }
+         break;
+       case REL_ARCH:
+         /* small hack: make it possible to match <pkg>.src
+          * we have to iterate over the solvables as src packages do not
+          * provide anything, thus they are not indexed in our
+          * whatprovides hash */
+         if (evr == ARCH_SRC || evr == ARCH_NOSRC)
+           {
+             Solvable *s;
+             for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
+               {
+                 if (!s->repo)
+                   continue;
+                 if (s->arch != evr && s->arch != ARCH_NOSRC)
+                   continue;
+                 if (pool_disabled_solvable(pool, s))
+                   continue;
+                 if (!name || pool_match_nevr(pool, s, name))
+                   queue_push(&plist, p);
+               }
+             break;
+           }
+         if (!name)
+           {
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->repo != pool->installed && !pool_installable(pool, s))
+                   continue;
+                 if (s->arch == evr)
+                   queue_push(&plist, p);
+               }
+             break;
+           }
+         wp = pool_whatprovides(pool, name);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
+           {
+             Solvable *s = pool->solvables + p;
+             if (s->arch == evr)
+               queue_push(&plist, p);
+             else
+               wp = 0;
+           }
+         break;
+       case REL_MULTIARCH:
+         if (evr != ARCH_ANY)
+           break;
+         /* XXX : need to check for Multi-Arch: allowed! */
+         wp = pool_whatprovides(pool, name);
+         break;
+       case REL_KIND:
+         /* package kind filtering */
+         if (!name)
+           {
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (s->repo != pool->installed && !pool_installable(pool, s))
+                   continue;
+                 if (pool_is_kind(pool, s->name, evr))
+                   queue_push(&plist, p);
+               }
+             break;
+           }
+         wp = pool_whatprovides(pool, name);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
+           {
+             Solvable *s = pool->solvables + p;
+             if (pool_is_kind(pool, s->name, evr))
+               queue_push(&plist, p);
+             else
+               wp = 0;
+           }
+         break;
+       case REL_FILECONFLICT:
+         pp = pool_whatprovides_ptr(pool, name);
+         while ((p = *pp++) != 0)
+           {
+             Id origd = MAKERELDEP(d);
+             Solvable *s = pool->solvables + p;
+             if (!s->provides)
+               continue;
+             pidp = s->repo->idarraydata + s->provides;
+             while ((pid = *pidp++) != 0)
+               if (pid == origd)
+                 break;
+             if (pid)
+               queue_push(&plist, p);
+           }
+         break;
+       default:
+         break;
+       }
+      if (wp)
+       {
+         /* we can reuse an existing entry */
+         queue_free(&plist);
+         pool->whatprovides_rel[d] = wp;
+         return wp;
+       }
+    }
+  else if (flags)
+    {
+      Id *ppaux = 0;
+      int eqmagic = 0;
+      /* simple version comparison relation */
+#if 0
+      POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
+#endif
+      pp = pool_whatprovides_ptr(pool, name);
+      if (!ISRELDEP(name) && name < pool->whatprovidesauxoff)
+       ppaux = pool->whatprovidesaux[name] ? pool->whatprovidesauxdata + pool->whatprovidesaux[name] : 0;
+      while (ISRELDEP(name))
+       {
+          rd = GETRELDEP(pool, name);
+         name = rd->name;
+       }
+      while ((p = *pp++) != 0)
+       {
+         Solvable *s = pool->solvables + p;
+         if (ppaux)
+           {
+             pid = *ppaux++;
+             if (pid && pid != 1)
+               {
+#if 0
+                 POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: aux hit %d %s\n", p, pool_dep2str(pool, pid));
+#endif
+                 if (!ISRELDEP(pid))
+                   {
+                     if (pid != name)
+                       continue;               /* wrong provides name */
+                     if (pool->disttype == DISTTYPE_DEB)
+                       continue;               /* unversioned provides can never match versioned deps */
+                   }
+                 else
+                   {
+                     prd = GETRELDEP(pool, pid);
+                     if (prd->name != name)
+                       continue;               /* wrong provides name */
+                     if (!eqmagic)
+                       eqmagic = rpmeqmagic_init(pool, flags, evr);
+                     if (eqmagic > 0 && prd->flags == REL_EQ && !ISRELDEP(prd->evr) &&
+                         rpmeqmagic_cantmatch(pool, prd->flags, prd->evr, eqmagic))
+                       continue;
+                     /* right package, both deps are rels. check flags/evr */
+                     if (!pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
+                       continue;
+                   }
+                 queue_push(&plist, p);
+                 continue;
+               }
+           }
+         if (!s->provides)
+           {
+             /* no provides - check nevr */
+             if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
+               queue_push(&plist, p);
+             continue;
+           }
+         /* solvable p provides name in some rels */
+         if (!eqmagic)
+           eqmagic = rpmeqmagic_init(pool, flags, evr);
+         pidp = s->repo->idarraydata + s->provides;
+         while ((pid = *pidp++) != 0)
+           {
+             if (!ISRELDEP(pid))
+               {
+                 if (pid != name)
+                   continue;           /* wrong provides name */
+                 if (pool->disttype == DISTTYPE_DEB)
+                   continue;           /* unversioned provides can never match versioned deps */
+                 break;
+               }
+             prd = GETRELDEP(pool, pid);
+             if (prd->name != name)
+               continue;               /* wrong provides name */
+             /* right package, both deps are rels. check flags/evr */
+             if (eqmagic > 0 && prd->flags == REL_EQ && !ISRELDEP(prd->evr) &&
+                 rpmeqmagic_cantmatch(pool, prd->flags, prd->evr, eqmagic))
+               continue;
+             if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
+               break;  /* matches */
+           }
+         if (!pid)
+           continue;   /* none of the providers matched */
+         queue_push(&plist, p);
+       }
+      /* make our system solvable provide all unknown rpmlib() stuff */
+      if (plist.count == 0 && !strncmp(pool_id2str(pool, name), "rpmlib(", 7))
+       queue_push(&plist, SYSTEMSOLVABLE);
+    }
+  /* add providers to whatprovides */
+#if 0
+  POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
+#endif
+  pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
+  queue_free(&plist);
+
+  return pool->whatprovides_rel[d];
+}
+
+void
+pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
+{
+  int nrels = pool->nrels;
+  Id d;
+  Reldep *rd;
+
+  if (!pool->whatprovides_rel)
+    return;
+  for (d = 1, rd = pool->rels + d; d < nrels; d++, rd++)
+    {
+      if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
+       continue;
+      if (ns && rd->name != ns)
+       continue;
+      if (evr && rd->evr != evr)
+       continue;
+      if (pool->whatprovides_rel[d])
+        pool_set_whatprovides(pool, MAKERELDEP(d), 0);
+    }
+}
+
+/* intersect dependencies in keyname with dep, return list of matching packages */
+void
+pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  int i;
+
+  queue_empty(q);
+  if (keyname == SOLVABLE_NAME)
+    {
+      Id pp;
+      FOR_PROVIDES(p, pp, dep)
+        if (pool_match_dep(pool, p, dep))
+         queue_push(q, p);
+      return;
+    }
+  queue_init(&qq);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (s->repo->disabled)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;
+      if (qq.count)
+       queue_empty(&qq);
+      solvable_lookup_deparray(s, keyname, &qq, marker);
+      for (i = 0; i < qq.count; i++)
+       if (pool_match_dep(pool, qq.elements[i], dep))
+         {
+           queue_push(q, p);
+           break;
+         }
+    }
+  queue_free(&qq);
+}
+
+/* check if keyname contains dep, return list of matching packages */
+void
+pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  int i;
+
+  queue_empty(q);
+  if (!dep)
+    return;
+  queue_init(&qq);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (s->repo->disabled)
+        continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+        continue;
+      if (qq.count)
+        queue_empty(&qq);
+      solvable_lookup_deparray(s, keyname, &qq, marker);
+      for (i = 0; i < qq.count; i++)
+        if (qq.elements[i] == dep)
+          {
+            queue_push(q, p);
+            break;
+          }
+    }
+  queue_free(&qq);
+}
+
+/* intersect dependencies in keyname with all provides of solvable solvid,
+ * return list of matching packages */
+/* this currently only works for installable packages */
+void
+pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  Map missc;           /* cache for misses */
+  int reloff;
+
+  queue_empty(q);
+  queue_init(&qq);
+  reloff = pool->ss.nstrings;
+  map_init(&missc, reloff + pool->nrels);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (p == solvid)
+       continue;       /* filter out self-matches */
+      if (s->repo->disabled)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;
+      if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff))
+        queue_push(q, p);
+    }
+  map_free(&missc);
+  queue_free(&qq);
+}
+
+/*************************************************************************/
+
+void
+pool_debug(Pool *pool, int type, const char *format, ...)
+{
+  va_list args;
+  char buf[1024];
+
+  if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0)
+    {
+      if ((pool->debugmask & type) == 0)
+       return;
+    }
+  va_start(args, format);
+  if (!pool->debugcallback)
+    {
+      if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0 && !(pool->debugmask & SOLV_DEBUG_TO_STDERR))
+        vprintf(format, args);
+      else
+        vfprintf(stderr, format, args);
+      return;
+    }
+  vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
+}
+
+int
+pool_error(Pool *pool, int ret, const char *format, ...)
+{
+  va_list args;
+  int l;
+
+  if (!pool)
+    return ret;
+  va_start(args, format);
+  if (!pool->errstr)
+    {
+      pool->errstra = 1024;
+      pool->errstr = solv_malloc(pool->errstra);
+    }
+  if (!*format)
+    {
+      *pool->errstr = 0;
+      l = 0;
+    }
+  else
+    l = vsnprintf(pool->errstr, pool->errstra, format, args);
+  va_end(args);
+  if (l >= 0 && l + 1 > pool->errstra)
+    {
+      pool->errstra = l + 256;
+      pool->errstr = solv_realloc(pool->errstr, pool->errstra);
+      va_start(args, format);
+      l = vsnprintf(pool->errstr, pool->errstra, format, args);
+      va_end(args);
+    }
+  if (l < 0)
+    strcpy(pool->errstr, "unknown error");
+  if (pool->debugmask & SOLV_ERROR)
+    pool_debug(pool, SOLV_ERROR, "%s\n", pool->errstr);
+  return ret;
+}
+
+char *
+pool_errstr(Pool *pool)
+{
+  return pool->errstr ? pool->errstr : "no error";
+}
+
+void
+pool_setdebuglevel(Pool *pool, int level)
+{
+  int mask = SOLV_DEBUG_RESULT;
+  if (level > 0)
+    mask |= SOLV_DEBUG_STATS|SOLV_DEBUG_ANALYZE|SOLV_DEBUG_UNSOLVABLE|SOLV_DEBUG_SOLVER|SOLV_DEBUG_TRANSACTION|SOLV_ERROR;
+  if (level > 1)
+    mask |= SOLV_DEBUG_JOB|SOLV_DEBUG_SOLUTIONS|SOLV_DEBUG_POLICY;
+  if (level > 2)
+    mask |= SOLV_DEBUG_PROPAGATE;
+  if (level > 3)
+    mask |= SOLV_DEBUG_RULE_CREATION;
+  mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR;      /* keep bit */
+  pool->debugmask = mask;
+}
+
+void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata)
+{
+  pool->debugcallback = debugcallback;
+  pool->debugcallbackdata = debugcallbackdata;
+}
+
+void pool_setdebugmask(Pool *pool, int mask)
+{
+  pool->debugmask = mask;
+}
+
+void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata)
+{
+  pool->loadcallback = cb;
+  pool->loadcallbackdata = loadcbdata;
+}
+
+void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata)
+{
+  pool->nscallback = cb;
+  pool->nscallbackdata = nscbdata;
+}
+
+void
+pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata)
+{
+  if (p)
+    {
+      if (pool->solvables[p].repo)
+        repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
+      return;
+    }
+  /* FIXME: obey callback return value! */
+  for (p = 1; p < pool->nsolvables; p++)
+    if (pool->solvables[p].repo)
+      repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
+}
+
+void
+pool_clear_pos(Pool *pool)
+{
+  memset(&pool->pos, 0, sizeof(pool->pos));
+}
+
+void
+pool_set_languages(Pool *pool, const char **languages, int nlanguages)
+{
+  int i;
+
+  pool->languagecache = solv_free(pool->languagecache);
+  pool->languagecacheother = 0;
+  for (i = 0; i < pool->nlanguages; i++)
+    free((char *)pool->languages[i]);
+  pool->languages = solv_free((void *)pool->languages);
+  pool->nlanguages = nlanguages;
+  if (!nlanguages)
+    return;
+  pool->languages = solv_calloc(nlanguages, sizeof(const char **));
+  for (i = 0; i < pool->nlanguages; i++)
+    pool->languages[i] = solv_strdup(languages[i]);
+}
+
+Id
+pool_id2langid(Pool *pool, Id id, const char *lang, int create)
+{
+  const char *n;
+  char buf[256], *p;
+  int l;
+
+  if (!lang || !*lang)
+    return id;
+  n = pool_id2str(pool, id);
+  l = strlen(n) + strlen(lang) + 2;
+  if (l > sizeof(buf))
+    p = solv_malloc(strlen(n) + strlen(lang) + 2);
+  else
+    p = buf;
+  sprintf(p, "%s:%s", n, lang);
+  id = pool_str2id(pool, p, create);
+  if (p != buf)
+    free(p);
+  return id;
+}
+
+char *
+pool_alloctmpspace(Pool *pool, int len)
+{
+  int n = pool->tmpspace.n;
+  if (!len)
+    return 0;
+  if (len > pool->tmpspace.len[n])
+    {
+      pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
+      pool->tmpspace.len[n] = len + 32;
+    }
+  pool->tmpspace.n = (n + 1) % POOL_TMPSPACEBUF;
+  return pool->tmpspace.buf[n];
+}
+
+static char *
+pool_alloctmpspace_free(Pool *pool, const char *space, int len)
+{
+  if (space)
+    {
+      int n, oldn;
+      n = oldn = pool->tmpspace.n;
+      for (;;)
+       {
+         if (!n--)
+           n = POOL_TMPSPACEBUF - 1;
+         if (n == oldn)
+           break;
+         if (pool->tmpspace.buf[n] != space)
+           continue;
+         if (len > pool->tmpspace.len[n])
+           {
+             pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
+             pool->tmpspace.len[n] = len + 32;
+           }
+          return pool->tmpspace.buf[n];
+       }
+    }
+  return 0;
+}
+
+void
+pool_freetmpspace(Pool *pool, const char *space)
+{
+  int n = pool->tmpspace.n;
+  if (!space)
+    return;
+  n = (n + (POOL_TMPSPACEBUF - 1)) % POOL_TMPSPACEBUF;
+  if (pool->tmpspace.buf[n] == space)
+    pool->tmpspace.n = n;
+}
+
+char *
+pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
+{
+  int l1, l2, l3;
+  char *s, *str;
+  l1 = str1 ? strlen(str1) : 0;
+  l2 = str2 ? strlen(str2) : 0;
+  l3 = str3 ? strlen(str3) : 0;
+  s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
+  if (l1)
+    {
+      strcpy(s, str1);
+      s += l1;
+    }
+  if (l2)
+    {
+      strcpy(s, str2);
+      s += l2;
+    }
+  if (l3)
+    {
+      strcpy(s, str3);
+      s += l3;
+    }
+  *s = 0;
+  return str;
+}
+
+char *
+pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3)
+{
+  int l1, l2, l3;
+  char *s, *str;
+
+  l1 = str1 ? strlen(str1) : 0;
+  l2 = str2 ? strlen(str2) : 0;
+  l3 = str3 ? strlen(str3) : 0;
+  str = pool_alloctmpspace_free(pool, str1, l1 + l2 + l3 + 1);
+  if (str)
+    str1 = str;
+  else
+    str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
+  s = str;
+  if (l1)
+    {
+      if (s != str1)
+        strcpy(s, str1);
+      s += l1;
+    }
+  if (l2)
+    {
+      strcpy(s, str2);
+      s += l2;
+    }
+  if (l3)
+    {
+      strcpy(s, str3);
+      s += l3;
+    }
+  *s = 0;
+  return str;
+}
+
+const char *
+pool_bin2hex(Pool *pool, const unsigned char *buf, int len)
+{
+  char *s;
+  if (!len)
+    return "";
+  s = pool_alloctmpspace(pool, 2 * len + 1);
+  solv_bin2hex(buf, len, s);
+  return s;
+}
+
+const char *
+pool_lookup_str(Pool *pool, Id entry, Id keyname)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_str(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
+  if (entry <= 0)
+    return 0;
+  return solvable_lookup_str(pool->solvables + entry, keyname);
+}
+
+Id
+pool_lookup_id(Pool *pool, Id entry, Id keyname)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_id(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
+  if (entry <= 0)
+    return 0;
+  return solvable_lookup_id(pool->solvables + entry, keyname);
+}
+
+unsigned long long
+pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_num(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, notfound);
+  if (entry <= 0)
+    return notfound;
+  return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
+}
+
+int
+pool_lookup_void(Pool *pool, Id entry, Id keyname)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_void(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
+  if (entry <= 0)
+    return 0;
+  return solvable_lookup_void(pool->solvables + entry, keyname);
+}
+
+const unsigned char *
+pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_bin_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
+  if (entry <= 0)
+    return 0;
+  return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
+}
+
+const char *
+pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
+  if (entry <= 0)
+    return 0;
+  return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
+}
+
+int
+pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q)
+{
+  if (entry == SOLVID_POS && pool->pos.repo)
+    return repo_lookup_idarray(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, q);
+  if (entry <= 0)
+    return 0;
+  return solvable_lookup_idarray(pool->solvables + entry, keyname, q);
+}
+
+const char *
+pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp)
+{
+  const char *loc;
+  if (medianrp)
+    *medianrp = 0;
+  if (entry != SOLVID_POS)
+    return 0;
+  loc = pool_lookup_str(pool, entry, DELTA_LOCATION_DIR);
+  loc = pool_tmpjoin(pool, loc, loc ? "/" : 0, pool_lookup_str(pool, entry, DELTA_LOCATION_NAME));
+  loc = pool_tmpappend(pool, loc, "-", pool_lookup_str(pool, entry, DELTA_LOCATION_EVR));
+  loc = pool_tmpappend(pool, loc, ".", pool_lookup_str(pool, entry, DELTA_LOCATION_SUFFIX));
+  return loc;
+}
+
+void
+pool_set_whatprovides(Pool *pool, Id id, Id providers)
+{
+  int d, nrels = pool->nrels;
+  Reldep *rd;
+  Map m;
+
+  /* set new entry */
+  if (ISRELDEP(id))
+    {
+      d = GETRELID(id);
+      pool->whatprovides_rel[d] = providers;
+      d++;
+    }
+  else
+    {
+      pool->whatprovides[id] = providers;
+      if (id < pool->whatprovidesauxoff)
+       pool->whatprovidesaux[id] = 0;  /* sorry */
+      d = 1;
+    }
+  if (!pool->whatprovides_rel)
+    return;
+  /* clear cache of all rels that use it */
+  map_init(&m, 0);
+  for (rd = pool->rels + d; d < nrels; d++, rd++)
+    {
+      if (rd->name == id || rd->evr == id ||
+         (m.size && ISRELDEP(rd->name) && MAPTST(&m, GETRELID(rd->name))) || 
+         (m.size && ISRELDEP(rd->evr)  && MAPTST(&m, GETRELID(rd->evr))))
+       {
+         pool->whatprovides_rel[d] = 0;        /* clear cache */
+         if (!m.size)
+           map_init(&m, nrels);
+         MAPSET(&m, d);
+       }
+    }
+  map_free(&m);
+}
+
+static void
+add_new_provider(Pool *pool, Id id, Id p)
+{
+  Queue q;
+  Id *pp;
+
+  /* find whatprovides entry */
+  while (ISRELDEP(id))
+    {
+      Reldep *rd = GETRELDEP(pool, id);
+      id = rd->name;
+    }
+
+  /* add new provider to existing list keeping it sorted */
+  queue_init(&q);
+  for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++)
+    {
+      if (*pp == p)
+       {
+         queue_free(&q);       /* already have it */
+         return;
+       }
+      if (*pp > p)
+       {
+         queue_push(&q, p);
+         p = 0;
+       }
+      queue_push(&q, *pp);
+    }
+  if (p)
+    queue_push(&q, p);
+  pool_set_whatprovides(pool, id, pool_queuetowhatprovides(pool, &q));
+  queue_free(&q);
+}
+
+void
+pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
+{
+  int hadhashes = pool->relhashtbl ? 1 : 0;
+  Solvable *s;
+  Id fn, p, q, md5;
+  Id id;
+  int i;
+
+  if (!conflicts->count)
+    return;
+  for (i = 0; i < conflicts->count; i += 6)
+    {
+      fn = conflicts->elements[i];
+      p = conflicts->elements[i + 1];
+      md5 = conflicts->elements[i + 2];
+      q = conflicts->elements[i + 4];
+      id = pool_rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
+      s = pool->solvables + p;
+      if (!s->repo)
+       continue;
+      s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
+      if (pool->whatprovides)
+       add_new_provider(pool, id, p);
+      s = pool->solvables + q;
+      if (!s->repo)
+       continue;
+      s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
+    }
+  if (!hadhashes)
+    pool_freeidhashes(pool);
+}
+
+char *
+pool_prepend_rootdir(Pool *pool, const char *path)
+{
+  if (!path)
+    return 0;
+  if (!pool->rootdir)
+    return solv_strdup(path);
+  return solv_dupjoin(pool->rootdir, "/", *path == '/' ? path + 1 : path);
+}
+
+const char *
+pool_prepend_rootdir_tmp(Pool *pool, const char *path)
+{
+  if (!path)
+    return 0;
+  if (!pool->rootdir)
+    return path;
+  return pool_tmpjoin(pool, pool->rootdir, "/", *path == '/' ? path + 1 : path);
+}
+
+void
+pool_set_rootdir(Pool *pool, const char *rootdir)
+{
+  solv_free(pool->rootdir);
+  pool->rootdir = solv_strdup(rootdir);
+}
+
+const char *
+pool_get_rootdir(Pool *pool)
+{
+  return pool->rootdir;
+}
+
+/* only used in libzypp */
+void
+pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *))
+{
+  pool->custom_vendorcheck = vendorcheck;
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/src/pool.h b/libsolv-0.7.2/src/pool.h
new file mode 100644 (file)
index 0000000..37583a1
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * pool.h
+ *
+ */
+
+#ifndef LIBSOLV_POOL_H
+#define LIBSOLV_POOL_H
+
+#include <stdio.h>
+
+#include "solvversion.h"
+#include "pooltypes.h"
+#include "poolid.h"
+#include "solvable.h"
+#include "bitmap.h"
+#include "queue.h"
+#include "strpool.h"
+
+/* well known ids */
+#include "knownid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* well known solvable */
+#define SYSTEMSOLVABLE         1
+
+
+/*----------------------------------------------- */
+
+struct s_Repo;
+struct s_Repodata;
+struct s_Repokey;
+struct s_KeyValue;
+
+typedef struct s_Datapos {
+  struct s_Repo *repo;
+  Id solvid;
+  Id repodataid;
+  Id schema;
+  Id dp;
+} Datapos;
+
+
+#ifdef LIBSOLV_INTERNAL
+
+/* how many strings to maintain (round robin) */
+#define POOL_TMPSPACEBUF 16
+
+struct s_Pool_tmpspace {
+  char *buf[POOL_TMPSPACEBUF];
+  int   len[POOL_TMPSPACEBUF];
+  int   n;
+};
+
+#endif
+
+struct s_Pool {
+  void *appdata;               /* application private pointer */
+
+  struct s_Stringpool ss;
+
+  Reldep *rels;                        /* table of rels: Id -> Reldep */
+  int nrels;                   /* number of unique rels */
+
+  struct s_Repo **repos;
+  int nrepos;                  /* repos allocated */
+  int urepos;                  /* repos in use */
+
+  struct s_Repo *installed;    /* packages considered installed */
+
+  Solvable *solvables;
+  int nsolvables;              /* solvables allocated */
+
+  const char **languages;
+  int nlanguages;
+
+  /* package manager type, deb/rpm */
+  int disttype;
+
+  Id *id2arch;                 /* map arch ids to scores */
+  unsigned char *id2color;     /* map arch ids to colors */
+  Id lastarch;                 /* size of the id2arch/id2color arrays */
+
+  Queue vendormap;             /* map vendor to vendorclasses mask */
+  const char **vendorclasses;  /* vendor equivalence classes */
+
+  /* providers data, as two-step indirect list
+   * whatprovides[Id] -> Offset into whatprovidesdata for name
+   * whatprovidesdata[Offset] -> 0-terminated list of solvables providing Id
+   */
+  Offset *whatprovides;                /* Offset to providers of a specific name, Id -> Offset  */
+  Offset *whatprovides_rel;    /* Offset to providers of a specific relation, Id -> Offset  */
+
+  Id *whatprovidesdata;                /* Ids of solvable providing Id */
+  Offset whatprovidesdataoff;  /* next free slot within whatprovidesdata */
+  int whatprovidesdataleft;    /* number of 'free slots' within whatprovidesdata */
+
+  /* If nonzero, then consider only the solvables with Ids set in this
+     bitmap for solving.  If zero, consider all solvables.  */
+  Map *considered;
+
+  /* callback for REL_NAMESPACE dependencies handled by the application  */
+  Id (*nscallback)(struct s_Pool *, void *data, Id name, Id evr);
+  void *nscallbackdata;
+
+  /* debug mask and callback */
+  int  debugmask;
+  void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str);
+  void *debugcallbackdata;
+
+  /* load callback */
+  int (*loadcallback)(struct s_Pool *, struct s_Repodata *, void *);
+  void *loadcallbackdata;
+
+  /* search position */
+  Datapos pos;
+
+  Queue pooljobs;              /* fixed jobs, like USERINSTALLED/MULTIVERSION */
+
+#ifdef LIBSOLV_INTERNAL
+  /* flags to tell the library how the installed package manager works */
+  int promoteepoch;            /* true: missing epoch is replaced by epoch of dependency   */
+  int havedistepoch;           /* true: thr release part in the evr may contain a distepoch suffix */
+  int obsoleteusesprovides;    /* true: obsoletes are matched against provides, not names */
+  int implicitobsoleteusesprovides;    /* true: implicit obsoletes due to same name are matched against provides, not names */
+  int obsoleteusescolors;      /* true: obsoletes check arch color */
+  int implicitobsoleteusescolors;      /* true: implicit obsoletes check arch color */
+  int noinstalledobsoletes;    /* true: ignore obsoletes of installed packages */
+  int forbidselfconflicts;     /* true: packages which conflict with itself are not installable */
+  int noobsoletesmultiversion; /* true: obsoletes are ignored for multiversion installs */
+
+  Id noarchid;                 /* ARCH_NOARCH, ARCH_ALL, ARCH_ANY, ... */
+
+  /* hash for rel unification */
+  Hashtable relhashtbl;                /* hashtable: (name,evr,op)Hash -> Id */
+  Hashval relhashmask;
+
+  Id *languagecache;
+  int languagecacheother;
+
+  /* our tmp space string space */
+  struct s_Pool_tmpspace tmpspace;
+
+  char *errstr;                        /* last error string */
+  int errstra;                 /* allocated space for errstr */
+
+  char *rootdir;
+
+  int (*custom_vendorcheck)(struct s_Pool *, Solvable *, Solvable *);
+
+  int addfileprovidesfiltered; /* 1: only use filtered file list for addfileprovides */
+  int addedfileprovides;       /* true: application called addfileprovides */
+  Queue lazywhatprovidesq;     /* queue to store old whatprovides offsets */
+  int nowhatprovidesaux;       /* don't allocate and use the whatprovides aux helper */
+  Offset *whatprovidesaux;
+  Offset whatprovidesauxoff;
+  Id *whatprovidesauxdata;
+  Offset whatprovidesauxdataoff;
+
+#endif
+};
+
+#define DISTTYPE_RPM   0
+#define DISTTYPE_DEB   1
+#define DISTTYPE_ARCH   2
+#define DISTTYPE_HAIKU  3
+
+#define SOLV_FATAL                     (1<<0)
+#define SOLV_ERROR                     (1<<1)
+#define SOLV_WARN                      (1<<2)
+#define SOLV_DEBUG_STATS               (1<<3)
+#define SOLV_DEBUG_RULE_CREATION       (1<<4)
+#define SOLV_DEBUG_PROPAGATE           (1<<5)
+#define SOLV_DEBUG_ANALYZE             (1<<6)
+#define SOLV_DEBUG_UNSOLVABLE          (1<<7)
+#define SOLV_DEBUG_SOLUTIONS           (1<<8)
+#define SOLV_DEBUG_POLICY              (1<<9)
+#define SOLV_DEBUG_RESULT              (1<<10)
+#define SOLV_DEBUG_JOB                 (1<<11)
+#define SOLV_DEBUG_SOLVER              (1<<12)
+#define SOLV_DEBUG_TRANSACTION         (1<<13)
+
+#define SOLV_DEBUG_TO_STDERR           (1<<30)
+
+#define POOL_FLAG_PROMOTEEPOCH                         1
+#define POOL_FLAG_FORBIDSELFCONFLICTS                  2
+#define POOL_FLAG_OBSOLETEUSESPROVIDES                 3
+#define POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES         4
+#define POOL_FLAG_OBSOLETEUSESCOLORS                   5
+#define POOL_FLAG_NOINSTALLEDOBSOLETES                 6
+#define POOL_FLAG_HAVEDISTEPOCH                                7
+#define POOL_FLAG_NOOBSOLETESMULTIVERSION              8
+#define POOL_FLAG_ADDFILEPROVIDESFILTERED              9
+#define POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS           10
+#define POOL_FLAG_NOWHATPROVIDESAUX                    11
+
+/* ----------------------------------------------- */
+
+
+/* mark dependencies with relation by setting bit31 */
+
+#define MAKERELDEP(id) ((id) | 0x80000000)
+#define ISRELDEP(id) (((id) & 0x80000000) != 0)
+#define GETRELID(id) ((id) ^ 0x80000000)                               /* returns Id */
+#define GETRELDEP(pool, id) ((pool)->rels + ((id) ^ 0x80000000))       /* returns Reldep* */
+
+#define REL_GT         1
+#define REL_EQ         2
+#define REL_LT         4
+
+#define REL_AND                16
+#define REL_OR         17
+#define REL_WITH       18
+#define REL_NAMESPACE  19
+#define REL_ARCH       20
+#define REL_FILECONFLICT       21
+#define REL_COND       22      /* OR_NOT */
+#define REL_COMPAT     23
+#define REL_KIND       24      /* for filters only */
+#define REL_MULTIARCH  25      /* debian multiarch annotation */
+#define REL_ELSE       26      /* only as evr part of REL_COND/REL_UNLESS */
+#define REL_ERROR      27      /* parse errors and the like */
+#define REL_WITHOUT    28
+#define REL_UNLESS     29      /* AND_NOT */
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+# define __attribute__(x)
+#endif
+
+extern Pool *pool_create(void);
+extern void pool_free(Pool *pool);
+extern void pool_freeallrepos(Pool *pool, int reuseids);
+
+extern void pool_setdebuglevel(Pool *pool, int level);
+extern int  pool_setdisttype(Pool *pool, int disttype);
+extern int  pool_set_flag(Pool *pool, int flag, int value);
+extern int  pool_get_flag(Pool *pool, int flag);
+
+extern void pool_debug(Pool *pool, int type, const char *format, ...) __attribute__((format(printf, 3, 4)));
+extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata);
+extern void pool_setdebugmask(Pool *pool, int mask);
+extern void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata);
+extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata);
+extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
+
+extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct s_Pool *, Solvable *, Solvable *));
+
+
+extern char *pool_alloctmpspace(Pool *pool, int len);
+extern void  pool_freetmpspace(Pool *pool, const char *space);
+extern char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3);
+extern char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
+extern const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
+
+extern void pool_set_installed(Pool *pool, struct s_Repo *repo);
+
+extern int  pool_error(Pool *pool, int ret, const char *format, ...) __attribute__((format(printf, 3, 4)));
+extern char *pool_errstr(Pool *pool);
+
+extern void pool_set_rootdir(Pool *pool, const char *rootdir);
+extern const char *pool_get_rootdir(Pool *pool);
+extern char *pool_prepend_rootdir(Pool *pool, const char *dir);
+extern const char *pool_prepend_rootdir_tmp(Pool *pool, const char *dir);
+
+/**
+ * Solvable management
+ */
+extern Id pool_add_solvable(Pool *pool);
+extern Id pool_add_solvable_block(Pool *pool, int count);
+
+extern void pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids);
+static inline Solvable *pool_id2solvable(const Pool *pool, Id p)
+{
+  return pool->solvables + p;
+}
+static inline Id pool_solvable2id(const Pool *pool, Solvable *s)
+{
+  return s - pool->solvables;
+}
+
+extern const char *pool_solvable2str(Pool *pool, Solvable *s);
+static inline const char *pool_solvid2str(Pool *pool, Id p)
+{
+  return pool_solvable2str(pool, pool->solvables + p);
+}
+
+void pool_set_languages(Pool *pool, const char **languages, int nlanguages);
+Id pool_id2langid(Pool *pool, Id id, const char *lang, int create);
+
+int pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, Id evr);
+int pool_match_dep(Pool *pool, Id d1, Id d2);
+
+/* semi private, used in pool_match_nevr */
+int pool_match_nevr_rel(Pool *pool, Solvable *s, Id d);
+
+static inline int pool_match_nevr(Pool *pool, Solvable *s, Id d)
+{
+  if (!ISRELDEP(d))
+    return d == s->name;
+  else
+    return pool_match_nevr_rel(pool, s, d);
+}
+
+
+/**
+ * Prepares a pool for solving
+ */
+extern void pool_createwhatprovides(Pool *pool);
+extern void pool_addfileprovides(Pool *pool);
+extern void pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst);
+extern void pool_freewhatprovides(Pool *pool);
+extern Id pool_queuetowhatprovides(Pool *pool, Queue *q);
+extern Id pool_ids2whatprovides(Pool *pool, Id *ids, int count);
+extern Id pool_searchlazywhatprovidesq(Pool *pool, Id d);
+
+extern Id pool_addrelproviders(Pool *pool, Id d);
+
+static inline Id pool_whatprovides(Pool *pool, Id d)
+{
+  if (!ISRELDEP(d))
+    {
+      if (pool->whatprovides[d])
+       return pool->whatprovides[d];
+    }
+  else
+    {
+      Id v = GETRELID(d);
+      if (pool->whatprovides_rel[v])
+       return pool->whatprovides_rel[v];
+    }
+  return pool_addrelproviders(pool, d);
+}
+
+static inline Id *pool_whatprovides_ptr(Pool *pool, Id d)
+{
+  Id off = pool_whatprovides(pool, d);
+  return pool->whatprovidesdata + off;
+}
+
+void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
+void pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
+void pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker);
+void pool_set_whatprovides(Pool *pool, Id id, Id providers);
+
+
+/* search the pool. the following filters are available:
+ *   p     - search just this solvable
+ *   key   - search only this key
+ *   match - key must match this string
+ */
+void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata);
+
+void pool_clear_pos(Pool *pool);
+
+/* lookup functions */
+const char *pool_lookup_str(Pool *pool, Id entry, Id keyname);
+Id pool_lookup_id(Pool *pool, Id entry, Id keyname);
+unsigned long long pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound);
+int pool_lookup_void(Pool *pool, Id entry, Id keyname);
+const unsigned char *pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep);
+int pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q);
+const char *pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep);
+const char *pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp);
+
+
+#define DUCHANGES_ONLYADD      1
+
+typedef struct s_DUChanges {
+  const char *path;
+  long long kbytes;
+  long long files;
+  int flags;
+} DUChanges;
+
+
+void pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap);
+void pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps);
+long long pool_calc_installsizechange(Pool *pool, Map *installedmap);
+
+void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts);
+
+
+
+/* loop over all providers of d */
+#define FOR_PROVIDES(v, vp, d)                                                 \
+  for (vp = pool_whatprovides(pool, d) ; (v = pool->whatprovidesdata[vp++]) != 0; )
+
+/* loop over all repositories */
+#define FOR_REPOS(repoid, r)                                           \
+  for (repoid = 1; repoid < pool->nrepos; repoid++)                    \
+    if ((r = pool->repos[repoid]) == 0)                                        \
+      continue;                                                                \
+    else
+
+#define FOR_POOL_SOLVABLES(p)                                          \
+  for (p = 2; p < pool->nsolvables; p++)                               \
+    if (pool->solvables[p].repo == 0)                                  \
+      continue;                                                                \
+    else
+
+#define POOL_DEBUG(type, ...) do {if ((pool->debugmask & (type)) != 0) pool_debug(pool, (type), __VA_ARGS__);} while (0)
+#define IF_POOLDEBUG(type) if ((pool->debugmask & (type)) != 0)
+
+/* weird suse stuff */
+void pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap);
+void pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* LIBSOLV_POOL_H */
diff --git a/libsolv-0.7.2/src/poolarch.c b/libsolv-0.7.2/src/poolarch.c
new file mode 100644 (file)
index 0000000..6727760
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * poolarch.c
+ *
+ * create architecture policies
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "poolid.h"
+#include "poolarch.h"
+#include "util.h"
+
+static const char *archpolicies[] = {
+#if defined(FEDORA) || defined(MAGEIA)
+  "x86_64",    "x86_64:athlon:i686:i586:i486:i386",
+#else
+  "x86_64",    "x86_64:i686:i586:i486:i386",
+#endif
+  "i686",      "i686:i586:i486:i386",
+  "i586",      "i586:i486:i386",
+  "i486",      "i486:i386",
+  "s390x",     "s390x:s390",
+  "ppc64",     "ppc64:ppc",
+  "ppc64p7",   "ppc64p7:ppc64:ppc",
+  "ia64",      "ia64:i686:i586:i486:i386",
+  "armv8hcnl", "armv8hcnl:armv8hnl:armv8hl:armv7hnl:armv7hl:armv6hl",
+  "armv8hnl",  "armv8hnl:armv8hl:armv7hnl:armv7hl:armv6hl",
+  "armv8hl",   "armv8hl:armv7hl:armv6hl",
+  "armv8l",    "armv8l:armv7l:armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
+  "armv7hnl",  "armv7hnl:armv7hl:armv6hl",
+  "armv7hl",   "armv7hl:armv6hl",
+  "armv7l",    "armv7l:armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
+  "armv6l",    "armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
+  "armv5tejl", "armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
+  "armv5tel",  "armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
+  "armv5tl",   "armv5tl:armv5l:armv4tl:armv4l:armv3l",
+  "armv5l",    "armv5l:armv4tl:armv4l:armv3l",
+  "armv4tl",   "armv4tl:armv4l:armv3l",
+  "armv4l",    "armv4l:armv3l",
+  "sh4a",      "sh4a:sh4",
+  "sparc64v",  "sparc64v:sparc64:sparcv9v:sparcv9:sparcv8:sparc",
+  "sparc64",   "sparc64:sparcv9:sparcv8:sparc",
+  "sparcv9v",  "sparcv9v:sparcv9:sparcv8:sparc",
+  "sparcv9",   "sparcv9:sparcv8:sparc",
+  "sparcv8",   "sparcv8:sparc",
+#if defined(FEDORA) || defined(MAGEIA)
+  "ia32e",     "ia32e:x86_64:athlon:i686:i586:i486:i386",
+  "athlon",    "athlon:i686:i586:i486:i386",
+  "amd64",     "amd64:x86_64:athlon:i686:i586:i486:i386",
+  "geode",     "geode:i586:i486:i386",
+  "ppc64iseries", "ppc64iseries:ppc64:ppc",
+  "ppc64pseries", "ppc64pseries:ppc64:ppc",
+#endif
+  0
+};
+
+void
+pool_setarch(Pool *pool, const char *arch)
+{
+  if (arch)
+    {
+      int i;
+      /* convert arch to known policy */
+      for (i = 0; archpolicies[i]; i += 2)
+       if (!strcmp(archpolicies[i], arch))
+         {
+           arch = archpolicies[i + 1];
+           break;
+         }
+    }
+  pool_setarchpolicy(pool, arch);
+}
+
+/*
+ * we support three relations:
+ *
+ * a = b   both architectures a and b are treated as equivalent
+ * a > b   a is considered a "better" architecture, the solver
+ *         should change from a to b, but must not change from b to a
+ * a : b   a is considered a "better" architecture, the solver
+ *         must not change the architecture from a to b or b to a
+ */
+void
+pool_setarchpolicy(Pool *pool, const char *arch)
+{
+  unsigned int score = 0x10001;
+  size_t l;
+  char d;
+  Id *id2arch;
+  Id id, lastarch;
+
+  pool->id2arch = solv_free(pool->id2arch);
+  pool->id2color = solv_free(pool->id2color);
+  if (!arch)
+    {
+      pool->lastarch = 0;
+      return;
+    }
+  id = pool->noarchid;
+  lastarch = id + 255;
+  /* note that we overallocate one element to be compatible with
+   * old versions that accessed id2arch[lastarch].
+   * id2arch[lastarch] will always be zero */
+  id2arch = solv_calloc(lastarch + 1, sizeof(Id));
+  id2arch[id] = 1;     /* the "noarch" class */
+
+  d = 0;
+  while (*arch)
+    {
+      l = strcspn(arch, ":=>");
+      if (l)
+       {
+         id = pool_strn2id(pool, arch, l, 1);
+         if (id >= lastarch)
+           {
+             id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id));
+             memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id));
+             lastarch = id + 255;
+           }
+         if (id2arch[id] == 0)
+           {
+             if (d == ':')
+               score += 0x10000;
+             else if (d == '>')
+               score += 0x00001;
+             id2arch[id] = score;
+           }
+       }
+      arch += l;
+      if ((d = *arch++) == 0)
+       break;
+    }
+  pool->id2arch = id2arch;
+  pool->lastarch = lastarch;
+}
+
+unsigned char
+pool_arch2color_slow(Pool *pool, Id arch)
+{
+  const char *s;
+  unsigned char color;
+
+  if ((unsigned int)arch >= (unsigned int)pool->lastarch)
+    return ARCHCOLOR_ALL;
+  if (!pool->id2color)
+    pool->id2color = solv_calloc(pool->lastarch + 1, 1);
+  s = pool_id2str(pool, arch);
+  if (arch == ARCH_NOARCH || arch == ARCH_ALL || arch == ARCH_ANY)
+    color = ARCHCOLOR_ALL;
+  else if (!strcmp(s, "s390x") || strstr(s, "64"))
+    color = ARCHCOLOR_64;
+  else
+    color = ARCHCOLOR_32;
+  pool->id2color[arch] = color;
+  return color;
+}
+
diff --git a/libsolv-0.7.2/src/poolarch.h b/libsolv-0.7.2/src/poolarch.h
new file mode 100644 (file)
index 0000000..787883b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef LIBSOLV_POOLARCH_H
+#define LIBSOLV_POOLARCH_H
+
+#include "pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void pool_setarch(Pool *, const char *);
+extern void pool_setarchpolicy(Pool *, const char *);
+extern unsigned char pool_arch2color_slow(Pool *pool, Id arch);
+
+#define ARCHCOLOR_32    1
+#define ARCHCOLOR_64    2
+#define ARCHCOLOR_ALL   255
+
+static inline unsigned char pool_arch2color(Pool *pool, Id arch)
+{
+  if ((unsigned int)arch >= (unsigned int)pool->lastarch)
+    return ARCHCOLOR_ALL;
+  if (pool->id2color && pool->id2color[arch])
+    return pool->id2color[arch];
+  return pool_arch2color_slow(pool, arch);
+}
+
+static inline int pool_colormatch(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  if (s1->arch == s2->arch)
+    return 1;
+  if ((pool_arch2color(pool, s1->arch) & pool_arch2color(pool, s2->arch)) != 0)
+    return 1;
+  return 0;
+}
+
+static inline unsigned int pool_arch2score(const Pool *pool, Id arch) {
+  return (unsigned int)arch < (unsigned int)pool->lastarch ? (unsigned int)pool->id2arch[arch] : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_POOLARCH_H */
diff --git a/libsolv-0.7.2/src/poolid.c b/libsolv-0.7.2/src/poolid.c
new file mode 100644 (file)
index 0000000..3b55f76
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * poolid.c
+ *
+ * Id management
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "pool.h"
+#include "poolid.h"
+#include "poolid_private.h"
+#include "util.h"
+
+
+/* intern string into pool, return id */
+
+Id
+pool_str2id(Pool *pool, const char *str, int create)
+{
+  int oldnstrings = pool->ss.nstrings;
+  Id id = stringpool_str2id(&pool->ss, str, create);
+  if (create && pool->whatprovides && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0)
+    {
+      /* grow whatprovides array */
+      pool->whatprovides = solv_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset));
+      memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
+    }
+  return id;
+}
+
+Id
+pool_strn2id(Pool *pool, const char *str, unsigned int len, int create)
+{
+  int oldnstrings = pool->ss.nstrings;
+  Id id = stringpool_strn2id(&pool->ss, str, len, create);
+  if (create && pool->whatprovides && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0)
+    {
+      /* grow whatprovides array */
+      pool->whatprovides = solv_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset));
+      memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
+    }
+  return id;
+}
+
+void
+pool_resize_rels_hash(Pool *pool, int numnew)
+{
+  Hashval h, hh, hashmask;
+  Hashtable hashtbl;
+  int i;
+  Reldep *rd;
+
+  if (numnew <= 0)
+    return;
+  hashmask = mkmask(pool->nrels + numnew);
+  if (hashmask <= pool->relhashmask)
+    return;    /* same as before */
+
+  /* realloc hash table */
+  pool->relhashmask = hashmask;
+  solv_free(pool->relhashtbl);
+  pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
+
+  /* rehash all rels into new hashtable */
+  for (i = 1, rd = pool->rels + i; i < pool->nrels; i++, rd++)
+    {
+      h = relhash(rd->name, rd->evr, rd->flags) & hashmask;
+      hh = HASHCHAIN_START;
+      while (hashtbl[h])
+       h = HASHCHAIN_NEXT(h, hh, hashmask);
+      hashtbl[h] = i;
+    }
+}
+
+Id
+pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create)
+{
+  Hashval h, hh, hashmask;
+  Id id;
+  Hashtable hashtbl;
+  Reldep *ran;
+
+
+  /* extend hashtable if needed */
+  hashmask = pool->relhashmask;
+  if ((Hashval)pool->nrels * 2 > hashmask)
+    {
+      pool_resize_rels_hash(pool, REL_BLOCK);
+      hashmask = pool->relhashmask;
+    }
+  hashtbl = pool->relhashtbl;
+
+  /* compute hash and check for match */
+  h = relhash(name, evr, flags) & hashmask;
+  hh = HASHCHAIN_START;
+  ran = pool->rels;
+  while ((id = hashtbl[h]) != 0)
+    {
+      if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
+       break;
+      h = HASHCHAIN_NEXT(h, hh, hashmask);
+    }
+  if (id)
+    return MAKERELDEP(id);
+
+  if (!create)
+    return ID_NULL;
+
+  id = pool->nrels++;
+  /* extend rel space if needed */
+  pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK);
+  hashtbl[h] = id;
+  ran = pool->rels + id;
+  ran->name = name;
+  ran->evr = evr;
+  ran->flags = flags;
+
+  /* extend whatprovides_rel if needed */
+  if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0)
+    {
+      pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset));
+      memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
+    }
+  return MAKERELDEP(id);
+}
+
+
+/* Id -> String
+ * for rels (returns name only) and strings
+ */
+const char *
+pool_id2str(const Pool *pool, Id id)
+{
+  while (ISRELDEP(id))
+    {
+      Reldep *rd = GETRELDEP(pool, id);
+      id = rd->name;
+    }
+  return pool->ss.stringspace + pool->ss.strings[id];
+}
+
+static const char *rels[] = {
+  " ! ",
+  " > ",
+  " = ",
+  " >= ",
+  " < ",
+  " <> ",
+  " <= ",
+  " <=> "
+};
+
+
+/* get operator for RelId */
+const char *
+pool_id2rel(const Pool *pool, Id id)
+{
+  Reldep *rd;
+  if (!ISRELDEP(id))
+    return "";
+  rd = GETRELDEP(pool, id);
+  switch (rd->flags)
+    {
+    /* debian special cases < and > */
+    /* haiku special cases <> (maybe we should use != for the others as well */
+    case 0: case REL_EQ: case REL_GT | REL_EQ:
+    case REL_LT | REL_EQ: case REL_LT | REL_EQ | REL_GT:
+#if !defined(DEBIAN) && !defined(MULTI_SEMANTICS)
+    case REL_LT: case REL_GT:
+#endif
+#if !defined(HAIKU) && !defined(MULTI_SEMANTICS)
+    case REL_LT | REL_GT:
+#endif
+      return rels[rd->flags];
+#if defined(DEBIAN) || defined(MULTI_SEMANTICS)
+    case REL_GT:
+      return pool->disttype == DISTTYPE_DEB ? " >> " : rels[rd->flags];
+    case REL_LT:
+      return pool->disttype == DISTTYPE_DEB ? " << " : rels[rd->flags];
+#endif
+#if defined(HAIKU) || defined(MULTI_SEMANTICS)
+    case REL_LT | REL_GT:
+      return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags];
+#endif
+    case REL_AND:
+      return pool->disttype == DISTTYPE_RPM ? " and " : " & ";
+    case REL_OR:
+      return pool->disttype == DISTTYPE_RPM ? " or " : " | ";
+    case REL_WITH:
+      return pool->disttype == DISTTYPE_RPM ? " with " : " + ";
+    case REL_WITHOUT:
+      return pool->disttype == DISTTYPE_RPM ? " without " : " - ";
+    case REL_NAMESPACE:
+      return " NAMESPACE ";    /* actually not used in dep2str */
+    case REL_ARCH:
+      return ".";
+    case REL_MULTIARCH:
+      return ":";
+    case REL_FILECONFLICT:
+      return " FILECONFLICT ";
+    case REL_COND:
+      return pool->disttype == DISTTYPE_RPM ? " if " : " IF ";
+    case REL_UNLESS:
+      return pool->disttype == DISTTYPE_RPM ? " unless " : " UNLESS ";
+    case REL_COMPAT:
+      return " compat >= ";
+    case REL_KIND:
+      return " KIND ";
+    case REL_ELSE:
+      return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
+    case REL_ERROR:
+      return " ERROR ";
+    default:
+      break;
+    }
+  return " ??? ";
+}
+
+
+/* get e:v.r for Id */
+const char *
+pool_id2evr(const Pool *pool, Id id)
+{
+  Reldep *rd;
+  if (!ISRELDEP(id))
+    return "";
+  rd = GETRELDEP(pool, id);
+  if (ISRELDEP(rd->evr))
+    return "(REL)";
+  return pool->ss.stringspace + pool->ss.strings[rd->evr];
+}
+
+static int
+dep2strlen(const Pool *pool, Id id)
+{
+  int l = 0;
+
+  while (ISRELDEP(id))
+    {
+      Reldep *rd = GETRELDEP(pool, id);
+      /* add 2 for parens */
+      l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id));
+      id = rd->evr;
+    }
+  return l + strlen(pool->ss.stringspace + pool->ss.strings[id]);
+}
+
+static void
+dep2strcpy(const Pool *pool, char *p, Id id, int oldrel)
+{
+  while (ISRELDEP(id))
+    {
+      Reldep *rd = GETRELDEP(pool, id);
+      int rel = rd->flags;
+      if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH || oldrel == REL_WITHOUT || oldrel == REL_COND || oldrel == REL_UNLESS || oldrel == REL_ELSE || oldrel == -1)
+       if (rel == REL_AND || rel == REL_OR || rel == REL_WITH || rel == REL_WITHOUT || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE)
+         if ((oldrel != rel || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE) && !((oldrel == REL_COND || oldrel == REL_UNLESS) && rel == REL_ELSE))
+           {
+             *p++ = '(';
+             dep2strcpy(pool, p, rd->name, rd->flags);
+             p += strlen(p);
+             strcpy(p, pool_id2rel(pool, id));
+             p += strlen(p);
+             dep2strcpy(pool, p, rd->evr, rd->flags);
+             strcat(p, ")");
+             return;
+           }
+      if (rd->flags == REL_KIND)
+       {
+         dep2strcpy(pool, p, rd->evr, rd->flags);
+         p += strlen(p);
+         *p++ = ':';
+         id = rd->name;
+         oldrel = rd->flags;
+         continue;
+       }
+      dep2strcpy(pool, p, rd->name, rd->flags);
+      p += strlen(p);
+      if (rd->flags == REL_NAMESPACE)
+       {
+         *p++ = '(';
+         dep2strcpy(pool, p, rd->evr, rd->flags);
+         strcat(p, ")");
+         return;
+       }
+      if (rd->flags == REL_FILECONFLICT)
+       {
+         *p = 0;
+         return;
+       }
+      strcpy(p, pool_id2rel(pool, id));
+      p += strlen(p);
+      id = rd->evr;
+      oldrel = rd->flags;
+    }
+  strcpy(p, pool->ss.stringspace + pool->ss.strings[id]);
+}
+
+const char *
+pool_dep2str(Pool *pool, Id id)
+{
+  char *p;
+  if (!ISRELDEP(id))
+    return pool->ss.stringspace + pool->ss.strings[id];
+  p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1);
+  dep2strcpy(pool, p, id, pool->disttype == DISTTYPE_RPM ? -1 : 0);
+  return p;
+}
+
+static void
+pool_free_rels_hash(Pool *pool)
+{
+  pool->relhashtbl = solv_free(pool->relhashtbl);
+  pool->relhashmask = 0;
+}
+
+void
+pool_shrink_strings(Pool *pool)
+{
+  /* free excessive big hashes */
+  if (pool->ss.stringhashmask && pool->ss.stringhashmask > mkmask(pool->ss.nstrings + 8192))
+    stringpool_freehash(&pool->ss);
+  stringpool_shrink(&pool->ss);
+}
+
+void
+pool_shrink_rels(Pool *pool)
+{
+  /* free excessive big hashes */
+  if (pool->relhashmask && pool->relhashmask > mkmask(pool->nrels + 4096))
+    pool_free_rels_hash(pool);
+  pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
+}
+
+/* free all hash tables */
+void
+pool_freeidhashes(Pool *pool)
+{
+  stringpool_freehash(&pool->ss);
+  pool_free_rels_hash(pool);
+}
+
+/* EOF */
diff --git a/libsolv-0.7.2/src/poolid.h b/libsolv-0.7.2/src/poolid.h
new file mode 100644 (file)
index 0000000..f832ff4
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * poolid.h
+ *
+ */
+
+#ifndef LIBSOLV_POOLID_H
+#define LIBSOLV_POOLID_H
+
+#include "pooltypes.h"
+#include "hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-----------------------------------------------
+ * Ids with relation
+ */
+
+typedef struct s_Reldep {
+  Id name;             /* "package" */
+  Id evr;              /* "0:42-3" */
+  int flags;           /* operation/relation, see REL_x in pool.h */
+} Reldep;
+
+extern Id pool_str2id(Pool *pool, const char *, int);
+extern Id pool_strn2id(Pool *pool, const char *, unsigned int, int);
+extern Id pool_rel2id(Pool *pool, Id, Id, int, int);
+extern const char *pool_id2str(const Pool *pool, Id);
+extern const char *pool_id2rel(const Pool *pool, Id);
+extern const char *pool_id2evr(const Pool *pool, Id);
+extern const char *pool_dep2str(Pool *pool, Id); /* might alloc tmpspace */
+
+extern void pool_shrink_strings(Pool *pool);
+extern void pool_shrink_rels(Pool *pool);
+extern void pool_freeidhashes(Pool *pool);
+extern void pool_resize_rels_hash(Pool *pool, int numnew);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_POOLID_H */
diff --git a/libsolv-0.7.2/src/poolid_private.h b/libsolv-0.7.2/src/poolid_private.h
new file mode 100644 (file)
index 0000000..43ff50d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * poolid_private.h
+ *
+ */
+
+#ifndef LIBSOLV_POOLID_PRIVATE_H
+#define LIBSOLV_POOLID_PRIVATE_H
+
+/* the size of all buffers is incremented in blocks
+ * these are the block values (increment values) for the
+ * rel hashtable
+ */
+#define REL_BLOCK              1023    /* hashtable for relations */
+#define WHATPROVIDES_BLOCK     1023
+
+#endif /* LIBSOLV_POOLID_PRIVATE_H */
diff --git a/libsolv-0.7.2/src/pooltypes.h b/libsolv-0.7.2/src/pooltypes.h
new file mode 100644 (file)
index 0000000..e1f77b0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * pooltypes.h
+ *
+ */
+
+#ifndef LIBSOLV_POOLTYPES_H
+#define LIBSOLV_POOLTYPES_H
+
+/* format version number for .solv files */
+#define SOLV_VERSION_0 0
+#define SOLV_VERSION_1 1
+#define SOLV_VERSION_2 2
+#define SOLV_VERSION_3 3
+#define SOLV_VERSION_4 4
+#define SOLV_VERSION_5 5
+#define SOLV_VERSION_6 6
+#define SOLV_VERSION_7 7
+#define SOLV_VERSION_8 8
+
+#define SOLV_FLAG_PREFIX_POOL 4
+#define SOLV_FLAG_SIZE_BYTES  8
+
+struct s_Stringpool;
+typedef struct s_Stringpool Stringpool;
+
+struct s_Pool;
+typedef struct s_Pool Pool;
+
+/* identifier for string values */
+typedef int Id;                /* must be signed!, since negative Id is used in solver rules to denote negation */
+
+/* offset value, e.g. used to 'point' into the stringspace */
+typedef unsigned int Offset;
+
+#endif /* LIBSOLV_POOLTYPES_H */
diff --git a/libsolv-0.7.2/src/poolvendor.c b/libsolv-0.7.2/src/poolvendor.c
new file mode 100644 (file)
index 0000000..adb84d8
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* we need FNM_CASEFOLD */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#include "pool.h"
+#include "poolid.h"
+#include "poolvendor.h"
+#include "util.h"
+
+/*
+ *  const char *vendorsclasses[] = {
+ *    "!openSUSE Build Service*",
+ *    "SUSE*",
+ *    "openSUSE*",
+ *    "SGI*",
+ *    "Novell*",
+ *    "Silicon Graphics*",
+ *    "Jpackage Project*",
+ *    "ATI Technologies Inc.*",
+ *    "Nvidia*",
+ *    0,
+ *    0,
+ *  };
+ */
+
+/* allows for 32 different vendor classes */
+
+Id pool_vendor2mask(Pool *pool, Id vendor)
+{
+  const char *vstr;
+  int i;
+  Id mask, m;
+  const char **v, *vs;
+
+  if (vendor == 0 || !pool->vendorclasses)
+    return 0;
+  for (i = 0; i < pool->vendormap.count; i += 2)
+    if (pool->vendormap.elements[i] == vendor)
+      return pool->vendormap.elements[i + 1];
+  vstr = pool_id2str(pool, vendor);
+  m = 1;
+  mask = 0;
+  for (v = pool->vendorclasses; ; v++)
+    {
+      vs = *v;
+      if (vs == 0)     /* end of block? */
+       {
+         v++;
+         if (*v == 0)
+           break;
+         if (m == (1 << 31))
+           break;      /* sorry, out of bits */
+         m <<= 1;      /* next vendor equivalence class */
+       }
+      if (fnmatch(*vs == '!' ? vs + 1 : vs, vstr, FNM_CASEFOLD) == 0)
+       {
+         if (*vs != '!')
+           mask |= m;
+         while (v[1])  /* forward to next block */
+           v++;
+       }
+    }
+  queue_push(&pool->vendormap, vendor);
+  queue_push(&pool->vendormap, mask);
+  return mask;
+}
+
+void
+pool_setvendorclasses(Pool *pool, const char **vendorclasses)
+{
+  int i;
+  const char **v;
+
+  if (pool->vendorclasses)
+    {
+      for (v = pool->vendorclasses; v[0] || v[1]; v++)
+       solv_free((void *)*v);
+      pool->vendorclasses = solv_free((void *)pool->vendorclasses);
+    }
+  if (!vendorclasses || !vendorclasses[0])
+    return;
+  for (v = vendorclasses; v[0] || v[1]; v++)
+    ;
+  pool->vendorclasses = solv_calloc(v - vendorclasses + 2, sizeof(const char *));
+  for (v = vendorclasses, i = 0; v[0] || v[1]; v++, i++)
+    pool->vendorclasses[i] = *v ? solv_strdup(*v) : 0;
+  pool->vendorclasses[i++] = 0;
+  pool->vendorclasses[i] = 0;
+  queue_empty(&pool->vendormap);
+}
+
+void
+pool_addvendorclass(Pool *pool, const char **vendorclass)
+{
+  int i, j;
+
+  if (!vendorclass || !vendorclass[0])
+    return;
+  for (j = 1; vendorclass[j]; j++)
+    ;
+  i = 0;
+  if (pool->vendorclasses)
+    {
+      for (i = 0; pool->vendorclasses[i] || pool->vendorclasses[i + 1]; i++)
+       ;
+      if (i)
+        i++;
+    }
+  pool->vendorclasses = solv_realloc2((void *)pool->vendorclasses, i + j + 2, sizeof(const char *));
+  for (j = 0; vendorclass[j]; j++)
+    pool->vendorclasses[i++] = solv_strdup(vendorclass[j]);
+  pool->vendorclasses[i++] = 0;
+  pool->vendorclasses[i] = 0;
+  queue_empty(&pool->vendormap);
+}
diff --git a/libsolv-0.7.2/src/poolvendor.h b/libsolv-0.7.2/src/poolvendor.h
new file mode 100644 (file)
index 0000000..873e090
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef LIBSOLV_POOLVENDOR_H
+#define LIBSOLV_POOLVENDOR_H
+
+#include "pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+Id pool_vendor2mask(Pool *pool, Id vendor);
+void pool_setvendorclasses(Pool *pool, const char **vendorclasses);
+void pool_addvendorclass(Pool *pool, const char **vendorclass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_POOLVENDOR_H */
diff --git a/libsolv-0.7.2/src/problems.c b/libsolv-0.7.2/src/problems.c
new file mode 100644 (file)
index 0000000..2b5cefd
--- /dev/null
@@ -0,0 +1,1400 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * problems.c
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "evr.h"
+#include "solverdebug.h"
+
+/**********************************************************************************/
+
+/* a problem is an item on the solver's problem list. It can either be >0, in that
+ * case it is a update/infarch/dup rule, or it can be <0, which makes it refer to a job
+ * consisting of multiple job rules.
+ */
+
+static void
+solver_disableproblem(Solver *solv, Id v)
+{
+  int i;
+  Id *jp;
+
+  if (v > 0)
+    {
+      if (v >= solv->infarchrules && v < solv->infarchrules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_disablerule(solv, solv->rules + v);
+         return;
+       }
+      if (v >= solv->duprules && v < solv->duprules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_disablerule(solv, solv->rules + v);
+         return;
+       }
+      solver_disablerule(solv, solv->rules + v);
+      return;
+    }
+  v = -(v + 1);
+  jp = solv->ruletojob.elements;
+  if (solv->bestrules_pkg)
+    {
+      int ni = solv->bestrules_up - solv->bestrules;
+      for (i = 0; i < ni; i++)
+       {
+         int j = solv->bestrules_pkg[i];
+         if (j < 0 && jp[-j - solv->jobrules] == v)
+           solver_disablerule(solv, solv->rules + solv->bestrules + i);
+       }
+    }
+  for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
+    if (*jp == v)
+      solver_disablerule(solv, solv->rules + i);
+}
+
+/*-------------------------------------------------------------------
+ * enableproblem
+ */
+
+static void
+solver_enableproblem(Solver *solv, Id v)
+{
+  Rule *r;
+  int i;
+  Id *jp;
+
+  if (v > 0)
+    {
+      if (v >= solv->infarchrules && v < solv->infarchrules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_enablerule(solv, solv->rules + v);
+         return;
+       }
+      if (v >= solv->duprules && v < solv->duprules_end)
+       {
+         Pool *pool = solv->pool;
+         Id name = pool->solvables[-solv->rules[v].p].name;
+         while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
+           v--;
+         for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
+           solver_enablerule(solv, solv->rules + v);
+         return;
+       }
+      if (v >= solv->featurerules && v < solv->featurerules_end)
+       {
+         /* do not enable feature rule if update rule is enabled */
+         r = solv->rules + (v - solv->featurerules + solv->updaterules);
+         if (r->d >= 0)
+           return;
+       }
+      solver_enablerule(solv, solv->rules + v);
+      if (v >= solv->updaterules && v < solv->updaterules_end)
+       {
+         /* disable feature rule when enabling update rule */
+         r = solv->rules + (v - solv->updaterules + solv->featurerules);
+         if (r->p)
+           solver_disablerule(solv, r);
+       }
+      return;
+    }
+  v = -(v + 1);
+  jp = solv->ruletojob.elements;
+  if (solv->bestrules_pkg)
+    {
+      int ni = solv->bestrules_up - solv->bestrules;
+      for (i = 0; i < ni; i++)
+       {
+         int j = solv->bestrules_pkg[i];
+         if (j < 0 && jp[-j - solv->jobrules] == v)
+           solver_enablerule(solv, solv->rules + solv->bestrules + i);
+       }
+    }
+  for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
+    if (*jp == v)
+      solver_enablerule(solv, solv->rules + i);
+}
+
+
+/*-------------------------------------------------------------------
+ * turn a problem rule into a problem id by normalizing it
+ */
+static Id
+solver_ruletoproblem(Solver *solv, Id rid)
+{
+  if (rid >= solv->jobrules && rid < solv->jobrules_end)
+    rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1);
+  else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_pkg[rid - solv->bestrules] < 0)
+    rid = -(solv->ruletojob.elements[-solv->bestrules_pkg[rid - solv->bestrules] - solv->jobrules] + 1);
+  else if (rid > solv->infarchrules && rid < solv->infarchrules_end)
+    {
+      Pool *pool = solv->pool;
+      Id name = pool->solvables[-solv->rules[rid].p].name;
+      while (rid > solv->infarchrules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+        rid--;
+    }
+  else if (rid > solv->duprules && rid < solv->duprules_end)
+    {
+      Pool *pool = solv->pool;
+      Id name = pool->solvables[-solv->rules[rid].p].name;
+      while (rid > solv->duprules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+        rid--;
+    }
+  return rid;
+}
+
+/*-------------------------------------------------------------------
+ * when the solver runs into a problem, it needs to disable all
+ * involved non-pkg rules and record the rules for solution
+ * generation.
+ */
+void
+solver_recordproblem(Solver *solv, Id rid)
+{
+  Id v = solver_ruletoproblem(solv, rid);
+  /* return if problem already countains our rule */
+  if (solv->problems.count)
+    {
+      int i;
+      for (i = solv->problems.count - 1; i >= 0; i--)
+        if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
+          break;
+        else if (solv->problems.elements[i] == v)
+          return;
+    }
+  queue_push(&solv->problems, v);
+}
+
+/*-------------------------------------------------------------------
+ * this is called when a problem is solved by disabling a rule.
+ * It calls disableproblem and then re-enables policy rules
+ */
+void
+solver_fixproblem(Solver *solv, Id rid)
+{
+  Id v = solver_ruletoproblem(solv, rid);
+  solver_disableproblem(solv, v);
+  if (v < 0)
+    solver_reenablepolicyrules(solv, -v);
+}
+
+/*-------------------------------------------------------------------
+ * disable a set of problems
+ */
+void
+solver_disableproblemset(Solver *solv, int start)
+{
+  int i;
+  for (i = start + 1; i < solv->problems.count - 1; i++)
+    solver_disableproblem(solv, solv->problems.elements[i]);
+}
+
+/*-------------------------------------------------------------------
+ * try to fix a problem by auto-uninstalling packages
+ */
+Id
+solver_autouninstall(Solver *solv, int start)
+{
+  Pool *pool = solv->pool;
+  int i;
+  int lastfeature = 0, lastupdate = 0;
+  Id v;
+  Id extraflags = -1;
+  Map *m = 0;
+
+  if (!solv->allowuninstall && !solv->allowuninstall_all)
+    {
+      if (!solv->allowuninstallmap.size)
+       return 0;               /* why did we get called? */
+      m = &solv->allowuninstallmap;
+    }
+  for (i = start + 1; i < solv->problems.count - 1; i++)
+    {
+      v = solv->problems.elements[i];
+      if (v < 0)
+       extraflags &= solv->job.elements[-v - 1];
+      if (v >= solv->updaterules && v < solv->updaterules_end)
+       {
+         Rule *r;
+         Id p = solv->installed->start + (v - solv->updaterules);
+         if (m && !MAPTST(m, v - solv->updaterules))
+           continue;
+         if (pool->considered && !MAPTST(pool->considered, p))
+           continue;   /* do not uninstalled disabled packages */
+         if (solv->bestrules_pkg && solv->bestrules_end > solv->bestrules)
+           {
+             int j;
+             for (j = start + 1; j < solv->problems.count - 1; j++)
+               {
+                 Id vv = solv->problems.elements[j];
+                 if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_pkg[vv - solv->bestrules] == p)
+                   break;
+               }
+             if (j < solv->problems.count - 1)
+               continue;       /* best rule involved, do not uninstall */
+           }
+         /* check if identical to feature rule, we don't like that (except for orphans) */
+         r = solv->rules + solv->featurerules + (v - solv->updaterules);
+         if (!r->p)
+           {
+             /* update rule == feature rule */
+             if (v > lastfeature)
+               lastfeature = v;
+             /* prefer orphaned packages in dup mode */
+             if (solv->keep_orphans)
+               {
+                 r = solv->rules + v;
+                 if (!r->d && !r->w2 && r->p == p)
+                   {
+                     lastfeature = v;
+                     lastupdate = 0;
+                     break;
+                   }
+               }
+             continue;
+           }
+         if (v > lastupdate)
+           lastupdate = v;
+       }
+    }
+  if (!lastupdate && !lastfeature)
+    return 0;
+  v = lastupdate ? lastupdate : lastfeature;
+  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
+  solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
+  /* should really be solver_fixproblem, but we know v is an update/feature rule */
+  solver_disableproblem(solv, v);
+  if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
+    {
+      /* add the package to the updatepkgs list, this will automatically turn
+       * on cleandeps mode */
+      Id p = solv->rules[v].p;
+      if (!solv->cleandeps_updatepkgs)
+       {
+         solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
+         queue_init(solv->cleandeps_updatepkgs);
+       }
+      if (p > 0)
+       {
+         int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
+          queue_pushunique(solv->cleandeps_updatepkgs, p);
+         if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
+           solver_disablepolicyrules(solv);
+       }
+    }
+  return v;
+}
+
+
+/*-------------------------------------------------------------------
+ * enable weak rules
+ *
+ * Reenable all disabled weak rules (marked in weakrulemap)
+ *
+ */
+
+static void
+enableweakrules(Solver *solv)
+{
+  int i;
+  Rule *r;
+
+  if (!solv->weakrulemap.size)
+    return;
+  for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
+    {
+      if (r->d >= 0) /* already enabled? */
+       continue;
+      if (!MAPTST(&solv->weakrulemap, i))
+       continue;
+      solver_enablerule(solv, r);
+    }
+  /* make sure broken orphan rules stay disabled */
+  if (solv->brokenorphanrules)
+    for (i = 0; i < solv->brokenorphanrules->count; i++)
+      solver_disablerule(solv, solv->rules + solv->brokenorphanrules->elements[i]);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * refine_suggestion
+ *
+ * at this point, all rules that led to conflicts are disabled.
+ * we re-enable all rules of a problem set but rule "sug", then
+ * continue to disable more rules until there as again a solution.
+ */
+
+/* FIXME: think about conflicting assertions */
+
+static void
+refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essentialok)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  Id v;
+  Queue disabled;
+  int disabledcnt;
+
+  IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+    {
+      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion start\n");
+      for (i = 0; problem[i]; i++)
+       {
+         if (problem[i] == sug)
+           POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "=> ");
+         solver_printproblem(solv, problem[i]);
+       }
+    }
+  queue_empty(refined);
+  if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
+    return;
+  queue_push(refined, sug);
+
+  /* re-enable all problem rules with the exception of "sug"(gestion) */
+  solver_reset(solv);
+
+  for (i = 0; problem[i]; i++)
+    if (problem[i] != sug)
+      solver_enableproblem(solv, problem[i]);
+  if (sug < 0)
+    solver_reenablepolicyrules(solv, -sug);
+
+  /* here is where the feature rules come into play: if we disabled an
+   * update rule, we enable the corresponding feature rule if there is
+   * one. We do this to make the solver downgrade packages instead of
+   * deinstalling them */
+  if (sug >= solv->updaterules && sug < solv->updaterules_end)
+    {
+      /* enable feature rule */
+      Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
+      if (r->p)
+       solver_enablerule(solv, r);
+    }
+
+  enableweakrules(solv);
+
+  /* disabled contains all of the rules we disabled in the refinement process */
+  queue_init(&disabled);
+  for (;;)
+    {
+      int nother, nfeature, nupdate, pass;
+      queue_empty(&solv->problems);
+      solver_reset(solv);
+      /* we set disablerules to zero because we are only interested in
+       * the first problem and we don't want the solver to disable the problems */
+      solver_run_sat(solv, 0, 0);
+
+      if (!solv->problems.count)
+       {
+         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no more problems!\n");
+         break;                /* great, no more problems */
+       }
+      disabledcnt = disabled.count;
+      nother = nfeature = nupdate = 0;
+      for (pass = 0; pass < 2; pass++)
+       {
+         /* start with 1 to skip over proof index */
+         for (i = 1; i < solv->problems.count - 1; i++)
+           {
+             /* ignore solutions in refined */
+             v = solv->problems.elements[i];
+             if (v == 0)
+               break;  /* end of problem reached */
+             if (!essentialok && v < 0 && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
+               continue;       /* not that one! */
+             if (sug != v)
+               {
+                 /* check if v is in the given problems list
+                  * we allow disabling all problem rules *after* sug in
+                  * pass 2, to prevent getting the same solution twice */
+                 for (j = 0; problem[j]; j++)
+                   if (problem[j] == v || (pass && problem[j] == sug))
+                     break;
+                 if (problem[j] == v)
+                   continue;
+               }
+             if (v >= solv->featurerules && v < solv->featurerules_end)
+               nfeature++;
+             else if (v > solv->updaterules && v < solv->updaterules_end)
+               nupdate++;
+             else
+               nother++;
+             queue_push(&disabled, v);
+           }
+         if (disabled.count != disabledcnt)
+           break;
+       }
+      if (disabled.count == disabledcnt)
+       {
+         /* no solution found, this was an invalid suggestion! */
+         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no solution found!\n");
+         refined->count = 0;
+         break;
+       }
+      if (!nother && nupdate && nfeature)
+       {
+         /* got only update rules, filter out feature rules */
+         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
+         for (i = j = disabledcnt; i < disabled.count; i++)
+           {
+             v = disabled.elements[i];
+             if (v < solv->featurerules || v >= solv->featurerules_end)
+               disabled.elements[j++] = v;
+           }
+         disabled.count = j;
+         nfeature = 0;
+       }
+      if (disabled.count == disabledcnt + 1)
+       {
+         /* just one suggestion, add it to refined list */
+         v = disabled.elements[disabledcnt];
+         if (!nfeature && v != sug)
+           queue_push(refined, v);     /* do not record feature rules */
+         solver_disableproblem(solv, v);
+         if (v < 0)
+           solver_reenablepolicyrules(solv, -v);
+         if (v >= solv->updaterules && v < solv->updaterules_end)
+           {
+             Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
+             if (r->p)
+               solver_enablerule(solv, r);     /* enable corresponding feature rule */
+           }
+       }
+      else
+       {
+         /* more than one solution, disable all */
+         /* do not push anything on refine list, as we do not know which solution to choose */
+         /* thus, the user will get another problem if he selects this solution, where he
+           * can choose the right one */
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "more than one solution found:\n");
+             for (i = disabledcnt; i < disabled.count; i++)
+               solver_printproblem(solv, disabled.elements[i]);
+           }
+         for (i = disabledcnt; i < disabled.count; i++)
+           {
+             v = disabled.elements[i];
+             solver_disableproblem(solv, v);
+             if (v >= solv->updaterules && v < solv->updaterules_end)
+               {
+                 Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
+                 if (r->p)
+                   solver_enablerule(solv, r);
+               }
+           }
+       }
+    }
+  /* all done, get us back into the same state as before */
+  /* enable refined rules again */
+  for (i = 0; i < disabled.count; i++)
+    solver_enableproblem(solv, disabled.elements[i]);
+  queue_free(&disabled);
+
+  /* reset policy rules */
+  for (i = 0; problem[i]; i++)
+    solver_enableproblem(solv, problem[i]);
+  solver_disablepolicyrules(solv);
+  /* disable problem rules again */
+  for (i = 0; problem[i]; i++)
+    solver_disableproblem(solv, problem[i]);
+  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion end\n");
+}
+
+
+/*-------------------------------------------------------------------
+ * sorting helper for problems
+ *
+ * bring update rules before job rules
+ * make essential job rules last
+ */
+
+static int
+problems_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Queue *job = dp;
+  Id a = *(Id *)ap, b = *(Id *)bp;
+  if (a < 0 && b > 0)
+    return 1;
+  if (a > 0 && b < 0)
+    return -1;
+  if (a < 0 && b < 0)
+    {
+      int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
+      int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
+      int x = af - bf;
+      if (x)
+       return x;
+    }
+  return a - b;
+}
+
+/*
+ * convert a solution rule into a job modifier
+ */
+static void
+convertsolution(Solver *solv, Id why, Queue *solutionq)
+{
+  Pool *pool = solv->pool;
+  if (why < 0)
+    {
+      why = -why;
+      if (why < solv->pooljobcnt)
+       {
+         queue_push(solutionq, SOLVER_SOLUTION_POOLJOB);
+         queue_push(solutionq, why);
+       }
+      else
+       {
+         queue_push(solutionq, SOLVER_SOLUTION_JOB);
+         queue_push(solutionq, why - solv->pooljobcnt);
+       }
+      return;
+    }
+  if (why >= solv->infarchrules && why < solv->infarchrules_end)
+    {
+      Id p, name;
+      /* infarch rule, find replacement */
+      assert(solv->rules[why].p < 0);
+      name = pool->solvables[-solv->rules[why].p].name;
+      while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
+       why--;
+      p = 0;
+      for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+       if (solv->decisionmap[-solv->rules[why].p] > 0)
+         {
+           p = -solv->rules[why].p;
+           break;
+         }
+      if (!p)
+       return;         /* false alarm */
+      queue_push(solutionq, SOLVER_SOLUTION_INFARCH);
+      queue_push(solutionq, p);
+      return;
+    }
+  if (why >= solv->duprules && why < solv->duprules_end)
+    {
+      Id p, name;
+      /* dist upgrade rule, find replacement */
+      assert(solv->rules[why].p < 0);
+      name = pool->solvables[-solv->rules[why].p].name;
+      while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
+       why--;
+      p = 0;
+      for (; why < solv->duprules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
+       if (solv->decisionmap[-solv->rules[why].p] > 0)
+         {
+           p = -solv->rules[why].p;
+           break;
+         }
+      if (!p)
+       return;         /* false alarm */
+      queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
+      queue_push(solutionq, p);
+      return;
+    }
+  if (why >= solv->updaterules && why < solv->updaterules_end)
+    {
+      /* update rule, find replacement package */
+      Id p, pp, rp = 0;
+      Rule *rr;
+
+      /* check if this is a false positive, i.e. the update rule is fulfilled */
+      rr = solv->rules + why;
+      FOR_RULELITERALS(p, pp, rr)
+       if (p > 0 && solv->decisionmap[p] > 0)
+         return;       /* false alarm */
+
+      p = solv->installed->start + (why - solv->updaterules);
+      if (solv->decisionmap[p] > 0)
+       return;         /* false alarm, turned out we can keep the package */
+      rr = solv->rules + solv->featurerules + (why - solv->updaterules);
+      if (!rr->p)
+       rr = solv->rules + why;
+      if (rr->w2)
+       {
+         int mvrp = 0;         /* multi-version replacement */
+         FOR_RULELITERALS(rp, pp, rr)
+           {
+             if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
+               {
+                 mvrp = rp;
+                 if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp)))
+                   break;
+               }
+           }
+         if (!rp && mvrp)
+           {
+             /* found only multi-version replacements */
+             /* have to split solution into two parts */
+             queue_push(solutionq, p);
+             queue_push(solutionq, mvrp);
+           }
+       }
+      queue_push(solutionq, p);
+      queue_push(solutionq, rp);
+      return;
+    }
+  if (why >= solv->bestrules && why < solv->bestrules_end)
+    {
+      int mvrp;
+      Id p, pp, rp = 0;
+      Rule *rr;
+      /* check false positive */
+      rr = solv->rules + why;
+      FOR_RULELITERALS(p, pp, rr)
+       if (p > 0 && solv->decisionmap[p] > 0)
+         return;       /* false alarm */
+      /* check update/feature rule */
+      p = solv->bestrules_pkg[why - solv->bestrules];
+      if (p < 0)
+       {
+         /* install job */
+         queue_push(solutionq, 0);
+         queue_push(solutionq, solv->ruletojob.elements[-p - solv->jobrules] + 1);
+         return;
+       }
+      if (solv->decisionmap[p] > 0)
+       {
+         /* disable best rule by keeping the old package */
+         queue_push(solutionq, SOLVER_SOLUTION_BEST);
+         queue_push(solutionq, p);
+         return;
+       }
+      rr = solv->rules + solv->featurerules + (p - solv->installed->start);
+      if (!rr->p)
+       rr = solv->rules + solv->updaterules + (p - solv->installed->start);
+      mvrp = 0;                /* multi-version replacement */
+      FOR_RULELITERALS(rp, pp, rr)
+       if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
+         {
+           mvrp = rp;
+           if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp)))
+             break;
+         }
+      if (!rp && mvrp)
+       {
+         queue_push(solutionq, SOLVER_SOLUTION_BEST);  /* split, see above */
+         queue_push(solutionq, mvrp);
+         queue_push(solutionq, p);
+         queue_push(solutionq, 0);
+         return;
+       }
+      if (rp)
+       {
+         queue_push(solutionq, SOLVER_SOLUTION_BEST);
+         queue_push(solutionq, rp);
+       }
+      return;
+    }
+}
+
+/*
+ * convert problem data into a form usable for refining.
+ * Returns the number of problems.
+ */
+int
+solver_prepare_solutions(Solver *solv)
+{
+  int i, j = 1, idx;
+
+  if (!solv->problems.count)
+    return 0;
+  queue_empty(&solv->solutions);
+  queue_push(&solv->solutions, 0);     /* dummy so idx is always nonzero */
+  idx = solv->solutions.count;
+  queue_push(&solv->solutions, -1);    /* unrefined */
+  /* proofidx stays in position, thus we start with 1 */
+  for (i = 1; i < solv->problems.count; i++)
+    {
+      Id p = solv->problems.elements[i];
+      queue_push(&solv->solutions, p);
+      if (p)
+        continue;
+      /* end of problem reached */
+      solv->problems.elements[j++] = idx;
+      if (i + 1 >= solv->problems.count)
+        break;
+      /* start another problem */
+      solv->problems.elements[j++] = solv->problems.elements[++i];  /* copy proofidx */
+      idx = solv->solutions.count;
+      queue_push(&solv->solutions, -1);        /* unrefined */
+    }
+  solv->problems.count = j;
+  return j / 2;
+}
+
+/*
+ * refine the simple solution rule list provided by
+ * the solver into multiple lists of job modifiers.
+ */
+static void
+create_solutions(Solver *solv, int probnr, int solidx)
+{
+  Pool *pool = solv->pool;
+  Queue redoq;
+  Queue problem, solution, problems_save, branches_save, decisionq_reason_save;
+  int i, j, nsol;
+  int essentialok;
+  unsigned int now;
+  int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0;
+  Id extraflags = -1;
+
+  now = solv_timems(0);
+  queue_init(&redoq);
+  /* save decisionq, decisionq_why, decisionmap, and decisioncnt */
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      Id p = solv->decisionq.elements[i];
+      queue_push(&redoq, p);
+      queue_push(&redoq, solv->decisionq_why.elements[i]);
+      queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
+    }
+
+  /* save problems queue */
+  problems_save = solv->problems;
+  memset(&solv->problems, 0, sizeof(solv->problems));
+
+  /* save branches queue */
+  branches_save = solv->branches;
+  memset(&solv->branches, 0, sizeof(solv->branches));
+
+  /* save decisionq_reason */
+  decisionq_reason_save = solv->decisionq_reason;
+  memset(&solv->decisionq_reason, 0, sizeof(solv->decisionq_reason));
+
+  /* extract problem from queue */
+  queue_init(&problem);
+  for (i = solidx + 1; i < solv->solutions.count; i++)
+    {
+      Id v = solv->solutions.elements[i];
+      if (!v)
+       break;
+      queue_push(&problem, v);
+      if (v < 0)
+       extraflags &= solv->job.elements[-v - 1];
+    }
+  if (extraflags == -1)
+    extraflags = 0;
+  if (problem.count > 1)
+    solv_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
+  queue_push(&problem, 0);     /* mark end for refine_suggestion */
+  problem.count--;
+#if 0
+  for (i = 0; i < problem.count; i++)
+    printf("PP %d %d\n", i, problem.elements[i]);
+#endif
+
+  /* refine each solution element */
+  nsol = 0;
+  essentialok = 0;
+  queue_init(&solution);
+  for (i = 0; i < problem.count; i++)
+    {
+      int solstart = solv->solutions.count;
+      refine_suggestion(solv, problem.elements, problem.elements[i], &solution, essentialok);
+      queue_push(&solv->solutions, 0); /* reserve room for number of elements */
+      for (j = 0; j < solution.count; j++)
+       convertsolution(solv, solution.elements[j], &solv->solutions);
+      if (solv->solutions.count == solstart + 1)
+       {
+         solv->solutions.count--;      /* this one did not work out */
+         if (nsol || i + 1 < problem.count)
+           continue;                   /* got one or still hope */
+         if (!essentialok)
+           {
+             /* nothing found, start over */
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "nothing found, re-run with essentialok = 1\n");
+             essentialok = 1;
+             i = -1;
+             continue;
+           }
+         /* this is bad, we found no solution */
+         /* for now just offer a rule */
+         POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "nothing found, already did essentialok, fake it\n");
+         queue_push(&solv->solutions, 0);
+         for (j = 0; j < problem.count; j++)
+           {
+             convertsolution(solv, problem.elements[j], &solv->solutions);
+             if (solv->solutions.count > solstart + 1)
+               break;
+           }
+         if (solv->solutions.count == solstart + 1)
+           {
+             solv->solutions.count--;
+             continue;         /* sorry */
+           }
+       }
+      /* patch in number of solution elements */
+      solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
+      queue_push(&solv->solutions, 0); /* add end marker */
+      queue_push(&solv->solutions, 0); /* add end marker */
+      queue_push(&solv->solutions, problem.elements[i]);       /* just for bookkeeping */
+      queue_push(&solv->solutions, extraflags & SOLVER_CLEANDEPS);     /* our extraflags */
+      solv->solutions.elements[solidx + 1 + nsol++] = solstart;
+    }
+  solv->solutions.elements[solidx + 1 + nsol] = 0;     /* end marker */
+  solv->solutions.elements[solidx] = nsol;
+  queue_free(&problem);
+  queue_free(&solution);
+
+  /* restore decisions */
+  memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
+  queue_empty(&solv->decisionq);
+  queue_empty(&solv->decisionq_why);
+  for (i = 0; i < redoq.count; i += 3)
+    {
+      Id p = redoq.elements[i];
+      queue_push(&solv->decisionq, p);
+      queue_push(&solv->decisionq_why, redoq.elements[i + 1]);
+      solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
+    }
+  queue_free(&redoq);
+
+  /* restore decision reasons */
+  queue_free(&solv->decisionq_reason);
+  solv->decisionq_reason = decisionq_reason_save;
+
+  /* restore problems */
+  queue_free(&solv->problems);
+  solv->problems = problems_save;
+
+  /* restore branches */
+  queue_free(&solv->branches);
+  solv->branches = branches_save;
+
+  if (solv->cleandeps_mistakes)
+    {
+      if (oldmistakes)
+       queue_truncate(solv->cleandeps_mistakes, oldmistakes);
+      else
+       {
+         queue_free(solv->cleandeps_mistakes);
+         solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
+       }
+    }
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "create_solutions for problem #%d took %d ms\n", probnr, solv_timems(now));
+}
+
+
+/**************************************************************************/
+
+unsigned int
+solver_problem_count(Solver *solv)
+{
+  return solv->problems.count / 2;
+}
+
+Id
+solver_next_problem(Solver *solv, Id problem)
+{
+  if (!problem)
+    return solv->problems.count ? 1 : 0;
+  return (problem + 1) * 2 - 1 < solv->problems.count ? problem + 1 : 0;
+}
+
+unsigned int
+solver_solution_count(Solver *solv, Id problem)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  if (solv->solutions.elements[solidx] < 0)
+    create_solutions(solv, problem, solidx);
+  return solv->solutions.elements[solidx];
+}
+
+Id
+solver_next_solution(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  if (solv->solutions.elements[solidx] < 0)
+    create_solutions(solv, problem, solidx);
+  return solv->solutions.elements[solidx + solution + 1] ? solution + 1 : 0;
+}
+
+unsigned int
+solver_solutionelement_count(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  return solv->solutions.elements[solidx];
+}
+
+Id
+solver_solutionelement_internalid(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 3];
+}
+
+Id
+solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 4];
+}
+
+
+/*
+ *  return the next item of the proposed solution
+ *  here are the possibilities for p / rp and what
+ *  the solver expects the application to do:
+ *    p                             rp
+ *  -------------------------------------------------------
+ *    SOLVER_SOLUTION_INFARCH       pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_DISTUPGRADE   pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_BEST          pkgid
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *    SOLVER_SOLUTION_JOB           jobidx
+ *    -> remove job (jobidx - 1, jobidx) from job queue
+ *    SOLVER_SOLUTION_POOLJOB       jobidx
+ *    -> remove job (jobidx - 1, jobidx) from pool job queue
+ *    pkgid (> 0)                   0
+ *    -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
+ *    pkgid (> 0)                   pkgid (> 0)
+ *    -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
+ *       (this will replace package p)
+ *
+ * Thus, the solver will either ask the application to remove
+ * a specific job from the job queue, or ask to add an install/erase
+ * job to it.
+ *
+ */
+
+Id
+solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
+{
+  Id solidx = solv->problems.elements[problem * 2 - 1];
+  solidx = solv->solutions.elements[solidx + solution];
+  if (!solidx)
+    return 0;
+  solidx += 1 + element * 2;
+  if (!solv->solutions.elements[solidx] && !solv->solutions.elements[solidx + 1])
+    return 0;
+  *p = solv->solutions.elements[solidx];
+  *rp = solv->solutions.elements[solidx + 1];
+  return element + 1;
+}
+
+void
+solver_take_solutionelement(Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job)
+{
+  int i;
+
+  if (p == SOLVER_SOLUTION_POOLJOB)
+    {
+      solv->pool->pooljobs.elements[rp - 1] = SOLVER_NOOP;
+      solv->pool->pooljobs.elements[rp] = 0;
+      return;
+    }
+  if (p == SOLVER_SOLUTION_JOB)
+    {
+      job->elements[rp - 1] = SOLVER_NOOP;
+      job->elements[rp] = 0;
+      return;
+    }
+  if (rp <= 0 && p <= 0)
+    return;    /* just in case */
+  if (rp > 0)
+    p = SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extrajobflags;
+  else
+    {
+      rp = p;
+      p = SOLVER_ERASE|SOLVER_SOLVABLE|extrajobflags;
+    }
+  for (i = 0; i < job->count; i += 2)
+    if (job->elements[i] == p && job->elements[i + 1] == rp)
+      return;
+  queue_push2(job, p, rp);
+}
+
+void
+solver_take_solution(Solver *solv, Id problem, Id solution, Queue *job)
+{
+  Id p, rp, element = 0;
+  Id extrajobflags = solver_solutionelement_extrajobflags(solv, problem, solution);
+  while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
+    solver_take_solutionelement(solv, p, rp, extrajobflags, job);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * find problem rule
+ */
+
+static void
+findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Map *rseen)
+{
+  Id rid, d;
+  Id lreqr, lconr, lsysr, ljobr;
+  Rule *r;
+  Id jobassert = 0;
+  int i, reqset = 0;   /* 0: unset, 1: installed, 2: jobassert, 3: assert */
+  int conset = 0;      /* 0: unset, 1: installed */
+
+  /* find us a jobassert rule */
+  for (i = idx; (rid = solv->learnt_pool.elements[i]) != 0; i++)
+    {
+      if (rid < solv->jobrules || rid >= solv->jobrules_end)
+       continue;
+      r = solv->rules + rid;
+      d = r->d < 0 ? -r->d - 1 : r->d;
+      if (!d && r->w2 == 0 && r->p > 0)
+       {
+         jobassert = r->p;
+         break;
+       }
+    }
+
+  /* the problem rules are somewhat ordered from "near to the problem" to
+   * "near to the job" */
+  lreqr = lconr = lsysr = ljobr = 0;
+  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
+    {
+      assert(rid > 0);
+      if (rid >= solv->learntrules)
+       {
+         if (MAPTST(rseen, rid - solv->learntrules))
+           continue;
+         MAPSET(rseen, rid - solv->learntrules);
+         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, rseen);
+       }
+      else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid <= solv->yumobsrules_end))
+       {
+         if (!*jobrp)
+           *jobrp = rid;
+       }
+      else if (rid >= solv->updaterules && rid < solv->updaterules_end)
+       {
+         if (!*sysrp)
+           *sysrp = rid;
+       }
+      else
+       {
+         assert(rid < solv->pkgrules_end);
+         r = solv->rules + rid;
+         d = r->d < 0 ? -r->d - 1 : r->d;
+         if (!d && r->w2 < 0)
+           {
+             /* prefer conflicts of installed packages */
+             if (solv->installed && !conset)
+               {
+                 if (r->p < 0 && (solv->pool->solvables[-r->p].repo == solv->installed ||
+                                 solv->pool->solvables[-r->w2].repo == solv->installed))
+                   {
+                     *conrp = rid;
+                     conset = 1;
+                   }
+               }
+             if (!*conrp)
+               *conrp = rid;
+           }
+         else
+           {
+             if (!d && r->w2 == 0 && reqset < 3)
+               {
+                 if (*reqrp > 0 && r->p < -1)
+                   {
+                     Pool *pool = solv->pool;
+                     Id op = -solv->rules[*reqrp].p;
+                     if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch &&
+                         pool->solvables[op].arch != pool->noarchid &&
+                         pool->solvables[-r->p].arch != pool->noarchid)
+                       continue;       /* different arch, skip */
+                   }
+                 /* prefer assertions */
+                 *reqrp = rid;
+                 reqset = 3;
+               }
+             else if (jobassert && r->p == -jobassert)
+               {
+                 /* prefer rules of job assertions */
+                 *reqrp = rid;
+                 reqset = 2;
+               }
+             else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && reqset <= 1)
+               {
+                 /* prefer rules of job installed package so that the user doesn't get confused by strange packages */
+                 *reqrp = rid;
+                 reqset = 1;
+               }
+             else if (!*reqrp)
+               *reqrp = rid;
+           }
+       }
+    }
+  if (!*reqrp && lreqr)
+    *reqrp = lreqr;
+  if (!*conrp && lconr)
+    *conrp = lconr;
+  if (!*jobrp && ljobr)
+    *jobrp = ljobr;
+  if (!*sysrp && lsysr)
+    *sysrp = lsysr;
+}
+
+/*
+ * find problem rule
+ *
+ * search for a rule that describes the problem to the
+ * user. Actually a pretty hopeless task that may leave the user
+ * puzzled. To get all of the needed information use
+ * solver_findallproblemrules() instead.
+ */
+
+Id
+solver_findproblemrule(Solver *solv, Id problem)
+{
+  Id reqr, conr, sysr, jobr;
+  Id idx = solv->problems.elements[2 * problem - 2];
+  Map rseen;
+  reqr = conr = sysr = jobr = 0;
+  map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
+  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &rseen);
+  map_free(&rseen);
+  /* check if the request is about a not-installed package requiring a installed
+   * package conflicting with the non-installed package. In that case return the conflict */
+  if (reqr && conr && solv->installed && solv->rules[reqr].p < 0 && solv->rules[conr].p < 0 && solv->rules[conr].w2 < 0)
+    {
+      Pool *pool = solv->pool;
+      Solvable *s  = pool->solvables - solv->rules[reqr].p;
+      Solvable *s1 = pool->solvables - solv->rules[conr].p;
+      Solvable *s2 = pool->solvables - solv->rules[conr].w2;
+      Id cp = 0;
+      if (s == s1 && s2->repo == solv->installed)
+       cp = -solv->rules[conr].w2;
+      else if (s == s2 && s1->repo == solv->installed)
+       cp = -solv->rules[conr].p;
+      if (cp && s1->name != s2->name && s->repo != solv->installed)
+       {
+         Id p, pp;
+         Rule *r = solv->rules + reqr;
+         FOR_RULELITERALS(p, pp, r)
+           if (p == cp)
+             return conr;
+       }
+    }
+  if (reqr)
+    return reqr;       /* some requires */
+  if (conr)
+    return conr;       /* some conflict */
+  if (sysr)
+    return sysr;       /* an update rule */
+  if (jobr)
+    return jobr;       /* a user request */
+  assert(0);
+  return 0;
+}
+
+/*-------------------------------------------------------------------*/
+
+static void
+findallproblemrules_internal(Solver *solv, Id idx, Queue *rules, Map *rseen)
+{
+  Id rid;
+  while ((rid = solv->learnt_pool.elements[idx++]) != 0)
+    {
+      if (rid >= solv->learntrules)
+        {
+         if (MAPTST(rseen, rid - solv->learntrules))
+           continue;
+         MAPSET(rseen, rid - solv->learntrules);
+         findallproblemrules_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], rules, rseen);
+          continue;
+       }
+      queue_pushunique(rules, rid);
+    }
+}
+
+/*
+ * find all problem rule
+ *
+ * return all rules that lead to the problem. This gives the user
+ * all of the information to understand the problem, but the result
+ * can be a large number of rules.
+ */
+
+void
+solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
+{
+  Map rseen;
+  queue_empty(rules);
+  map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
+  findallproblemrules_internal(solv, solv->problems.elements[2 * problem - 2], rules, &rseen);
+  map_free(&rseen);
+}
+
+const char *
+solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep)
+{
+  Pool *pool = solv->pool;
+  char *s;
+  Solvable *ss;
+  switch (type)
+    {
+    case SOLVER_RULE_DISTUPGRADE:
+      return pool_tmpjoin(pool, pool_solvid2str(pool, source), " does not belong to a distupgrade repository", 0);
+    case SOLVER_RULE_INFARCH:
+      return pool_tmpjoin(pool, pool_solvid2str(pool, source), " has inferior architecture", 0);
+    case SOLVER_RULE_UPDATE:
+      return pool_tmpjoin(pool, "problem with installed package ", pool_solvid2str(pool, source), 0);
+    case SOLVER_RULE_JOB:
+      return "conflicting requests";
+    case SOLVER_RULE_JOB_UNSUPPORTED:
+      return "unsupported request";
+    case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
+      return pool_tmpjoin(pool, "nothing provides requested ", pool_dep2str(pool, dep), 0);
+    case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
+      return pool_tmpjoin(pool, "package ", pool_dep2str(pool, dep), " does not exist");
+    case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
+      return pool_tmpjoin(pool, pool_dep2str(pool, dep), " is provided by the system", 0);
+    case SOLVER_RULE_PKG:
+      return "some dependency problem";
+    case SOLVER_RULE_BEST:
+      if (source > 0)
+        return pool_tmpjoin(pool, "cannot install the best update candidate for package ", pool_solvid2str(pool, source), 0);
+     return "cannot install the best candidate for the job";
+    case SOLVER_RULE_PKG_NOT_INSTALLABLE:
+      ss = pool->solvables + source;
+      if (pool_disabled_solvable(pool, ss))
+        return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is disabled");
+      if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC &&
+          pool->id2arch && pool_arch2score(pool, ss->arch) == 0)
+        return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " does not have a compatible architecture");
+      return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable");
+    case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
+      s = pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0);
+      return pool_tmpappend(pool, s, " needed by ", pool_solvid2str(pool, source));
+    case SOLVER_RULE_PKG_SAME_NAME:
+      s = pool_tmpjoin(pool, "cannot install both ", pool_solvid2str(pool, source), 0);
+      return pool_tmpappend(pool, s, " and ", pool_solvid2str(pool, target));
+    case SOLVER_RULE_PKG_CONFLICTS:
+      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
+      s = pool_tmpappend(pool, s, " conflicts with ", pool_dep2str(pool, dep));
+      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+    case SOLVER_RULE_PKG_OBSOLETES:
+      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
+      s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
+      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+    case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
+      s = pool_tmpjoin(pool, "installed package ", pool_solvid2str(pool, source), 0);
+      s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
+      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+    case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
+      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
+      s = pool_tmpappend(pool, s, " implicitly obsoletes ", pool_dep2str(pool, dep));
+      return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
+    case SOLVER_RULE_PKG_REQUIRES:
+      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " requires ");
+      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), ", but none of the providers can be installed");
+    case SOLVER_RULE_PKG_SELF_CONFLICT:
+      s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " conflicts with ");
+      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), " provided by itself");
+    case SOLVER_RULE_YUMOBS:
+      s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and ");
+      s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
+      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
+    default:
+      return "bad problem rule type";
+    }
+}
+
+/* convenience function */
+const char *
+solver_problem2str(Solver *solv, Id problem)
+{
+  Id type, source, target, dep;
+  Id r = solver_findproblemrule(solv, problem);
+  if (!r)
+    return "no problem rule?";
+  type = solver_ruleinfo(solv, r, &source, &target, &dep);
+  return solver_problemruleinfo2str(solv, type, source, target, dep);
+}
+
+const char *
+solver_solutionelement2str(Solver *solv, Id p, Id rp)
+{
+  Pool *pool = solv->pool;
+  if (p == SOLVER_SOLUTION_JOB || p == SOLVER_SOLUTION_POOLJOB)
+    {
+      Id how, what;
+      if (p == SOLVER_SOLUTION_JOB)
+       rp += solv->pooljobcnt;
+      how = solv->job.elements[rp - 1];
+      what = solv->job.elements[rp];
+      return pool_tmpjoin(pool, "do not ask to ", pool_job2str(pool, how, what, 0), 0);
+    }
+  else if (p == SOLVER_SOLUTION_INFARCH)
+    {
+      Solvable *s = pool->solvables + rp;
+      if (solv->installed && s->repo == solv->installed)
+        return pool_tmpjoin(pool, "keep ", pool_solvable2str(pool, s), " despite the inferior architecture");
+      else
+        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the inferior architecture");
+    }
+  else if (p == SOLVER_SOLUTION_DISTUPGRADE)
+    {
+      Solvable *s = pool->solvables + rp;
+      if (solv->installed && s->repo == solv->installed)
+        return pool_tmpjoin(pool, "keep obsolete ", pool_solvable2str(pool, s), 0);
+      else
+        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " from excluded repository");
+    }
+  else if (p == SOLVER_SOLUTION_BEST)
+    {
+      Solvable *s = pool->solvables + rp;
+      if (solv->installed && s->repo == solv->installed)
+        return pool_tmpjoin(pool, "keep old ", pool_solvable2str(pool, s), 0);
+      else
+        return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
+    }
+  else if (p > 0 && rp == 0)
+    return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
+  else if (p > 0 && rp > 0)
+    {
+      const char *sp = pool_solvid2str(pool, p);
+      const char *srp = pool_solvid2str(pool, rp);
+      const char *str = pool_tmpjoin(pool, "allow replacement of ", sp, 0);
+      return pool_tmpappend(pool, str, " with ", srp);
+    }
+  else
+    return "bad solution element";
+}
+
diff --git a/libsolv-0.7.2/src/problems.h b/libsolv-0.7.2/src/problems.h
new file mode 100644 (file)
index 0000000..37021e1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * problems.h
+ *
+ */
+
+#ifndef LIBSOLV_PROBLEMS_H
+#define LIBSOLV_PROBLEMS_H
+
+#include "rules.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct s_Solver;
+
+#define SOLVER_SOLUTION_JOB             (0)
+#define SOLVER_SOLUTION_DISTUPGRADE     (-1)
+#define SOLVER_SOLUTION_INFARCH         (-2)
+#define SOLVER_SOLUTION_BEST            (-3)
+#define SOLVER_SOLUTION_POOLJOB         (-4)
+
+void solver_recordproblem(struct s_Solver *solv, Id rid);
+void solver_fixproblem(struct s_Solver *solv, Id rid);
+Id solver_autouninstall(struct s_Solver *solv, int start);
+void solver_disableproblemset(struct s_Solver *solv, int start);
+
+int solver_prepare_solutions(struct s_Solver *solv);
+
+unsigned int solver_problem_count(struct s_Solver *solv);
+Id solver_next_problem(struct s_Solver *solv, Id problem);
+unsigned int solver_solution_count(struct s_Solver *solv, Id problem);
+Id solver_next_solution(struct s_Solver *solv, Id problem, Id solution);
+unsigned int solver_solutionelement_count(struct s_Solver *solv, Id problem, Id solution);
+Id solver_solutionelement_internalid(struct s_Solver *solv, Id problem, Id solution);
+Id solver_solutionelement_extrajobflags(struct s_Solver *solv, Id problem, Id solution);
+Id solver_next_solutionelement(struct s_Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
+
+void solver_take_solutionelement(struct s_Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job);
+void solver_take_solution(struct s_Solver *solv, Id problem, Id solution, Queue *job);
+
+Id solver_findproblemrule(struct s_Solver *solv, Id problem);
+void solver_findallproblemrules(struct s_Solver *solv, Id problem, Queue *rules);
+
+extern const char *solver_problemruleinfo2str(struct s_Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
+extern const char *solver_problem2str(struct s_Solver *solv, Id problem);
+extern const char *solver_solutionelement2str(struct s_Solver *solv, Id p, Id rp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsolv-0.7.2/src/qsort_r.c b/libsolv-0.7.2/src/qsort_r.c
new file mode 100644 (file)
index 0000000..d49049a
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * qsort taken from FreeBSD, slightly modified to match glibc's
+ * argument ordering
+ */
+
+/* FIXME: should use mergesort instead */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qsort.c    8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+
+/* $FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.13.2.1.8.1 2010/12/21 17:10:29 kensmith Exp $ */
+
+#include <stdlib.h>
+
+typedef int             cmp_t(const void *, const void *, void *);
+static inline char     *med3(char *, char *, char *, cmp_t *, void *);
+static inline void      swapfunc(char *, char *, int, int);
+
+#ifndef min
+#define min(a, b)      (a) < (b) ? a : b
+#endif
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) {              \
+       long i = (n) / sizeof (TYPE);                   \
+       TYPE *pi = (TYPE *) (parmi);            \
+       TYPE *pj = (TYPE *) (parmj);            \
+       do {                                            \
+               TYPE    t = *pi;                \
+               *pi++ = *pj;                            \
+               *pj++ = t;                              \
+        } while (--i > 0);                             \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+       es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static inline void
+swapfunc(a, b, n, swaptype)
+       char *a, *b;
+       int n, swaptype;
+{
+       if(swaptype <= 1)
+               swapcode(long, a, b, n)
+       else
+               swapcode(char, a, b, n)
+}
+
+#define swap(a, b)                                     \
+       if (swaptype == 0) {                            \
+               long t = *(long *)(a);                  \
+               *(long *)(a) = *(long *)(b);            \
+               *(long *)(b) = t;                       \
+       } else                                          \
+               swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n)       if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+#define        CMP(t, x, y) (cmp((x), (y), (t)))
+
+static inline char *
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk)
+{
+       return CMP(thunk, a, b) < 0 ?
+              (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
+              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+}
+
+void
+solv_sort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
+{
+       char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+       size_t d, r;
+       int cmp_result;
+       int swaptype, swap_cnt;
+
+loop:  SWAPINIT(a, es);
+       swap_cnt = 0;
+       if (n < 7) {
+               for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+                       for (pl = pm;
+                            pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+                            pl -= es)
+                               swap(pl, pl - es);
+               return;
+       }
+       pm = (char *)a + (n / 2) * es;
+       if (n > 7) {
+               pl = a;
+               pn = (char *)a + (n - 1) * es;
+               if (n > 40) {
+                       d = (n / 8) * es;
+                       pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+                       pm = med3(pm - d, pm, pm + d, cmp, thunk);
+                       pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
+               }
+               pm = med3(pl, pm, pn, cmp, thunk);
+       }
+       swap(a, pm);
+       pa = pb = (char *)a + es;
+
+       pc = pd = (char *)a + (n - 1) * es;
+       for (;;) {
+               while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
+                       if (cmp_result == 0) {
+                               swap_cnt = 1;
+                               swap(pa, pb);
+                               pa += es;
+                       }
+                       pb += es;
+               }
+               while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
+                       if (cmp_result == 0) {
+                               swap_cnt = 1;
+                               swap(pc, pd);
+                               pd -= es;
+                       }
+                       pc -= es;
+               }
+               if (pb > pc)
+                       break;
+               swap(pb, pc);
+               swap_cnt = 1;
+               pb += es;
+               pc -= es;
+       }
+       if (swap_cnt == 0) {  /* Switch to insertion sort */
+               for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+                       for (pl = pm;
+                            pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+                            pl -= es)
+                               swap(pl, pl - es);
+               return;
+       }
+
+       pn = (char *)a + n * es;
+       r = min(pa - (char *)a, pb - pa);
+       vecswap(a, pb - r, r);
+       r = min(pd - pc, pn - pd - es);
+       vecswap(pb, pn - r, r);
+       if ((r = pb - pa) > es)
+               solv_sort(a, r / es, es, cmp, thunk);
+       if ((r = pd - pc) > es) {
+               /* Iterate rather than recurse to save stack space */
+               a = pn - r;
+               n = r / es;
+               goto loop;
+       }
+/*             qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/libsolv-0.7.2/src/queue.c b/libsolv-0.7.2/src/queue.c
new file mode 100644 (file)
index 0000000..6d5e531
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * queue.c
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "queue.h"
+#include "util.h"
+
+static inline int
+queue_extra_space(int size)
+{
+  if (size < 32)
+    return 8;
+  if (size < 64)
+    return 16;
+  if (size < 128)
+    return 32;
+  return 64;
+}
+
+void
+queue_init(Queue *q)
+{
+  q->alloc = q->elements = 0;
+  q->count = q->left = 0;
+}
+
+void
+queue_init_clone(Queue *target, const Queue *source)
+{
+  int extra_space;
+  if (!source->elements)
+    {
+      target->alloc = target->elements = 0;
+      target->count = target->left = 0;
+      return;
+    }
+  extra_space = queue_extra_space(source->count);
+  target->alloc = target->elements = solv_malloc2(source->count + extra_space, sizeof(Id));
+  if (source->count)
+    memcpy(target->alloc, source->elements, source->count * sizeof(Id));
+  target->count = source->count;
+  target->left = extra_space;
+}
+
+void
+queue_init_buffer(Queue *q, Id *buf, int size)
+{
+  q->alloc = 0;
+  q->elements = buf;
+  q->count = 0;
+  q->left = size;
+}
+
+void
+queue_free(Queue *q)
+{
+  if (q->alloc)
+    solv_free(q->alloc);
+  q->alloc = q->elements = 0;
+  q->count = q->left = 0;
+}
+
+/* make room for one element at the tail of the queue */
+void
+queue_alloc_one(Queue *q)
+{
+  if (q->alloc && q->alloc != q->elements)
+    {
+      /* there's room at the front. just move data */
+      int l = q->elements - q->alloc;
+      if (q->count)
+        memmove(q->alloc, q->elements, q->count * sizeof(Id));
+      q->elements -= l;
+      q->left += l;
+    }
+  else
+    {
+      int extra_space = queue_extra_space(q->count);
+      if (!q->alloc)
+       {
+         q->alloc = solv_malloc2(q->count + extra_space, sizeof(Id));
+         if (q->count)
+           memcpy(q->alloc, q->elements, q->count * sizeof(Id));
+       }
+      else
+       q->alloc = solv_realloc2(q->alloc, q->count + extra_space, sizeof(Id));
+      q->elements = q->alloc;
+      q->left = extra_space;
+    }
+}
+
+/* make room for an element in front of queue */
+void
+queue_alloc_one_head(Queue *q)
+{
+  int l, extra_space;
+  if (!q->alloc || !q->left)
+    queue_alloc_one(q);                /* easy way to make room */
+  extra_space = queue_extra_space(q->count);
+  l = q->left > extra_space ? extra_space : q->left;
+  if (q->count)
+    memmove(q->elements + l, q->elements, q->count * sizeof(Id));
+  q->elements += l;
+  q->left -= l;
+}
+
+void
+queue_insert(Queue *q, int pos, Id id)
+{
+  queue_push(q, id);   /* make room */
+  if (pos < q->count - 1)
+    {
+      memmove(q->elements + pos + 1, q->elements + pos, (q->count - 1 - pos) * sizeof(Id));
+      q->elements[pos] = id;
+    }
+}
+
+void
+queue_delete(Queue *q, int pos)
+{
+  if (pos >= q->count)
+    return;
+  if (pos < q->count - 1)
+    memmove(q->elements + pos, q->elements + pos + 1, (q->count - 1 - pos) * sizeof(Id));
+  q->left++;
+  q->count--;
+}
+
+void
+queue_insert2(Queue *q, int pos, Id id1, Id id2)
+{
+  queue_push(q, id1);  /* make room */
+  queue_push(q, id2);  /* make room */
+  if (pos < q->count - 2)
+    {
+      memmove(q->elements + pos + 2, q->elements + pos, (q->count - 2 - pos) * sizeof(Id));
+      q->elements[pos] = id1;
+      q->elements[pos + 1] = id2;
+    }
+}
+
+void
+queue_delete2(Queue *q, int pos)
+{
+  if (pos >= q->count)
+    return;
+  if (pos == q->count - 1)
+    {
+      q->left++;
+      q->count--;
+      return;
+    }
+  if (pos < q->count - 2)
+    memmove(q->elements + pos, q->elements + pos + 2, (q->count - 2 - pos) * sizeof(Id));
+  q->left += 2;
+  q->count -= 2;
+}
+
+void
+queue_insertn(Queue *q, int pos, int n, const Id *elements)
+{
+  if (n <= 0)
+    return;
+  if (pos > q->count)
+    pos = q->count;
+  if (q->left < n)
+    queue_prealloc(q, n);
+  if (pos < q->count)
+    memmove(q->elements + pos + n, q->elements + pos, (q->count - pos) * sizeof(Id));
+  if (elements)
+    memcpy(q->elements + pos, elements, n * sizeof(Id));
+  else
+    memset(q->elements + pos, 0, n * sizeof(Id));
+  q->left -= n;
+  q->count += n;
+}
+
+void
+queue_deleten(Queue *q, int pos, int n)
+{
+  if (n <= 0 || pos >= q->count)
+    return;
+  if (pos + n >= q->count)
+    n = q->count - pos;
+  else
+    memmove(q->elements + pos, q->elements + pos + n, (q->count - n - pos) * sizeof(Id));
+  q->left += n;
+  q->count -= n;
+}
+
+/* pre-allocate room for n more elements */
+void
+queue_prealloc(Queue *q, int n)
+{
+  int off, extra_space;
+  if (n <= 0 || q->left >= n)
+    return;
+  if (!q->alloc)
+    queue_alloc_one(q);
+  off = q->elements - q->alloc;
+  extra_space = queue_extra_space(q->count + n);
+  q->alloc = solv_realloc2(q->alloc, off + q->count + n + extra_space, sizeof(Id));
+  q->elements = q->alloc + off;
+  q->left = n + extra_space;
+}
+
diff --git a/libsolv-0.7.2/src/queue.h b/libsolv-0.7.2/src/queue.h
new file mode 100644 (file)
index 0000000..8b1ef08
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * queue.h
+ *
+ */
+
+#ifndef LIBSOLV_QUEUE_H
+#define LIBSOLV_QUEUE_H
+
+#include "pooltypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct s_Queue {
+  Id *elements;                /* pointer to elements */
+  int count;           /* current number of elements in queue */
+  Id *alloc;           /* this is whats actually allocated, elements > alloc if shifted */
+  int left;            /* space left in alloc *after* elements+count */
+} Queue;
+
+
+extern void queue_alloc_one(Queue *q);         /* internal */
+extern void queue_alloc_one_head(Queue *q);    /* internal */
+
+/* clear queue */
+static inline void
+queue_empty(Queue *q)
+{
+  if (q->alloc)
+    {
+      q->left += (q->elements - q->alloc) + q->count;
+      q->elements = q->alloc;
+    }
+  else
+    q->left += q->count;
+  q->count = 0;
+}
+
+static inline Id
+queue_shift(Queue *q)
+{
+  if (!q->count)
+    return 0;
+  q->count--;
+  return *q->elements++;
+}
+
+static inline Id
+queue_pop(Queue *q)
+{
+  if (!q->count)
+    return 0;
+  q->left++;
+  return q->elements[--q->count];
+}
+
+static inline void
+queue_unshift(Queue *q, Id id)
+{
+  if (!q->alloc || q->alloc == q->elements)
+    queue_alloc_one_head(q);
+  *--q->elements = id;
+  q->count++;
+}
+
+static inline void
+queue_push(Queue *q, Id id)
+{
+  if (!q->left)
+    queue_alloc_one(q);
+  q->elements[q->count++] = id;
+  q->left--;
+}
+
+static inline void
+queue_pushunique(Queue *q, Id id)
+{
+  int i;
+  for (i = q->count; i > 0; )
+    if (q->elements[--i] == id)
+      return;
+  queue_push(q, id);
+}
+
+static inline void
+queue_push2(Queue *q, Id id1, Id id2)
+{
+  queue_push(q, id1);
+  queue_push(q, id2);
+}
+
+static inline void
+queue_truncate(Queue *q, int n)
+{
+  if (q->count > n)
+    {
+      q->left += q->count - n;
+      q->count = n;
+    }
+}
+
+extern void queue_init(Queue *q);
+extern void queue_init_buffer(Queue *q, Id *buf, int size);
+extern void queue_init_clone(Queue *target, const Queue *source);
+extern void queue_free(Queue *q);
+
+extern void queue_insert(Queue *q, int pos, Id id);
+extern void queue_insert2(Queue *q, int pos, Id id1, Id id2);
+extern void queue_insertn(Queue *q, int pos, int n, const Id *elements);
+extern void queue_delete(Queue *q, int pos);
+extern void queue_delete2(Queue *q, int pos);
+extern void queue_deleten(Queue *q, int pos, int n);
+extern void queue_prealloc(Queue *q, int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_QUEUE_H */
diff --git a/libsolv-0.7.2/src/repo.c b/libsolv-0.7.2/src/repo.c
new file mode 100644 (file)
index 0000000..d163f13
--- /dev/null
@@ -0,0 +1,1627 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo.c
+ *
+ * Manage metadata coming from one repository
+ *
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+#include "repo.h"
+#include "pool.h"
+#include "poolid_private.h"
+#include "util.h"
+#include "chksum.h"
+
+#define IDARRAY_BLOCK     4095
+
+
+/*
+ * create empty repo
+ * and add to pool
+ */
+
+Repo *
+repo_create(Pool *pool, const char *name)
+{
+  Repo *repo;
+
+  pool_freewhatprovides(pool);
+  repo = (Repo *)solv_calloc(1, sizeof(*repo));
+  if (!pool->nrepos)
+    {
+      pool->nrepos = 1;        /* start with repoid 1 */
+      pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *));
+    }
+  else
+    pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
+  pool->repos[pool->nrepos] = repo;
+  pool->urepos++;
+  repo->repoid = pool->nrepos++;
+  repo->name = name ? solv_strdup(name) : 0;
+  repo->pool = pool;
+  repo->start = pool->nsolvables;
+  repo->end = pool->nsolvables;
+  repo->nsolvables = 0;
+  return repo;
+}
+
+void
+repo_freedata(Repo *repo)
+{
+  int i;
+  for (i = 1; i < repo->nrepodata; i++)
+    repodata_freedata(repo->repodata + i);
+  solv_free(repo->repodata);
+  solv_free(repo->idarraydata);
+  solv_free(repo->rpmdbid);
+  solv_free(repo->lastidhash);
+  solv_free((char *)repo->name);
+  solv_free(repo);
+}
+
+/* delete all solvables and repodata blocks from this repo */
+
+void
+repo_empty(Repo *repo, int reuseids)
+{
+  Pool *pool = repo->pool;
+  Solvable *s;
+  int i;
+
+  pool_freewhatprovides(pool);
+  if (reuseids && repo->end == pool->nsolvables)
+    {
+      /* it's ok to reuse the ids. As this is the last repo, we can
+         just shrink the solvable array */
+      for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
+       if (s->repo != repo)
+         break;
+      pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids);
+      repo->end = i + 1;
+    }
+  /* zero out (i.e. free) solvables belonging to this repo */
+  for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
+    if (s->repo == repo)
+      memset(s, 0, sizeof(*s));
+  repo->end = repo->start;
+  repo->nsolvables = 0;
+
+  /* free all data belonging to this repo */
+  repo->idarraydata = solv_free(repo->idarraydata);
+  repo->idarraysize = 0;
+  repo->lastoff = 0;
+  repo->rpmdbid = solv_free(repo->rpmdbid);
+  for (i = 1; i < repo->nrepodata; i++)
+    repodata_freedata(repo->repodata + i);
+  solv_free(repo->repodata);
+  repo->repodata = 0;
+  repo->nrepodata = 0;
+}
+
+/*
+ * remove repo from pool, delete solvables
+ *
+ */
+
+void
+repo_free(Repo *repo, int reuseids)
+{
+  Pool *pool = repo->pool;
+  int i;
+
+  if (repo == pool->installed)
+    pool->installed = 0;
+  repo_empty(repo, reuseids);
+  for (i = 1; i < pool->nrepos; i++)   /* find repo in pool */
+    if (pool->repos[i] == repo)
+      break;
+  if (i == pool->nrepos)              /* repo not in pool, return */
+    return;
+  if (i == pool->nrepos - 1 && reuseids)
+    pool->nrepos--;
+  else
+    pool->repos[i] = 0;
+  pool->urepos--;
+  repo_freedata(repo);
+}
+
+Id
+repo_add_solvable(Repo *repo)
+{
+  Id p = pool_add_solvable(repo->pool);
+  if (!repo->start || repo->start == repo->end)
+    repo->start = repo->end = p;
+  /* warning: sidedata must be extended before adapting start/end */
+  if (repo->rpmdbid)
+    repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, 1);
+  if (p < repo->start)
+    repo->start = p;
+  if (p + 1 > repo->end)
+    repo->end = p + 1;
+  repo->nsolvables++;
+  repo->pool->solvables[p].repo = repo;
+  return p;
+}
+
+Id
+repo_add_solvable_block(Repo *repo, int count)
+{
+  Id p;
+  Solvable *s;
+  if (!count)
+    return 0;
+  p = pool_add_solvable_block(repo->pool, count);
+  if (!repo->start || repo->start == repo->end)
+    repo->start = repo->end = p;
+  /* warning: sidedata must be extended before adapting start/end */
+  if (repo->rpmdbid)
+    repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
+  if (p < repo->start)
+    repo->start = p;
+  if (p + count > repo->end)
+    repo->end = p + count;
+  repo->nsolvables += count;
+  for (s = repo->pool->solvables + p; count--; s++)
+    s->repo = repo;
+  return p;
+}
+
+void
+repo_free_solvable(Repo *repo, Id p, int reuseids)
+{
+  repo_free_solvable_block(repo, p, 1, reuseids);
+}
+
+void
+repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids)
+{
+  Solvable *s;
+  Repodata *data;
+  int i;
+  if (start + count == repo->end)
+    repo->end -= count;
+  repo->nsolvables -= count;
+  for (s = repo->pool->solvables + start, i = count; i--; s++)
+    s->repo = 0;
+  pool_free_solvable_block(repo->pool, start, count, reuseids);
+  FOR_REPODATAS(repo, i, data)
+    {
+      int dstart, dend;
+      if (data->end > repo->end)
+        repodata_shrink(data, repo->end);
+      dstart = data->start > start ? data->start : start;
+      dend = data->end < start + count ? data->end : start + count;
+      if (dstart < dend)
+       {
+         if (data->attrs)
+           {
+             int j;
+             for (j = dstart; j < dend; j++)   
+               data->attrs[j - data->start] = solv_free(data->attrs[j - data->start]);
+           }
+         if (data->incoreoffset)
+           memset(data->incoreoffset + (dstart - data->start), 0, (dend - dstart) * sizeof(Id));
+       }
+    }
+}
+
+/* specialized version of repo_add_solvable_block that inserts the new solvable
+ * block before the indicated repo, which gets relocated.
+ * used in repo_add_rpmdb
+ */
+Id
+repo_add_solvable_block_before(Repo *repo, int count, Repo *beforerepo)
+{
+  Pool *pool = repo->pool;
+  Id p;
+  Solvable *s;
+  Repodata *data;
+  int i;
+
+  if (!count || !beforerepo || beforerepo->end != pool->nsolvables || beforerepo->start == beforerepo->end)
+    return repo_add_solvable_block(repo, count);
+  p = beforerepo->start;
+  /* make sure all solvables belong to beforerepo */
+  for (i = p, s = pool->solvables + i; i < beforerepo->end; i++, s++)
+    if (s->repo && s->repo != beforerepo)
+      return repo_add_solvable_block(repo, count);
+  /* now move beforerepo to back */
+  pool_add_solvable_block(pool, count);        /* must return beforerepo->end! */
+  memmove(pool->solvables + p + count, pool->solvables + p, (beforerepo->end - p) * sizeof(Solvable));
+  memset(pool->solvables + p, 0, sizeof(Solvable) * count);
+  /* adapt repodata */
+  FOR_REPODATAS(beforerepo, i, data)
+    {
+      if (data->start < p)
+       continue;
+      data->start += count;
+      data->end += count;
+    }
+  beforerepo->start += count;
+  beforerepo->end += count;
+  /* we now have count free solvables at id p */
+  /* warning: sidedata must be extended before adapting start/end */
+  if (repo->rpmdbid)
+    repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
+  if (p < repo->start)
+    repo->start = p;
+  if (p + count > repo->end)
+    repo->end = p + count;
+  repo->nsolvables += count;
+  for (s = pool->solvables + p; count--; s++)
+    s->repo = repo;
+  return p;
+}
+
+
+/* repository sidedata is solvable data allocated on demand.
+ * It is used for data that is normally not present
+ * in the solvable like the rpmdbid.
+ * The solvable allocation funcions need to make sure that
+ * the sidedata gets extended if new solvables get added.
+ */
+
+#define REPO_SIDEDATA_BLOCK 63
+
+void *
+repo_sidedata_create(Repo *repo, size_t size)
+{
+  return solv_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
+}
+
+void *
+repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
+{
+  int n = repo->end - repo->start;
+  if (p < repo->start)
+    {
+      int d = repo->start - p;
+      b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
+      memmove((char *)b + d * size, b, n * size);
+      memset(b, 0, d * size);
+      n += d;
+    }
+  if (p + count > repo->end)
+    {
+      int d = p + count - repo->end;
+      b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
+      memset((char *)b + n * size, 0, d * size);
+    }
+  return b;
+}
+
+/*
+ * add Id to idarraydata used to store dependencies
+ * olddeps: old array offset to extend
+ * returns new array offset
+ */
+
+Offset
+repo_addid(Repo *repo, Offset olddeps, Id id)
+{
+  Id *idarray;
+  int idarraysize;
+  int i;
+
+  idarray = repo->idarraydata;
+  idarraysize = repo->idarraysize;
+
+  if (!idarray)                               /* alloc idarray if not done yet */
+    {
+      idarraysize = 1;
+      idarray = solv_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
+      idarray[0] = 0;
+      repo->lastoff = 0;
+    }
+
+  if (!olddeps)                                /* no deps yet */
+    {
+      olddeps = idarraysize;
+      idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
+    }
+  else if (olddeps == repo->lastoff)   /* extend at end */
+    idarraysize--;
+  else                                 /* can't extend, copy old */
+    {
+      i = olddeps;
+      olddeps = idarraysize;
+      for (; idarray[i]; i++)
+        {
+         idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
+          idarray[idarraysize++] = idarray[i];
+        }
+      idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
+    }
+
+  idarray[idarraysize++] = id;         /* insert Id into array */
+  idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
+  idarray[idarraysize++] = 0;          /* ensure NULL termination */
+
+  repo->idarraydata = idarray;
+  repo->idarraysize = idarraysize;
+  repo->lastoff = olddeps;
+
+  return olddeps;
+}
+
+#define REPO_ADDID_DEP_HASHTHRES       64
+#define REPO_ADDID_DEP_HASHMIN         128
+
+/*
+ * Optimization for packages with an excessive amount of provides/requires:
+ * if the number of deps exceed a threshold, we build a hash of the already
+ * seen ids.
+ */
+static Offset
+repo_addid_dep_hash(Repo *repo, Offset olddeps, Id id, Id marker, int size)
+{
+  Id oid, *oidp;
+  int before;
+  Hashval h, hh;
+  Id hid;
+
+  before = 0;
+  if (marker)
+    {
+      if (marker < 0)
+       {
+         marker = -marker;
+         before = 1;
+       }
+      if (marker == id)
+       marker = 0;
+    }
+
+  /* maintain hash and lastmarkerpos */
+  if (repo->lastidhash_idarraysize != repo->idarraysize || (Hashval)size * 2 > repo->lastidhash_mask || repo->lastmarker != marker)
+    {
+      repo->lastmarkerpos = 0;
+      if (size * 2 > (Hashval)repo->lastidhash_mask)
+       {
+         repo->lastidhash_mask = mkmask(size < REPO_ADDID_DEP_HASHMIN ? REPO_ADDID_DEP_HASHMIN : size);
+         repo->lastidhash = solv_realloc2(repo->lastidhash, repo->lastidhash_mask + 1, sizeof(Id));
+       }
+      memset(repo->lastidhash, 0, (repo->lastidhash_mask + 1) * sizeof(Id));
+      for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
+       {
+         h = oid & repo->lastidhash_mask;
+         hh = HASHCHAIN_START;
+         while (repo->lastidhash[h] != 0)
+           h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
+         repo->lastidhash[h] = oid;
+         if (marker && oid == marker)
+           repo->lastmarkerpos = oidp - repo->idarraydata;
+       }
+      repo->lastmarker = marker;
+      repo->lastidhash_idarraysize = repo->idarraysize;
+    }
+
+  /* check the hash! */
+  h = id & repo->lastidhash_mask;
+  hh = HASHCHAIN_START;
+  while ((hid = repo->lastidhash[h]) != 0 && hid != id)
+    h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
+  /* put new element in hash */
+  if (!hid)
+    repo->lastidhash[h] = id;
+  else if (marker == SOLVABLE_FILEMARKER && (!before || !repo->lastmarkerpos))
+    return olddeps;
+  if (marker && !before && !repo->lastmarkerpos)
+    {
+      /* we have to add the marker first */
+      repo->lastmarkerpos = repo->idarraysize - 1;
+      olddeps = repo_addid(repo, olddeps, marker);
+      /* now put marker in hash */
+      h = marker & repo->lastidhash_mask;
+      hh = HASHCHAIN_START;
+      while (repo->lastidhash[h] != 0)
+       h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
+      repo->lastidhash[h] = marker;
+      repo->lastidhash_idarraysize = repo->idarraysize;
+    }
+  if (!hid)
+    {
+      /* new entry, insert in correct position */
+      if (marker && before && repo->lastmarkerpos)
+       {
+         /* need to add it before the marker */
+         olddeps = repo_addid(repo, olddeps, id);      /* dummy to make room */
+         memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (repo->idarraysize - repo->lastmarkerpos - 2) * sizeof(Id));
+         repo->idarraydata[repo->lastmarkerpos++] = id;
+       }
+      else
+       {
+         /* just append it to the end */
+         olddeps = repo_addid(repo, olddeps, id);
+       }
+      repo->lastidhash_idarraysize = repo->idarraysize;
+      return olddeps;
+    }
+  /* we already have it in the hash */
+  if (!marker)
+    return olddeps;
+  if (marker == SOLVABLE_FILEMARKER)
+    {
+      /* check if it is in the wrong half */
+      /* (we already made sure that "before" and "lastmarkerpos" are set, see above) */
+      for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
+       if (oid == id)
+         break;
+      if (!oid)
+       return olddeps;
+      /* yes, wrong half. copy it over */
+      memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (oidp - (repo->idarraydata + repo->lastmarkerpos)) * sizeof(Id));
+      repo->idarraydata[repo->lastmarkerpos++] = id;
+      return olddeps;
+    }
+  if (before)
+    return olddeps;
+  /* check if it is in the correct half */
+  for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
+    if (oid == id)
+      return olddeps;
+  /* nope, copy it over */
+  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
+    if (oid == id)
+      break;
+  if (!oid)
+    return olddeps;    /* should not happen */
+  memmove(oidp, oidp + 1, (repo->idarraydata + repo->idarraysize - oidp - 2) * sizeof(Id));
+  repo->idarraydata[repo->idarraysize - 2] = id;
+  repo->lastmarkerpos--;       /* marker has been moved */
+  return olddeps;
+}
+
+/*
+ * add dependency (as Id) to repo, also unifies dependencies
+ * olddeps = offset into idarraydata
+ * marker= 0 for normal dep
+ * marker > 0 add dep after marker
+ * marker < 0 add dep before -marker
+ * returns new start of dependency array
+ */
+Offset
+repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
+{
+  Id oid, *oidp, *markerp;
+  int before;
+
+  if (!olddeps)
+    {
+      if (marker > 0)
+       olddeps = repo_addid(repo, olddeps, marker);
+      return repo_addid(repo, olddeps, id);
+    }
+
+  /* check if we should use the hash optimization */
+  if (olddeps == repo->lastoff)
+    {
+      int size = repo->idarraysize - 1 - repo->lastoff;
+      if (size >= REPO_ADDID_DEP_HASHTHRES)
+        return repo_addid_dep_hash(repo, olddeps, id, marker, size);
+    }
+
+  before = 0;
+  if (marker)
+    {
+      if (marker < 0)
+       {
+         marker = -marker;
+         before = 1;
+       }
+      if (marker == id)
+       marker = 0;
+    }
+
+  if (!marker)
+    {
+      for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
+        if (oid == id)
+         return olddeps;
+      return repo_addid(repo, olddeps, id);
+    }
+
+  markerp = 0;
+  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
+    {
+      if (oid == marker)
+       markerp = oidp;
+      else if (oid == id)
+       break;
+    }
+
+  if (oid)
+    {
+      if (marker == SOLVABLE_FILEMARKER)
+       {
+         if (!markerp || !before)
+            return olddeps;
+          /* we found it, but in the second half */
+          memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
+          *markerp = id;
+          return olddeps;
+       }
+      if (markerp || before)
+        return olddeps;
+      /* we found it, but in the first half */
+      markerp = oidp++;
+      for (; (oid = *oidp) != 0; oidp++)
+        if (oid == marker)
+          break;
+      if (!oid)
+        {
+         /* no marker in array yet */
+          oidp--;
+          if (markerp < oidp)
+            memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
+          *oidp = marker;
+          return repo_addid(repo, olddeps, id);
+        }
+      while (oidp[1])
+        oidp++;
+      memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
+      *oidp = id;
+      return olddeps;
+    }
+  /* id not yet in array */
+  if (!before && !markerp)
+    olddeps = repo_addid(repo, olddeps, marker);
+  else if (before && markerp)
+    {
+      *markerp++ = id;
+      id = *--oidp;
+      if (markerp < oidp)
+        memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
+      *markerp = marker;
+    }
+  return repo_addid(repo, olddeps, id);
+}
+
+/* return standard marker for the keyname dependency.
+ * 1: return positive marker, -1: return negative marker
+ */
+Id
+solv_depmarker(Id keyname, Id marker)
+{
+  if (marker != 1 && marker != -1)
+    return marker;
+  if (keyname == SOLVABLE_PROVIDES)
+    return marker < 0 ? -SOLVABLE_FILEMARKER : SOLVABLE_FILEMARKER;
+  if (keyname == SOLVABLE_REQUIRES)
+    return marker < 0 ? -SOLVABLE_PREREQMARKER : SOLVABLE_PREREQMARKER;
+  return 0;
+}
+
+/*
+ * reserve Ids
+ * make space for 'num' more dependencies
+ * returns new start of dependency array
+ *
+ * reserved ids will always begin at offset idarraysize
+ */
+Offset
+repo_reserve_ids(Repo *repo, Offset olddeps, int num)
+{
+  num++;       /* room for trailing ID_NULL */
+
+  if (!repo->idarraysize)             /* ensure buffer space */
+    {
+      repo->idarraysize = 1;
+      repo->idarraydata = solv_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
+      repo->idarraydata[0] = 0;
+      repo->lastoff = 1;
+      return 1;
+    }
+
+  if (olddeps && olddeps != repo->lastoff)   /* if not appending */
+    {
+      /* can't insert into idarray, this would invalidate all 'larger' offsets
+       * so create new space at end and move existing deps there.
+       * Leaving 'hole' at old position.
+       */
+
+      Id *idstart, *idend;
+      int count;
+
+      for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
+       ;
+      count = idend - idstart - 1 + num;              /* new size */
+
+      repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
+      /* move old deps to end */
+      olddeps = repo->lastoff = repo->idarraysize;
+      memcpy(repo->idarraydata + olddeps, idstart, count - num);
+      repo->idarraysize = olddeps + count - num;
+
+      return olddeps;
+    }
+
+  if (olddeps)                        /* appending */
+    repo->idarraysize--;
+
+  /* make room*/
+  repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
+
+  /* appending or new */
+  repo->lastoff = olddeps ? olddeps : repo->idarraysize;
+
+  return repo->lastoff;
+}
+
+
+/***********************************************************************/
+
+struct matchdata
+{
+  Pool *pool;
+  int flags;
+  Datamatcher matcher;
+  int stop;
+  Id *keyskip;
+  int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
+  void *callback_data;
+};
+
+static int
+repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  struct matchdata *md = cbdata;
+
+  if (md->matcher.match)
+    {
+      const char *str;
+      if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0)
+       if (!datamatcher_checkbasename(&md->matcher, kv->str))
+         return 0;
+      if (!(str = repodata_stringify(md->pool, data, key, kv, md->flags)))
+       return 0;
+      if (!datamatcher_match(&md->matcher, str))
+       return 0;
+    }
+  else
+    {
+      /* stringify filelist if requested */
+      if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0)
+        repodata_stringify(md->pool, data, key, kv, md->flags);
+    }
+  md->stop = md->callback(md->callback_data, s, data, key, kv);
+  return md->stop;
+}
+
+
+/* list of all keys we store in the solvable */
+/* also used in the dataiterator code in repodata.c */
+Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
+  { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
+  { RPM_RPMDBID,          REPOKEY_TYPE_NUM, 0, KEY_STORAGE_SOLVABLE },
+};
+
+static void
+domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
+{
+  KeyValue kv;
+  kv.entry = 0;
+  kv.parent = 0;
+  for (; *ida && !md->stop; ida++)
+    {
+      kv.id = *ida;
+      kv.eof = ida[1] ? 0 : 1;
+      repo_matchvalue(md, s, 0, repo_solvablekeys + (keyname - SOLVABLE_NAME), &kv);
+      kv.entry++;
+    }
+}
+
+static void
+repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
+{
+  KeyValue kv;
+  Pool *pool = repo->pool;
+  Repodata *data;
+  int i, flags;
+  Solvable *s;
+  Id *keyskip;
+
+  kv.parent = 0;
+  md->stop = 0;
+  if (!p)
+    {
+      for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
+       {
+         if (s->repo == repo)
+            repo_search_md(repo, p, keyname, md);
+         if (md->stop > SEARCH_NEXT_SOLVABLE)
+           break;
+       }
+      return;
+    }
+  if (p < 0 && p != SOLVID_META)
+    return;            /* SOLVID_POS not supported yet */
+  flags = md->flags;
+  if (p > 0 && !(flags & SEARCH_NO_STORAGE_SOLVABLE))
+    {
+      s = pool->solvables + p;
+      switch(keyname)
+       {
+         case 0:
+         case SOLVABLE_NAME:
+           if (s->name)
+             {
+               kv.id = s->name;
+               repo_matchvalue(md, s, 0, repo_solvablekeys + 0, &kv);
+             }
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_ARCH:
+           if (s->arch)
+             {
+               kv.id = s->arch;
+               repo_matchvalue(md, s, 0, repo_solvablekeys + 1, &kv);
+             }
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_EVR:
+           if (s->evr)
+             {
+               kv.id = s->evr;
+               repo_matchvalue(md, s, 0, repo_solvablekeys + 2, &kv);
+             }
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_VENDOR:
+           if (s->vendor)
+             {
+               kv.id = s->vendor;
+               repo_matchvalue(md, s, 0, repo_solvablekeys + 3, &kv);
+             }
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_PROVIDES:
+           if (s->provides)
+             domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_OBSOLETES:
+           if (s->obsoletes)
+             domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_CONFLICTS:
+           if (s->conflicts)
+             domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_REQUIRES:
+           if (s->requires)
+             domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_RECOMMENDS:
+           if (s->recommends)
+             domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_SUPPLEMENTS:
+           if (s->supplements)
+             domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_SUGGESTS:
+           if (s->suggests)
+             domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case SOLVABLE_ENHANCES:
+           if (s->enhances)
+             domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+         case RPM_RPMDBID:
+           if (repo->rpmdbid)
+             {
+               kv.num = repo->rpmdbid[p - repo->start];
+               kv.num2 = 0;
+               repo_matchvalue(md, s, 0, repo_solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
+             }
+           if (keyname || md->stop > SEARCH_NEXT_KEY)
+             return;
+           break;
+         default:
+           break;
+       }
+    }
+
+  if (keyname)
+    {
+      if (keyname == SOLVABLE_FILELIST)
+       data = repo_lookup_filelist_repodata(repo, p, &md->matcher);
+      else
+        data = repo_lookup_repodata_opt(repo, p, keyname);
+      if (data)
+        repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
+      return;
+    }
+
+  keyskip = repo_create_keyskip(repo, p, &md->keyskip);
+  FOR_REPODATAS(repo, i, data)
+    {
+      if (p != SOLVID_META && (p < data->start || p >= data->end))
+       continue;
+      repodata_search_keyskip(data, p, keyname, md->flags, keyskip, repo_matchvalue, md);
+      if (md->stop > SEARCH_NEXT_KEY)
+       break;
+    }
+}
+
+void
+repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  struct matchdata md;
+
+  if (repo->disabled && !(flags & SEARCH_DISABLED_REPOS))
+    return;
+  memset(&md, 0, sizeof(md));
+  md.pool = repo->pool;
+  md.flags = flags;
+  md.callback = callback;
+  md.callback_data = cbdata;
+  if (match)
+    datamatcher_init(&md.matcher, match, flags);
+  repo_search_md(repo, p, keyname, &md);
+  if (match)
+    datamatcher_free(&md.matcher);
+  solv_free(md.keyskip);
+}
+
+Repodata *
+repo_lookup_repodata(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data;
+  int rdid;
+  Id type;
+
+  if (entry == SOLVID_POS)
+    {
+      Pool *pool = repo->pool;
+      return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
+    }
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {
+      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
+       continue;
+      if (!repodata_precheck_keyname(data, keyname))
+       continue;
+      if ((type = repodata_lookup_type(data, entry, keyname)) != 0)
+        return type == REPOKEY_TYPE_DELETED ? 0 : data;
+    }
+  return 0;
+}
+
+/* like repo_lookup_repodata, but may return a repodata that contains no match instead of NULL */
+Repodata *
+repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data, *found = 0;
+  int rdid;
+  Id type;
+
+  if (entry == SOLVID_POS)
+    {
+      Pool *pool = repo->pool;
+      return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
+    }
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {
+      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
+       continue;
+      if (!repodata_precheck_keyname(data, keyname))
+       continue;
+      if (found && (type = repodata_lookup_type(found, entry, keyname)) != 0)
+       return type == REPOKEY_TYPE_DELETED ? 0 : found;
+      found = data;
+    }
+  return found;
+}
+
+Repodata *
+repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher)
+{
+  Repodata *data;
+  int haveextension;
+  int rdid;
+  Id type;
+
+  if (entry <= 0 || !matcher || !matcher->match || ((matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
+      && (matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB))
+    return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);   /* cannot use filtered filelist */
+
+  haveextension = 0;
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {    
+      if (entry < data->start || entry >= data->end)
+       continue;
+      if (data->filelisttype == REPODATA_FILELIST_FILTERED)
+       {
+         if (data->state != REPODATA_AVAILABLE)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE || entry < data->start || entry >= data->end)
+               continue;
+           }
+         /* does this contain any data about the solvable we're looking for? */
+         if (!data->incoreoffset[entry - data->start])
+           continue;   /* no, ignore */
+         if (haveextension && repodata_filelistfilter_matches(data, matcher->match))
+           return data;
+         break;        /* fall back to normal code */
+       }
+      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+       continue;
+      if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+       {
+         haveextension++;
+         continue;
+       }
+      if ((type = repodata_lookup_type(data, entry, SOLVABLE_FILELIST)) != 0)
+       {
+         if (haveextension)
+           break;              /* need to look in extension */
+         return type == REPOKEY_TYPE_DELETED ? 0 : data;
+       }
+    }
+  /* cannot use filtered filelist */
+  return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);
+}
+
+
+/* the keyskip array has the following format:
+ * 0: keyname area size
+ * 1: repoid base
+ * 2: repoid end
+ * 3: entry for keyname 0
+ * 4: entry for keyname 1
+ * ...
+ */
+Id *
+repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip)
+{
+  Repodata *data, *last = 0;
+  Id *keyskip;
+  int rdid, cnt = 0;
+
+  if (repo->nrepodata <= 2)
+    return 0;  /* just one repodata, nothing to filter */
+  keyskip = oldkeyskip ? *oldkeyskip : 0;
+  if (keyskip)
+    {
+      if (keyskip[1] >= 0x10000000)
+       keyskip = solv_free(keyskip);
+      else
+        keyskip[1] = keyskip[2];
+    }
+  FOR_REPODATAS(repo, rdid, data)
+    {
+      if (entry != SOLVID_META)
+       {
+         if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE)
+               continue;
+           }
+         if ((entry < data->start || entry >= data->end))
+           continue;
+         if (!data->incoreoffset[entry - data->start])
+            continue;
+       }
+      if (last)
+        keyskip = repodata_fill_keyskip(last, entry, keyskip);
+      last = data;
+      cnt++;
+    }
+  if (cnt <= 1)
+    {
+      if (oldkeyskip)
+       *oldkeyskip = keyskip;
+      return 0;
+    }
+  keyskip = repodata_fill_keyskip(last, entry, keyskip);
+  if (keyskip)
+    keyskip[2] = keyskip[1] + repo->nrepodata;
+  if (oldkeyskip)
+    *oldkeyskip = keyskip;
+  return keyskip;
+}
+
+const char *
+repo_lookup_str(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data;
+
+  if (entry >= 0)
+    {
+      Pool *pool = repo->pool;
+      switch (keyname)
+       {
+       case SOLVABLE_NAME:
+         return pool_id2str(pool, pool->solvables[entry].name);
+       case SOLVABLE_ARCH:
+         return pool_id2str(pool, pool->solvables[entry].arch);
+       case SOLVABLE_EVR:
+         return pool_id2str(pool, pool->solvables[entry].evr);
+       case SOLVABLE_VENDOR:
+         return pool_id2str(pool, pool->solvables[entry].vendor);
+       }
+    }
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  return data ? repodata_lookup_str(data, entry, keyname) : 0;
+}
+
+
+unsigned long long
+repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
+{
+  Repodata *data;
+
+  if (entry >= 0)
+    {
+      if (keyname == RPM_RPMDBID)
+       {
+         if (repo->rpmdbid && entry >= repo->start && entry < repo->end)
+           return repo->rpmdbid[entry - repo->start];
+         return notfound;
+       }
+    }
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  return data ? repodata_lookup_num(data, entry, keyname, notfound) : notfound;
+}
+
+Id
+repo_lookup_id(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data;
+  Id id;
+
+  if (entry >= 0)
+    {
+      switch (keyname)
+       {
+       case SOLVABLE_NAME:
+         return repo->pool->solvables[entry].name;
+       case SOLVABLE_ARCH:
+         return repo->pool->solvables[entry].arch;
+       case SOLVABLE_EVR:
+         return repo->pool->solvables[entry].evr;
+       case SOLVABLE_VENDOR:
+         return repo->pool->solvables[entry].vendor;
+       }
+    }
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (id = repodata_lookup_id(data, entry, keyname)) != 0)
+    return data->localpool ? repodata_globalize_id(data, id, 1) : id;
+  return 0;
+}
+
+static int
+lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
+{
+  Id *p;
+
+  queue_empty(q);
+  if (off)
+    for (p = repo->idarraydata + off; *p; p++)
+      queue_push(q, *p);
+  return 1;
+}
+
+int
+repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
+{
+  Repodata *data;
+  int i;
+  if (entry >= 0)
+    {
+      switch (keyname)
+        {
+       case SOLVABLE_PROVIDES:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q);
+       case SOLVABLE_OBSOLETES:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q);
+       case SOLVABLE_CONFLICTS:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q);
+       case SOLVABLE_REQUIRES:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q);
+       case SOLVABLE_RECOMMENDS:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q);
+       case SOLVABLE_SUGGESTS:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q);
+       case SOLVABLE_SUPPLEMENTS:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q);
+       case SOLVABLE_ENHANCES:
+         return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
+        }
+    }
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && repodata_lookup_idarray(data, entry, keyname, q))
+    {
+      if (data->localpool)
+       {
+         for (i = 0; i < q->count; i++)
+           q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
+       }
+      return 1;
+    }
+  queue_empty(q);
+  return 0;
+}
+
+int
+repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker)
+{
+  int r = repo_lookup_idarray(repo, entry, keyname, q);
+  if (!r)
+    return 0;
+  if (marker == -1 || marker == 1)
+    marker = solv_depmarker(keyname, marker);
+  if (marker && q->count)
+    {
+      int i;
+      if (marker < 0)
+       {
+         marker = -marker;
+         for (i = 0; i < q->count; i++)
+           if (q->elements[i] == marker)
+             {
+               queue_truncate(q, i);
+               return r;
+             }
+       }
+      else
+       {
+         for (i = 0; i < q->count; i++)
+           if (q->elements[i] == marker)
+             {
+               queue_deleten(q, 0, i + 1);
+               return r;
+             }
+         queue_empty(q);
+       }
+    }
+  return r;
+}
+
+const unsigned char *
+repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
+{
+  const unsigned char *chk;
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (chk = repodata_lookup_bin_checksum(data, entry, keyname, typep)) != 0)
+    return chk;
+  *typep = 0;
+  return 0;
+}
+
+const char *
+repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
+{
+  const unsigned char *chk = repo_lookup_bin_checksum(repo, entry, keyname, typep);
+  return chk ? pool_bin2hex(repo->pool, chk, solv_chksum_len(*typep)) : 0;
+}
+
+int
+repo_lookup_void(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data)
+    return repodata_lookup_void(data, entry, keyname);
+  return 0;
+}
+
+Id
+repo_lookup_type(Repo *repo, Id entry, Id keyname)
+{
+  Id type;
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (type = repodata_lookup_type(data, entry, keyname)) != 0 && type != REPOKEY_TYPE_DELETED)
+    return type;
+  return 0;
+}
+
+const void *
+repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp)
+{
+  const void *bin;
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (bin = repodata_lookup_binary(data, entry, keyname, lenp)) != 0)
+    return bin;
+  *lenp = 0;
+  return 0;
+}
+
+/***********************************************************************/
+
+Repodata *
+repo_add_repodata(Repo *repo, int flags)
+{
+  Repodata *data;
+  int i;
+  if ((flags & REPO_USE_LOADING) != 0)
+    {
+      for (i = repo->nrepodata - 1; i > 0; i--)
+       if (repo->repodata[i].state == REPODATA_LOADING)
+         {
+           Repodata *data = repo->repodata + i;
+           /* re-init */
+           /* hack: we mis-use REPO_REUSE_REPODATA here */
+           if (!(flags & REPO_REUSE_REPODATA))
+             repodata_empty(data, (flags & REPO_LOCALPOOL) ? 1 : 0);
+           return data;
+         }
+      return 0;        /* must not create a new repodata! */
+    }
+  if ((flags & REPO_REUSE_REPODATA) != 0)
+    {
+      for (i = repo->nrepodata - 1; i > 0; i--)
+       if (repo->repodata[i].state != REPODATA_STUB)
+         return repo->repodata + i;
+    }
+  if (!repo->nrepodata)
+    {
+      repo->nrepodata = 2;      /* start with id 1 */
+      repo->repodata = solv_calloc(repo->nrepodata, sizeof(*data));
+    }
+  else
+    {
+      repo->nrepodata++;
+      repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
+    }
+  data = repo->repodata + repo->nrepodata - 1;
+  repodata_initdata(data, repo, (flags & REPO_LOCALPOOL) ? 1 : 0);
+  return data;
+}
+
+Repodata *
+repo_id2repodata(Repo *repo, Id id)
+{
+  return id ? repo->repodata + id : 0;
+}
+
+Repodata *
+repo_last_repodata(Repo *repo)
+{
+  int i;
+  for (i = repo->nrepodata - 1; i > 0; i--)
+    if (repo->repodata[i].state != REPODATA_STUB)
+      return repo->repodata + i;
+  return repo_add_repodata(repo, 0);
+}
+
+void
+repo_set_id(Repo *repo, Id p, Id keyname, Id id)
+{
+  Repodata *data;
+  if (p >= 0)
+    {
+      switch (keyname)
+       {
+       case SOLVABLE_NAME:
+         repo->pool->solvables[p].name = id;
+         return;
+       case SOLVABLE_ARCH:
+         repo->pool->solvables[p].arch = id;
+         return;
+       case SOLVABLE_EVR:
+         repo->pool->solvables[p].evr = id;
+         return;
+       case SOLVABLE_VENDOR:
+         repo->pool->solvables[p].vendor = id;
+         return;
+       }
+    }
+  data = repo_last_repodata(repo);
+  if (data->localpool)
+    id = repodata_localize_id(data, id, 1);
+  repodata_set_id(data, p, keyname, id);
+}
+
+void
+repo_set_num(Repo *repo, Id p, Id keyname, unsigned long long num)
+{
+  Repodata *data;
+  if (p >= 0)
+    {
+      if (keyname == RPM_RPMDBID)
+       {
+         if (!repo->rpmdbid)
+           repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
+         repo->rpmdbid[p - repo->start] = num;
+         return;
+       }
+    }
+  data = repo_last_repodata(repo);
+  repodata_set_num(data, p, keyname, num);
+}
+
+void
+repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
+{
+  Repodata *data;
+  if (p >= 0)
+    {
+      switch (keyname)
+       {
+       case SOLVABLE_NAME:
+       case SOLVABLE_ARCH:
+       case SOLVABLE_EVR:
+       case SOLVABLE_VENDOR:
+         repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
+         return;
+       }
+    }
+  data = repo_last_repodata(repo);
+  repodata_set_str(data, p, keyname, str);
+}
+
+void
+repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
+{
+  Repodata *data;
+  if (p >= 0)
+    {
+      switch (keyname)
+       {
+       case SOLVABLE_NAME:
+       case SOLVABLE_ARCH:
+       case SOLVABLE_EVR:
+       case SOLVABLE_VENDOR:
+         repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
+         return;
+       }
+    }
+  data = repo_last_repodata(repo);
+  repodata_set_poolstr(data, p, keyname, str);
+}
+
+void
+repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
+{
+  Repodata *data = repo_last_repodata(repo);
+  repodata_add_poolstr_array(data, p, keyname, str);
+}
+
+void
+repo_add_deparray(Repo *repo, Id p, Id keyname, Id dep, Id marker)
+{
+  Repodata *data;
+  if (marker == -1 || marker == 1)
+    marker = solv_depmarker(keyname, marker);
+  if (p >= 0)
+    {
+      Solvable *s = repo->pool->solvables + p;
+      switch (keyname)
+       {
+       case SOLVABLE_PROVIDES:
+         s->provides = repo_addid_dep(repo, s->provides, dep, marker);
+         return;
+       case SOLVABLE_OBSOLETES:
+         s->obsoletes = repo_addid_dep(repo, s->obsoletes, dep, marker);
+         return;
+       case SOLVABLE_CONFLICTS:
+         s->conflicts = repo_addid_dep(repo, s->conflicts, dep, marker);
+         return;
+       case SOLVABLE_REQUIRES:
+         s->requires = repo_addid_dep(repo, s->requires, dep, marker);
+         return;
+       case SOLVABLE_RECOMMENDS:
+         s->recommends = repo_addid_dep(repo, s->recommends, dep, marker);
+         return;
+       case SOLVABLE_SUGGESTS:
+         s->suggests = repo_addid_dep(repo, s->suggests, dep, marker);
+         return;
+       case SOLVABLE_SUPPLEMENTS:
+         s->supplements = repo_addid_dep(repo, s->supplements, dep, marker);
+         return;
+       case SOLVABLE_ENHANCES:
+         s->enhances = repo_addid_dep(repo, s->enhances, dep, marker);
+         return;
+       }
+    }
+  data = repo_last_repodata(repo);
+  repodata_add_idarray(data, p, keyname, dep);
+}
+
+void
+repo_add_idarray(Repo *repo, Id p, Id keyname, Id id)
+{
+  repo_add_deparray(repo, p, keyname, id, 0);
+}
+
+static Offset
+repo_set_idarray_solvable(Repo *repo, Queue *q)
+{
+  Offset o = 0;
+  int i;
+  for (i = 0; i < q->count; i++)
+    repo_addid_dep(repo, o, q->elements[i], 0);
+  return o;
+}
+
+void
+repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker)
+{
+  Repodata *data;
+  if (marker == -1 || marker == 1)
+    marker = solv_depmarker(keyname, marker);
+  if (marker)
+    {
+      /* complex case, splice old and new arrays */
+      int i;
+      Queue q2;
+      queue_init(&q2);
+      repo_lookup_deparray(repo, p, keyname, &q2, -marker);
+      if (marker > 0)
+       {
+         if (q->count)
+           {
+             queue_push(&q2, marker);
+             for (i = 0; i < q->count; i++)
+               queue_push(&q2, q->elements[i]);
+           }
+       }
+      else
+       {
+         if (q2.count)
+           queue_insert(&q2, 0, -marker);
+         queue_insertn(&q2, 0, q->count, q->elements);
+       }
+      repo_set_deparray(repo, p, keyname, &q2, 0);
+      queue_free(&q2);
+      return;
+    }
+  if (p >= 0)
+    {
+      Solvable *s = repo->pool->solvables + p;
+      switch (keyname)
+       {
+       case SOLVABLE_PROVIDES:
+         s->provides = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_OBSOLETES:
+         s->obsoletes = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_CONFLICTS:
+         s->conflicts = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_REQUIRES:
+         s->requires = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_RECOMMENDS:
+         s->recommends = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_SUGGESTS:
+         s->suggests = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_SUPPLEMENTS:
+         s->supplements = repo_set_idarray_solvable(repo, q);
+         return;
+       case SOLVABLE_ENHANCES:
+         s->enhances = repo_set_idarray_solvable(repo, q);
+         return;
+       }
+    }
+  data = repo_last_repodata(repo);
+  repodata_set_idarray(data, p, keyname, q);
+}
+
+void
+repo_set_idarray(Repo *repo, Id p, Id keyname, Queue *q)
+{
+  repo_set_deparray(repo, p, keyname, q, 0);
+}
+
+void
+repo_unset(Repo *repo, Id p, Id keyname)
+{
+  Repodata *data;
+  if (p >= 0)
+    {
+      Solvable *s = repo->pool->solvables + p;
+      switch (keyname)
+       {
+       case SOLVABLE_NAME:
+         s->name = 0;
+         return;
+       case SOLVABLE_ARCH:
+         s->arch = 0;
+         return;
+       case SOLVABLE_EVR:
+         s->evr = 0;
+         return;
+       case SOLVABLE_VENDOR:
+         s->vendor = 0;
+         return;
+        case RPM_RPMDBID:
+         if (repo->rpmdbid)
+           repo->rpmdbid[p - repo->start] = 0;
+         return;
+       case SOLVABLE_PROVIDES:
+         s->provides = 0;
+         return;
+       case SOLVABLE_OBSOLETES:
+         s->obsoletes = 0;
+         return;
+       case SOLVABLE_CONFLICTS:
+         s->conflicts = 0;
+         return;
+       case SOLVABLE_REQUIRES:
+         s->requires = 0;
+         return;
+       case SOLVABLE_RECOMMENDS:
+         s->recommends = 0;
+         return;
+       case SOLVABLE_SUGGESTS:
+         s->suggests = 0;
+         return;
+       case SOLVABLE_SUPPLEMENTS:
+         s->supplements = 0;
+       case SOLVABLE_ENHANCES:
+         s->enhances = 0;
+         return;
+       default:
+         break;
+       }
+    }
+  data = repo_last_repodata(repo);
+  repodata_unset(data, p, keyname);
+}
+
+void
+repo_internalize(Repo *repo)
+{
+  int i;
+  Repodata *data;
+
+  FOR_REPODATAS(repo, i, data)
+    if (data->attrs || data->xattrs)
+      repodata_internalize(data);
+}
+
+void
+repo_disable_paging(Repo *repo)
+{
+  int i;
+  Repodata *data;
+
+  FOR_REPODATAS(repo, i, data)
+    repodata_disable_paging(data);
+}
+
diff --git a/libsolv-0.7.2/src/repo.h b/libsolv-0.7.2/src/repo.h
new file mode 100644 (file)
index 0000000..58704f1
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo.h
+ *
+ */
+
+#ifndef LIBSOLV_REPO_H
+#define LIBSOLV_REPO_H
+
+#include "pooltypes.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "repodata.h"
+#include "dataiterator.h"
+#include "hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct s_Repo {
+  const char *name;            /* name pointer */
+  Id repoid;                   /* our id */
+  void *appdata;               /* application private pointer */
+
+  Pool *pool;                  /* pool containing this repo */
+
+  int start;                   /* start of this repo solvables within pool->solvables */
+  int end;                     /* last solvable + 1 of this repo */
+  int nsolvables;              /* number of solvables repo is contributing to pool */
+
+  int disabled;                        /* ignore the solvables? */
+  int priority;                        /* priority of this repo */
+  int subpriority;             /* sub-priority of this repo, used just for sorting, not pruning */
+
+  Id *idarraydata;             /* array of metadata Ids, solvable dependencies are offsets into this array */
+  int idarraysize;
+
+  int nrepodata;               /* number of our stores..  */
+
+  Id *rpmdbid;                 /* solvable side data: rpm database id */
+
+#ifdef LIBSOLV_INTERNAL
+  Repodata *repodata;          /* our stores for non-solvable related data */
+  Offset lastoff;              /* start of last array in idarraydata */
+
+  Hashtable lastidhash;                /* hash to speed up repo_addid_dep */
+  Hashval lastidhash_mask;
+  int lastidhash_idarraysize;
+  int lastmarker;
+  Offset lastmarkerpos;
+#endif /* LIBSOLV_INTERNAL */
+} Repo;
+
+extern Repo *repo_create(Pool *pool, const char *name);
+extern void repo_free(Repo *repo, int reuseids);
+extern void repo_empty(Repo *repo, int reuseids);
+extern void repo_freedata(Repo *repo);
+extern Id repo_add_solvable(Repo *repo);
+extern Id repo_add_solvable_block(Repo *repo, int count);
+extern void repo_free_solvable(Repo *repo, Id p, int reuseids);
+extern void repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids);
+extern void *repo_sidedata_create(Repo *repo, size_t size);
+extern void *repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count);
+extern Id repo_add_solvable_block_before(Repo *repo, int count, Repo *beforerepo);
+
+extern Offset repo_addid(Repo *repo, Offset olddeps, Id id);
+extern Offset repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker);
+extern Offset repo_reserve_ids(Repo *repo, Offset olddeps, int num);
+
+static inline const char *repo_name(const Repo *repo)
+{
+  return repo->name;
+}
+
+/* those two functions are here because they need the Repo definition */
+
+static inline Repo *pool_id2repo(Pool *pool, Id repoid)
+{
+  return repoid < pool->nrepos ? pool->repos[repoid] : 0;
+}
+
+static inline int pool_disabled_solvable(const Pool *pool, Solvable *s)
+{
+  if (s->repo && s->repo->disabled)
+    return 1;
+  if (pool->considered)
+    {
+      Id id = s - pool->solvables;
+      if (!MAPTST(pool->considered, id))
+       return 1;
+    }
+  return 0;
+}
+
+static inline int pool_badarch_solvable(const Pool *pool, Solvable *s)
+{
+  if (pool->id2arch && (!s->arch || pool_arch2score(pool, s->arch) == 0))
+    return 1;
+  return 0;
+}
+
+static inline int pool_installable(const Pool *pool, Solvable *s)
+{
+  if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+    return 0;
+  if (s->repo && s->repo->disabled)
+    return 0;
+  if (pool->id2arch && (!s->arch || pool_arch2score(pool, s->arch) == 0))
+    return 0;
+  if (pool->considered)
+    {
+      Id id = s - pool->solvables;
+      if (!MAPTST(pool->considered, id))
+       return 0;
+    }
+  return 1;
+}
+
+/* not in solvable.h because we need the repo definition */
+static inline Solvable *solvable_free(Solvable *s, int reuseids)
+{
+  if (s && s->repo)
+    repo_free_solvable(s->repo, s - s->repo->pool->solvables, reuseids);
+  return 0;
+}
+
+/* search callback values */
+#define SEARCH_NEXT_KEY         1
+#define SEARCH_NEXT_SOLVABLE    2
+#define SEARCH_STOP             3
+#define SEARCH_ENTERSUB                -1
+
+/* standard flags used in the repo_add functions */
+#define REPO_REUSE_REPODATA            (1 << 0)
+#define REPO_NO_INTERNALIZE            (1 << 1)
+#define REPO_LOCALPOOL                 (1 << 2)
+#define REPO_USE_LOADING               (1 << 3)
+#define REPO_EXTEND_SOLVABLES          (1 << 4)
+#define REPO_USE_ROOTDIR               (1 << 5)
+#define REPO_NO_LOCATION               (1 << 6)
+
+Repodata *repo_add_repodata(Repo *repo, int flags);
+Repodata *repo_id2repodata(Repo *repo, Id id);
+Repodata *repo_last_repodata(Repo *repo);
+
+void repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata);
+
+/* returns the last repodata that contains the key */
+Repodata *repo_lookup_repodata(Repo *repo, Id entry, Id keyname);
+Repodata *repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname);
+Repodata *repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher);
+
+/* returns the string value of the attribute, or NULL if not found */
+Id repo_lookup_type(Repo *repo, Id entry, Id keyname);
+const char *repo_lookup_str(Repo *repo, Id entry, Id keyname);
+/* returns the integer value of the attribute, or notfound if not found */
+unsigned long long repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound);
+Id repo_lookup_id(Repo *repo, Id entry, Id keyname);
+int repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q);
+int repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker);
+int repo_lookup_void(Repo *repo, Id entry, Id keyname);
+const char *repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep);
+const unsigned char *repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep);
+const void *repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp);
+Id solv_depmarker(Id keyname, Id marker);
+
+void repo_set_id(Repo *repo, Id p, Id keyname, Id id);
+void repo_set_num(Repo *repo, Id p, Id keyname, unsigned long long num);
+void repo_set_str(Repo *repo, Id p, Id keyname, const char *str);
+void repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str);
+void repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str);
+void repo_add_idarray(Repo *repo, Id p, Id keyname, Id id);
+void repo_add_deparray(Repo *repo, Id p, Id keyname, Id dep, Id marker);
+void repo_set_idarray(Repo *repo, Id p, Id keyname, Queue *q);
+void repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker);
+void repo_unset(Repo *repo, Id p, Id keyname);
+
+void repo_internalize(Repo *repo);
+void repo_disable_paging(Repo *repo);
+Id *repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip);
+
+
+/* iterator macros */
+#define FOR_REPO_SOLVABLES(r, p, s)                                            \
+  for (p = (r)->start, s = (r)->pool->solvables + p; p < (r)->end; p++, s = (r)->pool->solvables + p)  \
+    if (s->repo != (r))                                                                \
+      continue;                                                                        \
+    else
+
+#ifdef LIBSOLV_INTERNAL
+#define FOR_REPODATAS(repo, rdid, data)        \
+       for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++)
+#else
+#define FOR_REPODATAS(repo, rdid, data)        \
+       for (rdid = 1; rdid < repo->nrepodata && (data = repo_id2repodata(repo, rdid)); rdid++)
+#endif
+
+/* weird suse stuff, do not use */
+extern Offset repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens);
+extern Offset repo_fix_conflicts(Repo *repo, Offset conflicts);
+extern void repo_rewrite_suse_deps(Solvable *s, Offset freshens);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_REPO_H */
diff --git a/libsolv-0.7.2/src/repo_solv.c b/libsolv-0.7.2/src/repo_solv.c
new file mode 100644 (file)
index 0000000..be33967
--- /dev/null
@@ -0,0 +1,1355 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_solv.c
+ *
+ * Add a repo in solv format
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "repo_solv.h"
+#include "util.h"
+
+#include "repopack.h"
+#include "repopage.h"
+
+#include "poolid_private.h"    /* WHATPROVIDES_BLOCK */
+
+#define INTERESTED_START       SOLVABLE_NAME
+#define INTERESTED_END         SOLVABLE_ENHANCES
+
+#define SOLV_ERROR_NOT_SOLV    1
+#define SOLV_ERROR_UNSUPPORTED 2
+#define SOLV_ERROR_EOF         3
+#define SOLV_ERROR_ID_RANGE    4
+#define SOLV_ERROR_OVERFLOW    5
+#define SOLV_ERROR_CORRUPT     6
+
+
+
+/*******************************************************************************
+ * functions to extract data from a file handle
+ */
+
+/*
+ * read u32
+ */
+
+static unsigned int
+read_u32(Repodata *data)
+{
+  int c, i;
+  unsigned int x = 0;
+
+  if (data->error)
+    return 0;
+  for (i = 0; i < 4; i++)
+    {
+      c = getc(data->fp);
+      if (c == EOF)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
+         return 0;
+       }
+      x = (x << 8) | c;
+    }
+  return x;
+}
+
+
+/*
+ * read u8
+ */
+
+static unsigned int
+read_u8(Repodata *data)
+{
+  int c;
+
+  if (data->error)
+    return 0;
+  c = getc(data->fp);
+  if (c == EOF)
+    {
+      data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
+      return 0;
+    }
+  return c;
+}
+
+
+/*
+ * read Id
+ */
+
+static Id
+read_id(Repodata *data, Id max)
+{
+  unsigned int x = 0;
+  int c, i;
+
+  if (data->error)
+    return 0;
+  for (i = 0; i < 5; i++)
+    {
+      c = getc(data->fp);
+      if (c == EOF)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
+         return 0;
+       }
+      if (!(c & 128))
+       {
+         x = (x << 7) | c;
+         if (max && x >= (unsigned int)max)
+           {
+             data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_id: id too large (%u/%u)", x, max);
+             return 0;
+           }
+         return x;
+       }
+      x = (x << 7) ^ c ^ 128;
+    }
+  data->error = pool_error(data->repo->pool, SOLV_ERROR_CORRUPT, "read_id: id too long");
+  return 0;
+}
+
+
+static Id *
+read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
+{
+  unsigned int x = 0;
+  int c;
+
+  if (data->error)
+    return 0;
+  for (;;)
+    {
+      c = getc(data->fp);
+      if (c == EOF)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
+         return 0;
+       }
+      if ((c & 128) != 0)
+       {
+         x = (x << 7) ^ c ^ 128;
+         continue;
+       }
+      x = (x << 6) | (c & 63);
+      if (max && x >= (unsigned int)max)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "read_idarray: id too large (%u/%u)", x, max);
+         return 0;
+       }
+      if (map)
+       x = map[x];
+      if (store == end)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
+         return 0;
+       }
+      *store++ = x;
+      if ((c & 64) == 0)
+       {
+         if (x == 0)   /* already have trailing zero? */
+           return store;
+         if (store == end)
+           {
+             data->error = pool_error(data->repo->pool, SOLV_ERROR_OVERFLOW, "read_idarray: array overflow");
+             return 0;
+           }
+         *store++ = 0;
+         return store;
+       }
+      x = 0;
+    }
+}
+
+
+/*******************************************************************************
+ * functions to extract data from memory
+ */
+
+/*
+ * read array of Ids
+ */
+
+static inline unsigned char *
+data_read_id_max(unsigned char *dp, Id *ret, Id *map, int max, Repodata *data)
+{
+  Id x;
+  dp = data_read_id(dp, &x);
+  if (x < 0 || (max && x >= max))
+    {
+      data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_id_max: id too large (%u/%u)", x, max);
+      x = 0;
+    }
+  *ret = map ? map[x] : x;
+  return dp;
+}
+
+static unsigned char *
+data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data)
+{
+  Id *store = *storep;
+  unsigned int x = 0;
+  int c;
+
+  for (;;)
+    {
+      c = *dp++;
+      if ((c & 128) != 0)
+       {
+         x = (x << 7) ^ c ^ 128;
+         continue;
+       }
+      x = (x << 6) | (c & 63);
+      if (max && x >= (unsigned int)max)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_idarray: id too large (%u/%u)", x, max);
+         data->error = SOLV_ERROR_ID_RANGE;
+         break;
+       }
+      *store++ = map ? map[x] : x;
+      if ((c & 64) == 0)
+        break;
+      x = 0;
+    }
+  *store++ = 0;
+  *storep = store;
+  return dp;
+}
+
+static unsigned char *
+data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id marker)
+{
+  Id *store = *storep;
+  Id old = 0;
+  unsigned int x = 0;
+  int c;
+
+  for (;;)
+    {
+      c = *dp++;
+      if ((c & 128) != 0)
+       {
+         x = (x << 7) ^ c ^ 128;
+         continue;
+       }
+      x = (x << 6) | (c & 63);
+      if (x == 0)
+       {
+         if (!(c & 64))
+           break;
+          if (marker)
+           *store++ = marker;
+         old = 0;
+         continue;
+       }
+      x = old + (x - 1);
+      old = x;
+      if (max && x >= (unsigned int)max)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "data_read_rel_idarray: id too large (%u/%u)", x, max);
+         break;
+       }
+      *store++ = map ? map[x] : x;
+      if (!(c & 64))
+        break;
+      x = 0;
+    }
+  *store++ = 0;
+  *storep = store;
+  return dp;
+}
+
+
+
+
+/*******************************************************************************
+ * functions to add data to our incore memory space
+ */
+
+#define INCORE_ADD_CHUNK 8192
+#define DATA_READ_CHUNK 8192
+
+static void
+incore_add_id(Repodata *data, Id sx)
+{
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+  /* make sure we have at least 5 bytes free */
+  if (data->incoredatafree < 5)
+    {
+      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
+      data->incoredatafree = INCORE_ADD_CHUNK;
+    }
+  dp = data->incoredata + data->incoredatalen;
+  if (x >= (1 << 14))
+    {
+      if (x >= (1 << 28))
+       *dp++ = (x >> 28) | 128;
+      if (x >= (1 << 21))
+       *dp++ = (x >> 21) | 128;
+      *dp++ = (x >> 14) | 128;
+    }
+  if (x >= (1 << 7))
+    *dp++ = (x >> 7) | 128;
+  *dp++ = x & 127;
+  data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
+  data->incoredatalen = dp - data->incoredata;
+}
+
+static void
+incore_add_sizek(Repodata *data, unsigned int sx)
+{
+  if (sx < (1 << 22))
+    incore_add_id(data, (Id)(sx << 10));
+  else
+    {
+      if ((sx >> 25) != 0)
+       {
+         incore_add_id(data, (Id)(sx >> 25));
+         data->incoredata[data->incoredatalen - 1] |= 128;
+       }
+      incore_add_id(data, (Id)((sx << 10) | 0x80000000));
+      data->incoredata[data->incoredatalen - 5] = (sx >> 18) | 128;
+    }
+}
+
+static void
+incore_add_ideof(Repodata *data, Id sx, int eof)
+{
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+  /* make sure we have at least 5 bytes free */
+  if (data->incoredatafree < 5)
+    {
+      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
+      data->incoredatafree = INCORE_ADD_CHUNK;
+    }
+  dp = data->incoredata + data->incoredatalen;
+  if (x >= (1 << 13))
+    {
+      if (x >= (1 << 27))
+       *dp++ = (x >> 27) | 128;
+      if (x >= (1 << 20))
+       *dp++ = (x >> 20) | 128;
+      *dp++ = (x >> 13) | 128;
+    }
+  if (x >= (1 << 6))
+    *dp++ = (x >> 6) | 128;
+  *dp++ = eof ? (x & 63) : (x & 63) | 64;
+  data->incoredatafree -= dp - (data->incoredata + data->incoredatalen);
+  data->incoredatalen = dp - data->incoredata;
+}
+
+static void
+incore_add_blob(Repodata *data, unsigned char *buf, int len)
+{
+  if (data->incoredatafree < (unsigned int)len)
+    {
+      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK + len);
+      data->incoredatafree = INCORE_ADD_CHUNK + len;
+    }
+  memcpy(data->incoredata + data->incoredatalen, buf, len);
+  data->incoredatafree -= len;
+  data->incoredatalen += len;
+}
+
+static void
+incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
+{
+  /* We have to map the IDs, which might also change
+     the necessary number of bytes, so we can't just copy
+     over the blob and adjust it.  */
+  for (;;)
+    {
+      Id id;
+      int eof;
+      dp = data_read_ideof(dp, &id, &eof);
+      if (id < 0 || (max && id >= max))
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "incore_map_idarray: id too large (%u/%u)", id, max);
+         break;
+       }
+      id = map[id];
+      incore_add_ideof(data, id, eof);
+      if (eof)
+       break;
+    }
+}
+
+#if 0
+static void
+incore_add_u32(Repodata *data, unsigned int x)
+{
+  unsigned char *dp;
+  /* make sure we have at least 4 bytes free */
+  if (data->incoredatafree < 4)
+    {
+      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + INCORE_ADD_CHUNK);
+      data->incoredatafree = INCORE_ADD_CHUNK;
+    }
+  dp = data->incoredata + data->incoredatalen;
+  *dp++ = x >> 24;
+  *dp++ = x >> 16;
+  *dp++ = x >> 8;
+  *dp++ = x;
+  data->incoredatafree -= 4;
+  data->incoredatalen += 4;
+}
+
+static void
+incore_add_u8(Repodata *data, unsigned int x)
+{
+  unsigned char *dp;
+  /* make sure we have at least 1 byte free */
+  if (data->incoredatafree < 1)
+    {
+      data->incoredata = solv_realloc(data->incoredata, data->incoredatalen + 1024);
+      data->incoredatafree = 1024;
+    }
+  dp = data->incoredata + data->incoredatalen;
+  *dp++ = x;
+  data->incoredatafree--;
+  data->incoredatalen++;
+}
+#endif
+
+
+/*******************************************************************************
+ * our main function
+ */
+
+/*
+ * read repo from .solv file and add it to pool
+ */
+
+int
+repo_add_solv(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  int i, l;
+  int numid, numrel, numdir, numsolv;
+  int numkeys, numschemata;
+
+  Offset sizeid;
+  Offset *str;                        /* map Id -> Offset into string space */
+  char *strsp;                        /* repo string space */
+  char *sp;                           /* pointer into string space */
+  Id *idmap;                          /* map of repo Ids to pool Ids */
+  Id id, type;
+  Hashval hashmask, h, hh;
+  Hashtable hashtbl;
+  Id name, evr, did;
+  int relflags;
+  Reldep *ran;
+  unsigned int size_idarray;
+  Id *idarraydatap, *idarraydataend;
+  Offset ido;
+  Solvable *s;
+  unsigned int solvflags;
+  unsigned int solvversion;
+  Repokey *keys;
+  Id *schemadata, *schemadatap, *schemadataend;
+  Id *schemata, key, *keyp;
+  int nentries;
+  int have_incoredata;
+  int maxsize, allsize;
+  unsigned char *buf, *bufend, *dp, *dps;
+  Id stack[3 * 5];
+  int keydepth;
+  int needchunk;       /* need a new chunk of data */
+  unsigned int now;
+  int oldnstrings = pool->ss.nstrings;
+  int oldnrels = pool->nrels;
+
+  struct s_Stringpool *spool;
+
+  Repodata *parent = 0;
+  Repodata data;
+
+  int extendstart = 0, extendend = 0;  /* set in case we're extending */
+
+  now = solv_timems(0);
+
+  if ((flags & REPO_USE_LOADING) != 0)
+    {
+      /* this is a stub replace operation */
+      flags |= REPO_EXTEND_SOLVABLES;
+      /* use REPO_REUSE_REPODATA hack so that the old repodata is kept */
+      parent = repo_add_repodata(repo, flags | REPO_REUSE_REPODATA);
+      extendstart = parent->start;
+      extendend = parent->end;
+    }
+  else if (flags & REPO_EXTEND_SOLVABLES)
+    {
+      /* extend all solvables of this repo */
+      extendstart = repo->start;
+      extendend = repo->end;
+    }
+
+  memset(&data, 0, sizeof(data));
+  data.repo = repo;
+  data.fp = fp;
+  repopagestore_init(&data.store);
+
+  if (read_u32(&data) != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
+     return pool_error(pool, SOLV_ERROR_NOT_SOLV, "not a SOLV file");
+  solvversion = read_u32(&data);
+  switch (solvversion)
+    {
+      case SOLV_VERSION_8:
+       break;
+      default:
+        return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
+    }
+
+  numid = (int)read_u32(&data);
+  numrel = (int)read_u32(&data);
+  numdir = (int)read_u32(&data);
+  numsolv = (int)read_u32(&data);
+  numkeys = (int)read_u32(&data);
+  numschemata = (int)read_u32(&data);
+  solvflags = read_u32(&data);
+
+  if (numid < 0 || numid >= 0x20000000)
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of ids");
+  if (numrel < 0 || numrel >= 0x20000000)
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of rels");
+  if (numdir && (numdir < 2 || numdir >= 0x20000000))
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of dirs");
+  if (numsolv < 0 || numsolv >= 0x20000000)
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of solvables");
+  if (numkeys < 0 || numkeys >= 0x20000000)
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of keys");
+  if (numschemata < 0 || numschemata >= 0x20000000)
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "bad number of schematas");
+
+  if (numrel && (flags & REPO_LOCALPOOL) != 0)
+    return pool_error(pool, SOLV_ERROR_CORRUPT, "relations are forbidden in a local pool");
+  if ((flags & REPO_EXTEND_SOLVABLES) && numsolv)
+    {
+      /* make sure that we exactly replace the stub repodata */
+      if (extendend - extendstart != numsolv)
+       return pool_error(pool, SOLV_ERROR_CORRUPT, "sub-repository solvable number does not match main repository (%d - %d)", extendend - extendstart, numsolv);
+      for (i = 0; i < numsolv; i++)
+       if (pool->solvables[extendstart + i].repo != repo)
+         return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
+    }
+
+  /*******  Part 1: string IDs  *****************************************/
+
+  sizeid = read_u32(&data);           /* size of string space */
+
+  /*
+   * read strings and Ids
+   *
+   */
+
+
+  /*
+   * alloc buffers
+   */
+
+  if (!(flags & REPO_LOCALPOOL))
+    {
+      spool = &pool->ss;
+      /* alloc max needed string buffer and string pointers, will shrink again later */
+#if 0
+      spool->stringspace = solv_realloc(spool->stringspace, spool->sstrings + sizeid + 1);
+      spool->strings = solv_realloc2(spool->strings, spool->nstrings + numid, sizeof(Offset));
+#else
+      spool->sstrings += sizeid + 1;
+      spool->nstrings += numid;
+      stringpool_shrink(spool);                /* we misuse stringpool_shrink so that the correct BLOCK factor is used */
+      spool->sstrings -= sizeid + 1;
+      spool->nstrings -= numid;
+#endif
+    }
+  else
+    {
+      data.localpool = 1;
+      spool = &data.spool;
+      spool->stringspace = solv_malloc(7 + sizeid + 1);
+      spool->strings = solv_malloc2(numid < 2 ?  2 : numid, sizeof(Offset));
+      strcpy(spool->stringspace, "<NULL>");
+      spool->sstrings = 7;
+      spool->nstrings = 1;
+      spool->strings[0] = 0;   /* <NULL> */
+    }
+
+
+  /*
+   * read string data and append to old string space
+   */
+
+  strsp = spool->stringspace + spool->sstrings;        /* append new entries */
+  if ((solvflags & SOLV_FLAG_PREFIX_POOL) == 0)
+    {
+      if (sizeid && fread(strsp, sizeid, 1, fp) != 1)
+       {
+         repodata_freedata(&data);
+         return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
+       }
+    }
+  else
+    {
+      unsigned int pfsize = read_u32(&data);
+      char *prefix = solv_malloc(pfsize);
+      char *pp = prefix;
+      char *old_str = strsp;
+      char *dest = strsp;
+      int freesp = sizeid;
+
+      if (pfsize && fread(prefix, pfsize, 1, fp) != 1)
+       {
+         solv_free(prefix);
+         repodata_freedata(&data);
+         return pool_error(pool, SOLV_ERROR_EOF, "read error while reading strings");
+       }
+      for (i = 1; i < numid; i++)
+        {
+         int same = (unsigned char)*pp++;
+         size_t len = strlen(pp) + 1;
+         freesp -= same + len;
+         if (freesp < 0)
+           {
+             solv_free(prefix);
+             repodata_freedata(&data);
+             return pool_error(pool, SOLV_ERROR_OVERFLOW, "overflow while expanding strings");
+           }
+         if (same)
+           memcpy(dest, old_str, same);
+         memcpy(dest + same, pp, len);
+         pp += len;
+         old_str = dest;
+         dest += same + len;
+       }
+      solv_free(prefix);
+      if (freesp != 0)
+       {
+         repodata_freedata(&data);
+         return pool_error(pool, SOLV_ERROR_CORRUPT, "expanding strings size mismatch");
+       }
+    }
+  strsp[sizeid] = 0;                  /* make string space \0 terminated */
+  sp = strsp;
+
+  /* now merge */
+  str = spool->strings;                        /* array of offsets into strsp, indexed by Id */
+  if ((flags & REPO_LOCALPOOL) != 0)
+    {
+      /* no shared pool, thus no idmap and no unification needed */
+      idmap = 0;
+      spool->nstrings = numid < 2 ? 2 : numid; /* make sure we have at least id 0 and 1 */
+      if (*sp)
+       {
+         /* we need id 1 to be '' for directories */
+         repodata_freedata(&data);
+         return pool_error(pool, SOLV_ERROR_CORRUPT, "store strings don't start with an empty string");
+       }
+      for (i = 1; i < spool->nstrings; i++)
+       {
+         if (sp >= strsp + sizeid && numid >= 2)
+           {
+             repodata_freedata(&data);
+             return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings");
+           }
+         str[i] = sp - spool->stringspace;
+         sp += strlen(sp) + 1;
+       }
+      spool->sstrings = sp - spool->stringspace;
+    }
+  else
+    {
+      Offset oldsstrings = spool->sstrings;
+
+      /* alloc id map for name and rel Ids. this maps ids in the solv files
+       * to the ids in our pool */
+      idmap = solv_calloc(numid + numrel, sizeof(Id));
+      stringpool_resize_hash(spool, numid);
+      hashtbl = spool->stringhashtbl;
+      hashmask = spool->stringhashmask;
+#if 0
+      POOL_DEBUG(SOLV_DEBUG_STATS, "read %d strings\n", numid);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
+#endif
+      /*
+       * run over strings and merge with pool.
+       * we could use stringpool_str2id, but this is faster.
+       * also populate id map (maps solv Id -> pool Id)
+       */
+      for (i = 1; i < numid; i++)
+       {
+         if (sp >= strsp + sizeid)
+           {
+             solv_free(idmap);
+             spool->nstrings = oldnstrings;
+             spool->sstrings = oldsstrings;
+             stringpool_freehash(spool);
+             repodata_freedata(&data);
+             return pool_error(pool, SOLV_ERROR_OVERFLOW, "not enough strings %d %d", i, numid);
+           }
+         if (!*sp)                            /* empty string */
+           {
+             idmap[i] = ID_EMPTY;
+             sp++;
+             continue;
+           }
+
+         /* find hash slot */
+         h = strhash(sp) & hashmask;
+         hh = HASHCHAIN_START;
+         for (;;)
+           {
+             id = hashtbl[h];
+             if (!id)
+               break;
+             if (!strcmp(spool->stringspace + spool->strings[id], sp))
+               break;          /* already in pool */
+             h = HASHCHAIN_NEXT(h, hh, hashmask);
+           }
+
+         /* length == offset to next string */
+         l = strlen(sp) + 1;
+         if (!id)             /* end of hash chain -> new string */
+           {
+             id = spool->nstrings++;
+             hashtbl[h] = id;
+             str[id] = spool->sstrings;        /* save offset */
+             if (sp != spool->stringspace + spool->sstrings)
+               memmove(spool->stringspace + spool->sstrings, sp, l);
+             spool->sstrings += l;
+           }
+         idmap[i] = id;       /* repo relative -> pool relative */
+         sp += l;             /* next string */
+       }
+      stringpool_shrink(spool);                /* vacuum */
+    }
+
+
+  /*******  Part 2: Relation IDs  ***************************************/
+
+  /*
+   * read RelDeps
+   *
+   */
+
+  if (numrel)
+    {
+      /* extend rels */
+      pool->rels = solv_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep));
+      ran = pool->rels;
+
+      pool_resize_rels_hash(pool, numrel);
+      hashtbl = pool->relhashtbl;
+      hashmask = pool->relhashmask;
+#if 0
+      POOL_DEBUG(SOLV_DEBUG_STATS, "read %d rels\n", numrel);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
+#endif
+
+      /*
+       * read RelDeps from repo
+       */
+      for (i = 0; i < numrel; i++)
+       {
+         name = read_id(&data, i + numid);     /* read (repo relative) Ids */
+         evr = read_id(&data, i + numid);
+         relflags = read_u8(&data);
+         name = idmap[name];           /* map to (pool relative) Ids */
+         evr = idmap[evr];
+         h = relhash(name, evr, relflags) & hashmask;
+         hh = HASHCHAIN_START;
+         for (;;)
+           {
+             id = hashtbl[h];
+             if (!id)          /* end of hash chain reached */
+               break;
+             if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == relflags)
+               break;
+             h = HASHCHAIN_NEXT(h, hh, hashmask);
+           }
+         if (!id)              /* new RelDep */
+           {
+             id = pool->nrels++;
+             hashtbl[h] = id;
+             ran[id].name = name;
+             ran[id].evr = evr;
+             ran[id].flags = relflags;
+           }
+         idmap[i + numid] = MAKERELDEP(id);   /* fill Id map */
+       }
+      pool_shrink_rels(pool);          /* vacuum */
+    }
+
+  /* if we added ids/rels, make room in our whatprovide arrays */
+  if (!(flags & REPO_LOCALPOOL))
+    {
+      if (pool->whatprovides && oldnstrings != pool->ss.nstrings)
+       {
+         int newlen = (pool->ss.nstrings + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
+         pool->whatprovides = solv_realloc2(pool->whatprovides, newlen, sizeof(Offset));
+         memset(pool->whatprovides + oldnstrings, 0, (newlen - oldnstrings) * sizeof(Offset));
+       }
+      if (pool->whatprovides_rel && oldnrels != pool->nrels)
+       {
+         int newlen = (pool->nrels + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK;
+         pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, newlen, sizeof(Offset));
+         memset(pool->whatprovides_rel + oldnrels, 0, (newlen - oldnrels) * sizeof(Offset));
+       }
+    }
+
+  /*******  Part 3: Dirs  ***********************************************/
+  if (numdir)
+    {
+      data.dirpool.dirs = solv_malloc2(numdir, sizeof(Id));
+      data.dirpool.ndirs = numdir;
+      data.dirpool.dirs[0] = 0;                /* dir 0: virtual root */
+      data.dirpool.dirs[1] = 1;                /* dir 1: / */
+      for (i = 2; i < numdir; i++)
+       {
+         id = read_id(&data, i + numid);
+         if (id >= numid)
+           {
+             data.dirpool.dirs[i++] = -(id - numid);
+             if (i >= numdir)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "last dir entry is not a component");
+                 break;
+               }
+             id = read_id(&data, numid);
+           }
+         if (idmap)
+           id = idmap[id];
+         data.dirpool.dirs[i] = id;
+         if (id <= 0)
+            data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "bad dir component");
+       }
+    }
+
+  /*******  Part 4: Keys  ***********************************************/
+
+  keys = solv_calloc(numkeys, sizeof(*keys));
+  /* keys start at 1 */
+  for (i = 1; i < numkeys; i++)
+    {
+      id = read_id(&data, numid);
+      if (idmap)
+       id = idmap[id];
+      else if ((flags & REPO_LOCALPOOL) != 0)
+        id = pool_str2id(pool, stringpool_id2str(spool, id), 1);
+      type = read_id(&data, numid);
+      if (idmap)
+       type = idmap[type];
+      else if ((flags & REPO_LOCALPOOL) != 0)
+        type = pool_str2id(pool, stringpool_id2str(spool, type), 1);
+      if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_DELETED)
+       {
+         data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
+         type = REPOKEY_TYPE_VOID;
+       }
+      keys[i].name = id;
+      keys[i].type = type;
+      keys[i].size = read_id(&data, keys[i].type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
+      keys[i].storage = read_id(&data, 0);
+      /* old versions used SOLVABLE for main solvable data */
+      if (keys[i].storage == KEY_STORAGE_SOLVABLE)
+       keys[i].storage = KEY_STORAGE_INCORE;
+      if (keys[i].storage != KEY_STORAGE_INCORE && keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", keys[i].storage);
+      if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
+       {
+         if (keys[i].storage != KEY_STORAGE_INCORE)
+           data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage %d", keys[i].storage);
+         keys[i].storage = KEY_STORAGE_SOLVABLE;
+       }
+      if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && keys[i].storage != KEY_STORAGE_INCORE)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n");
+      /* cannot handle rel idarrays in incore/vertical */
+      if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_SOLVABLE");
+      /* cannot handle mapped ids in vertical */
+      if (!(flags & REPO_LOCALPOOL) && keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "mapped ids are not supported for STORAGE_VERTICAL_OFFSET");
+
+      if (keys[i].type == REPOKEY_TYPE_CONSTANTID && idmap)
+       keys[i].size = idmap[keys[i].size];
+#if 0
+      fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool,id), pool_id2str(pool, keys[i].type),
+               keys[i].size, keys[i].storage);
+#endif
+    }
+
+  have_incoredata = 0;
+  for (i = 1; i < numkeys; i++)
+    if (keys[i].storage == KEY_STORAGE_INCORE || keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
+      have_incoredata = 1;
+
+  data.keys = keys;
+  data.nkeys = numkeys;
+  for (i = 1; i < numkeys; i++)
+    {
+      id = keys[i].name;
+      data.keybits[(id >> 3) & (sizeof(data.keybits) - 1)] |= 1 << (id & 7);
+    }
+
+  /*******  Part 5: Schemata ********************************************/
+
+  id = read_id(&data, 0);
+  schemadata = solv_calloc(id + 1, sizeof(Id));
+  schemadatap = schemadata + 1;
+  schemadataend = schemadatap + id;
+  schemata = solv_calloc(numschemata, sizeof(Id));
+  for (i = 1; i < numschemata; i++)
+    {
+      schemata[i] = schemadatap - schemadata;
+      schemadatap = read_idarray(&data, numid, 0, schemadatap, schemadataend);
+#if 0
+      Id *sp = schemadata + schemata[i];
+      fprintf(stderr, "schema %d:", i);
+      for (; *sp; sp++)
+        fprintf(stderr, " %d", *sp);
+      fprintf(stderr, "\n");
+#endif
+    }
+  data.schemata = schemata;
+  data.nschemata = numschemata;
+  data.schemadata = schemadata;
+  data.schemadatalen = schemadataend - data.schemadata;
+
+  /*******  Part 6: Data ********************************************/
+
+  idarraydatap = idarraydataend = 0;
+  size_idarray = 0;
+
+  maxsize = read_id(&data, 0);
+  allsize = read_id(&data, 0);
+  maxsize += 5;        /* so we can read the next schema of an array */
+  if (maxsize > allsize)
+    maxsize = allsize;
+
+  buf = solv_calloc(maxsize + DATA_READ_CHUNK + 4, 1); /* 4 extra bytes to detect overflows */
+  bufend = buf;
+  dp = buf;
+
+  l = maxsize;
+  if (l < DATA_READ_CHUNK)
+    l = DATA_READ_CHUNK;
+  if (l > allsize)
+    l = allsize;
+  if (!l || fread(buf, l, 1, data.fp) != 1)
+    {
+      data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
+      id = 0;
+    }
+  else
+    {
+      bufend = buf + l;
+      allsize -= l;
+      dp = data_read_id_max(dp, &id, 0, numschemata, &data);
+    }
+
+  incore_add_id(&data, 0);     /* so that incoreoffset 0 means schema 0 */
+  incore_add_id(&data, id);    /* main schema id */
+  keyp = schemadata + schemata[id];
+  data.mainschema = id;
+  for (i = 0; keyp[i]; i++)
+    ;
+  if (i)
+    data.mainschemaoffsets = solv_calloc(i, sizeof(Id));
+
+  nentries = 0;
+  keydepth = 0;
+  s = 0;
+  needchunk = 1;
+  for(;;)
+    {
+      /* make sure we have enough room */
+      if (keydepth == 0 || needchunk)
+       {
+         int left = bufend - dp;
+         /* read data chunk to dp */
+         if (data.error)
+           break;
+         if (left < 0)
+           {
+              data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
+             break;
+           }
+         if (left < maxsize)
+           {
+             if (left)
+               memmove(buf, dp, left);
+             l = maxsize - left;
+             if (l < DATA_READ_CHUNK)
+               l = DATA_READ_CHUNK;
+             if (l > allsize)
+               l = allsize;
+             if (l && fread(buf + left, l, 1, data.fp) != 1)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
+                 break;
+               }
+             allsize -= l;
+             left += l;
+             bufend = buf + left;
+             if (allsize + left < maxsize)
+               maxsize = allsize + left;
+             dp = buf;
+           }
+         needchunk = 0;
+       }
+
+      key = *keyp++;
+#if 0
+printf("key %d at %d\n", key, (int)(keyp - 1 - schemadata));
+#endif
+      if (!key)
+       {
+         if (keydepth <= 3)
+           needchunk = 1;
+         if (nentries)
+           {
+             if (s && keydepth == 3)
+               {
+                 s++;  /* next solvable */
+                 if (have_incoredata)
+                   data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
+               }
+             id = stack[keydepth - 1];
+             if (!id)
+               {
+                 dp = data_read_id_max(dp, &id, 0, numschemata, &data);
+                 incore_add_id(&data, id);
+               }
+             keyp = schemadata + schemata[id];
+             nentries--;
+             continue;
+           }
+         if (!keydepth)
+           break;
+         --keydepth;
+         keyp = schemadata + stack[--keydepth];
+         nentries = stack[--keydepth];
+#if 0
+printf("pop flexarray %d %d\n", keydepth, nentries);
+#endif
+         if (!keydepth && s)
+           s = 0;      /* back from solvables */
+         continue;
+       }
+
+      if (keydepth == 0)
+       data.mainschemaoffsets[keyp - 1 - (schemadata + schemata[data.mainschema])] = data.incoredatalen;
+
+#if 0
+printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, keys[key].type), s);
+#endif
+      id = keys[key].name;
+      if (keys[key].storage == KEY_STORAGE_VERTICAL_OFFSET)
+       {
+         dps = dp;
+         dp = data_skip(dp, REPOKEY_TYPE_ID);
+         dp = data_skip(dp, REPOKEY_TYPE_ID);
+         incore_add_blob(&data, dps, dp - dps);        /* just record offset/size */
+         continue;
+       }
+      switch (keys[key].type)
+       {
+       case REPOKEY_TYPE_ID:
+         dp = data_read_id_max(dp, &did, idmap, numid + numrel, &data);
+         if (s && id == SOLVABLE_NAME)
+           s->name = did;
+         else if (s && id == SOLVABLE_ARCH)
+           s->arch = did;
+         else if (s && id == SOLVABLE_EVR)
+           s->evr = did;
+         else if (s && id == SOLVABLE_VENDOR)
+           s->vendor = did;
+         else if (keys[key].storage == KEY_STORAGE_INCORE)
+           incore_add_id(&data, did);
+#if 0
+         POOL_DEBUG(SOLV_DEBUG_STATS, "%s -> %s\n", pool_id2str(pool, id), pool_id2str(pool, did));
+#endif
+         break;
+       case REPOKEY_TYPE_IDARRAY:
+       case REPOKEY_TYPE_REL_IDARRAY:
+         if (!s || id < INTERESTED_START || id > INTERESTED_END)
+           {
+             dps = dp;
+             dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
+             if (keys[key].storage != KEY_STORAGE_INCORE)
+               break;
+             if (idmap)
+               incore_map_idarray(&data, dps, idmap, numid + numrel);
+             else
+               incore_add_blob(&data, dps, dp - dps);
+             break;
+           }
+         ido = idarraydatap - repo->idarraydata;
+         if (keys[key].type == REPOKEY_TYPE_IDARRAY)
+           dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
+         else if (id == SOLVABLE_REQUIRES)
+           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_PREREQMARKER);
+         else if (id == SOLVABLE_PROVIDES)
+           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_FILEMARKER);
+         else
+           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, 0);
+         if (idarraydatap > idarraydataend)
+           {
+             data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
+             break;
+           }
+         if (id == SOLVABLE_PROVIDES)
+           s->provides = ido;
+         else if (id == SOLVABLE_OBSOLETES)
+           s->obsoletes = ido;
+         else if (id == SOLVABLE_CONFLICTS)
+           s->conflicts = ido;
+         else if (id == SOLVABLE_REQUIRES)
+           s->requires = ido;
+         else if (id == SOLVABLE_RECOMMENDS)
+           s->recommends= ido;
+         else if (id == SOLVABLE_SUPPLEMENTS)
+           s->supplements = ido;
+         else if (id == SOLVABLE_SUGGESTS)
+           s->suggests = ido;
+         else if (id == SOLVABLE_ENHANCES)
+           s->enhances = ido;
+#if 0
+         POOL_DEBUG(SOLV_DEBUG_STATS, "%s ->\n", pool_id2str(pool, id));
+         for (; repo->idarraydata[ido]; ido++)
+           POOL_DEBUG(SOLV_DEBUG_STATS,"  %s\n", pool_dep2str(pool, repo->idarraydata[ido]));
+#endif
+         break;
+       case REPOKEY_TYPE_FIXARRAY:
+       case REPOKEY_TYPE_FLEXARRAY:
+         if (!keydepth)
+           needchunk = 1;
+          if (keydepth == sizeof(stack)/sizeof(*stack))
+           {
+             data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "array stack overflow");
+             break;
+           }
+         stack[keydepth++] = nentries;
+         stack[keydepth++] = keyp - schemadata;
+         stack[keydepth++] = 0;
+         dp = data_read_id_max(dp, &nentries, 0, 0, &data);
+         incore_add_id(&data, nentries);
+         if (!nentries)
+           {
+             /* zero size array? */
+             keydepth -= 2;
+             nentries = stack[--keydepth];
+             break;
+           }
+         if (keydepth == 3 && id == REPOSITORY_SOLVABLES)
+           {
+             /* horray! here come the solvables */
+             if (nentries != numsolv)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "inconsistent number of solvables: %d %d", nentries, numsolv);
+                 break;
+               }
+             if (idarraydatap)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "more than one solvable block");
+                 break;
+               }
+             if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+               s = pool_id2solvable(pool, extendstart);
+             else
+               s = pool_id2solvable(pool, repo_add_solvable_block(repo, numsolv));
+             data.start = s - pool->solvables;
+             data.end = data.start + numsolv;
+             repodata_extend_block(&data, data.start, numsolv);
+             for (i = 1; i < numkeys; i++)
+               {
+                 id = keys[i].name;
+                 if ((keys[i].type == REPOKEY_TYPE_IDARRAY || keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
+                     && id >= INTERESTED_START && id <= INTERESTED_END)
+                   size_idarray += keys[i].size;
+               }
+             /* allocate needed space in repo */
+             /* we add maxsize because it is an upper limit for all idarrays, thus we can't overflow */
+             repo_reserve_ids(repo, 0, size_idarray + maxsize + 1);
+             idarraydatap = repo->idarraydata + repo->idarraysize;
+             repo->idarraysize += size_idarray;
+             idarraydataend = idarraydatap + size_idarray;
+             repo->lastoff = 0;
+             if (have_incoredata)
+               data.incoreoffset[(s - pool->solvables) - data.start] = data.incoredatalen;
+           }
+         nentries--;
+         dp = data_read_id_max(dp, &id, 0, numschemata, &data);
+         incore_add_id(&data, id);
+         if (keys[key].type == REPOKEY_TYPE_FIXARRAY)
+           {
+             if (!id)
+               data.error = pool_error(pool, SOLV_ERROR_CORRUPT, "illegal fixarray");
+             stack[keydepth - 1] = id;
+           }
+         keyp = schemadata + schemata[id];
+         break;
+       case REPOKEY_TYPE_NUM:
+         if (!(solvflags & SOLV_FLAG_SIZE_BYTES) && keys[key].storage == KEY_STORAGE_INCORE &&
+               (id == SOLVABLE_INSTALLSIZE || id == SOLVABLE_DOWNLOADSIZE || id == DELTA_DOWNLOADSIZE))
+           {
+             /* old solv file with sizes in kilos. transcode. */
+             dp = data_read_id(dp, &id);
+             incore_add_sizek(&data, (unsigned int)id);
+             break;
+           }
+         /* FALLTHROUGH */
+       default:
+         if (id == RPM_RPMDBID && s && keys[key].type == REPOKEY_TYPE_NUM)
+           {
+             dp = data_read_id_max(dp, &id, 0, 0, &data);
+             if (!repo->rpmdbid)
+               repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
+             repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
+             break;
+           }
+         dps = dp;
+         dp = data_skip(dp, keys[key].type);
+         if (keys[key].storage == KEY_STORAGE_INCORE)
+           incore_add_blob(&data, dps, dp - dps);
+         break;
+       }
+    }
+  /* should shrink idarraydata again */
+
+  if (keydepth)
+    data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF, depth = %d", keydepth);
+  if (!data.error)
+    {
+      if (dp > bufend)
+       data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
+    }
+  solv_free(buf);
+
+  if (data.error)
+    {
+      /* free solvables */
+      repo_free_solvable_block(repo, data.start, data.end - data.start, 1);
+      /* free id array */
+      repo->idarraysize -= size_idarray;
+      /* free incore data */
+      data.incoredata = solv_free(data.incoredata);
+      data.incoredatalen = data.incoredatafree = 0;
+    }
+
+  if (data.incoredatafree)
+    {
+      /* shrink excess size */
+      data.incoredata = solv_realloc(data.incoredata, data.incoredatalen);
+      data.incoredatafree = 0;
+    }
+  solv_free(idmap);
+
+  /* fixup the special idarray type */
+  for (i = 1; i < numkeys; i++)
+    if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
+      keys[i].type = REPOKEY_TYPE_IDARRAY;
+
+  for (i = 1; i < numkeys; i++)
+    if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size)
+      break;
+  if (i < numkeys && !data.error)
+    {
+      Id fileoffset = 0;
+      unsigned int pagesize;
+
+      /* we have vertical data, make it available */
+      data.verticaloffset = solv_calloc(numkeys, sizeof(Id));
+      for (i = 1; i < numkeys; i++)
+        if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
+         {
+           data.verticaloffset[i] = fileoffset;
+           fileoffset += keys[i].size;
+         }
+      data.lastverticaloffset = fileoffset;
+      pagesize = read_u32(&data);
+      if (!data.error)
+       {
+         data.error = repopagestore_read_or_setup_pages(&data.store, data.fp, pagesize, fileoffset);
+         if (data.error == SOLV_ERROR_EOF)
+           pool_error(pool, data.error, "repopagestore setup: unexpected EOF");
+         else if (data.error)
+           pool_error(pool, data.error, "repopagestore setup failed");
+       }
+    }
+  data.fp = 0; /* no longer needed */
+
+  if (data.error)
+    {
+      i = data.error;
+      repodata_freedata(&data);
+      return i;
+    }
+
+  if (parent)
+    {
+      /* overwrite stub repodata */
+      repodata_freedata(parent);
+      data.repodataid = parent->repodataid;
+      data.loadcallback = parent->loadcallback;
+      *parent = data;
+    }
+  else
+    {
+      /* make it available as new repodata */
+      if (!repo->nrepodata)
+       {
+         repo->nrepodata = 1;
+         repo->repodata = solv_calloc(2, sizeof(data));
+       }
+      else
+        repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata + 1, sizeof(data));
+      data.repodataid = repo->nrepodata;
+      repo->repodata[repo->nrepodata++] = data;
+    }
+
+  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {
+      if (repodata_has_keyname(&data, SOLVABLE_FILELIST))
+       repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_EXTENSION);
+    }
+  else
+    {
+      if (repodata_lookup_type(&data, SOLVID_META, REPOSITORY_FILTEREDFILELIST))
+        repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_FILTERED);
+    }
+
+  /* create stub repodata entries for all external */
+  if (!(flags & SOLV_ADD_NO_STUBS) && !parent)
+    {
+      for (key = 1 ; key < data.nkeys; key++)
+       if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY)
+         break;
+      if (key < data.nkeys)
+       repodata_create_stubs(repo->repodata + data.repodataid);
+    }
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_solv took %d ms\n", solv_timems(now));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data.incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id)));
+  return 0;
+}
+
diff --git a/libsolv-0.7.2/src/repo_solv.h b/libsolv-0.7.2/src/repo_solv.h
new file mode 100644 (file)
index 0000000..0c66394
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_solv.h
+ *
+ */
+
+#ifndef LIBSOLV_REPO_SOLVE_H
+#define LIBSOLV_REPO_SOLVE_H
+
+#include <stdio.h>
+
+#include "pool.h"
+#include "repo.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int repo_add_solv(Repo *repo, FILE *fp, int flags);
+
+#define SOLV_ADD_NO_STUBS      (1 << 8)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_REPO_SOLVE_H */
diff --git a/libsolv-0.7.2/src/repo_write.c b/libsolv-0.7.2/src/repo_write.c
new file mode 100644 (file)
index 0000000..d3b8a83
--- /dev/null
@@ -0,0 +1,2149 @@
+/*
+ * Copyright (c) 2007-2011, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_write.c
+ *
+ * Write Repo data out to a file in solv format
+ *
+ * See doc/README.format for a description
+ * of the binary file format
+ *
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "util.h"
+#include "repo_write.h"
+#include "repopage.h"
+
+/*------------------------------------------------------------------*/
+/* Id map optimizations */
+
+typedef struct needid {
+  Id need;
+  Id map;
+} NeedId;
+
+
+#define NEEDIDOFF(id) (ISRELDEP(id) ? (needid[0].map + GETRELID(id)) : id)
+
+/*
+ * increment need Id
+ * idarray: array of Ids, ID_NULL terminated
+ * needid: array of Id->NeedId
+ *
+ * return size of array (including trailing zero)
+ *
+ */
+
+static inline void
+incneedid(Id id, NeedId *needid)
+{
+  needid[NEEDIDOFF(id)].need++;
+}
+
+static int
+incneedidarray(Id *idarray, NeedId *needid)
+{
+  Id id;
+  int n = 0;
+
+  while ((id = *idarray++) != 0)
+    {
+      n++;
+      needid[NEEDIDOFF(id)].need++;
+    }
+  return n + 1;
+}
+
+
+/*
+ *
+ */
+
+static int
+needid_cmp_need(const void *ap, const void *bp, void *dp)
+{
+  const NeedId *a = ap;
+  const NeedId *b = bp;
+  int r;
+  r = b->need - a->need;
+  if (r)
+    return r;
+  return a->map - b->map;
+}
+
+static int
+needid_cmp_need_s(const void *ap, const void *bp, void *dp)
+{
+  const NeedId *a = ap;
+  const NeedId *b = bp;
+  Stringpool *spool = dp;
+  const char *as;
+  const char *bs;
+
+  int r;
+  r = b->need - a->need;
+  if (r)
+    return r;
+  as = spool->stringspace + spool->strings[a->map];
+  bs = spool->stringspace + spool->strings[b->map];
+  return strcmp(as, bs);
+}
+
+
+/*------------------------------------------------------------------*/
+/* output helper routines, used for writing the header */
+/* (the data itself is accumulated in memory and written with
+ * write_blob) */
+
+/*
+ * unsigned 32-bit
+ */
+
+static void
+write_u32(Repodata *data, unsigned int x)
+{
+  FILE *fp = data->fp;
+  if (data->error)
+    return;
+  if (putc(x >> 24, fp) == EOF ||
+      putc(x >> 16, fp) == EOF ||
+      putc(x >> 8, fp) == EOF ||
+      putc(x, fp) == EOF)
+    {
+      data->error = pool_error(data->repo->pool, -1, "write error u32: %s", strerror(errno));
+    }
+}
+
+
+/*
+ * unsigned 8-bit
+ */
+
+static void
+write_u8(Repodata *data, unsigned int x)
+{
+  if (data->error)
+    return;
+  if (putc(x, data->fp) == EOF)
+    {
+      data->error = pool_error(data->repo->pool, -1, "write error u8: %s", strerror(errno));
+    }
+}
+
+/*
+ * data blob
+ */
+
+static void
+write_blob(Repodata *data, void *blob, int len)
+{
+  if (data->error)
+    return;
+  if (len && fwrite(blob, len, 1, data->fp) != 1)
+    {
+      data->error = pool_error(data->repo->pool, -1, "write error blob: %s", strerror(errno));
+    }
+}
+
+/*
+ * Id
+ */
+
+static void
+write_id(Repodata *data, Id x)
+{
+  FILE *fp = data->fp;
+  if (data->error)
+    return;
+  if (x >= (1 << 14))
+    {
+      if (x >= (1 << 28))
+       putc((x >> 28) | 128, fp);
+      if (x >= (1 << 21))
+       putc((x >> 21) | 128, fp);
+      putc((x >> 14) | 128, fp);
+    }
+  if (x >= (1 << 7))
+    putc((x >> 7) | 128, fp);
+  if (putc(x & 127, fp) == EOF)
+    {
+      data->error = pool_error(data->repo->pool, -1, "write error id: %s", strerror(errno));
+    }
+}
+
+static inline void
+write_id_eof(Repodata *data, Id x, int eof)
+{
+  if (x >= 64)
+    x = (x & 63) | ((x & ~63) << 1);
+  write_id(data, x | (eof ? 0 : 64));
+}
+
+
+
+static inline void
+write_str(Repodata *data, const char *str)
+{
+  if (data->error)
+    return;
+  if (fputs(str, data->fp) == EOF || putc(0, data->fp) == EOF)
+    {
+      data->error = pool_error(data->repo->pool, -1, "write error str: %s", strerror(errno));
+    }
+}
+
+/*
+ * Array of Ids
+ */
+
+static void
+write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids)
+{
+  Id id;
+  if (!ids)
+    return;
+  if (!*ids)
+    {
+      write_u8(data, 0);
+      return;
+    }
+  for (;;)
+    {
+      id = *ids++;
+      if (needid)
+        id = needid[NEEDIDOFF(id)].need;
+      if (id >= 64)
+       id = (id & 63) | ((id & ~63) << 1);
+      if (!*ids)
+       {
+         write_id(data, id);
+         return;
+       }
+      write_id(data, id | 64);
+    }
+}
+
+struct extdata {
+  unsigned char *buf;
+  int len;
+};
+
+struct cbdata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *target;
+
+  Stringpool *ownspool;
+  Dirpool *owndirpool;
+  int clonepool;       /* are the pool ids cloned into ownspool? */
+
+  Id *keymap;          /* keymap for this repodata */
+
+  NeedId *needid;
+
+  Id *schema;          /* schema construction space */
+  Id *sp;              /* pointer in above */
+
+  Id *subschemata;
+  int nsubschemata;
+  int current_sub;
+
+  struct extdata *extdata;
+
+  Id *dirused;
+
+  Id vstart;           /* offset of key in vertical data */
+
+  Id maxdata;
+  Id lastlen;
+
+  int doingsolvables;  /* working on solvables data */
+  int filelistmode;
+
+  Id lastdirid;                /* last dir id seen in this repodata */
+  Id lastdirid_own;    /* last dir id put in own pool */
+};
+
+#define NEEDID_BLOCK 1023
+#define SCHEMATA_BLOCK 31
+#define EXTDATA_BLOCK 4095
+
+static inline void
+data_addid(struct extdata *xd, Id sx)
+{
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+
+  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
+  dp = xd->buf + xd->len;
+
+  if (x >= (1 << 14))
+    {
+      if (x >= (1 << 28))
+       *dp++ = (x >> 28) | 128;
+      if (x >= (1 << 21))
+       *dp++ = (x >> 21) | 128;
+      *dp++ = (x >> 14) | 128;
+    }
+  if (x >= (1 << 7))
+    *dp++ = (x >> 7) | 128;
+  *dp++ = x & 127;
+  xd->len = dp - xd->buf;
+}
+
+static inline void
+data_addideof(struct extdata *xd, Id sx, int eof)
+{
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+
+  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
+  dp = xd->buf + xd->len;
+
+  if (x >= (1 << 13))
+    {
+      if (x >= (1 << 27))
+        *dp++ = (x >> 27) | 128;
+      if (x >= (1 << 20))
+        *dp++ = (x >> 20) | 128;
+      *dp++ = (x >> 13) | 128;
+    }
+  if (x >= (1 << 6))
+    *dp++ = (x >> 6) | 128;
+  *dp++ = eof ? (x & 63) : (x & 63) | 64;
+  xd->len = dp - xd->buf;
+}
+
+static inline int
+data_addideof_len(Id sx)
+{
+  unsigned int x = (unsigned int)sx;
+  if (x >= (1 << 13))
+    {
+      if (x >= (1 << 27))
+       return 5;
+      return x >= (1 << 20) ? 4 : 3;
+    }
+  return x >= (1 << 6) ? 2 : 1;
+}
+
+static void
+data_addid64(struct extdata *xd, unsigned int x, unsigned int hx)
+{
+  if (hx)
+    {
+      if (hx > 7)
+        {
+          data_addid(xd, (Id)(hx >> 3));
+          xd->buf[xd->len - 1] |= 128;
+         hx &= 7;
+        }
+      data_addid(xd, (Id)(x | 0x80000000));
+      xd->buf[xd->len - 5] = (x >> 28) | (hx << 4) | 128;
+    }
+  else
+    data_addid(xd, (Id)x);
+}
+
+#define USE_REL_IDARRAY
+#ifdef USE_REL_IDARRAY
+
+static int
+cmp_ids(const void *pa, const void *pb, void *dp)
+{
+  Id a = *(Id *)pa;
+  Id b = *(Id *)pb;
+  return a - b;
+}
+
+static void
+data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
+{
+  int len, i;
+  Id lids[64], *sids;
+  Id id, old;
+
+  if (!ids)
+    return;
+  if (!*ids)
+    {
+      data_addid(xd, 0);
+      return;
+    }
+  for (len = 0; len < 64 && ids[len]; len++)
+    {
+      Id id = ids[len];
+      if (needid)
+        id = needid[NEEDIDOFF(id)].need;
+      lids[len] = id;
+    }
+  if (ids[len])
+    {
+      for (i = len + 1; ids[i]; i++)
+       ;
+      sids = solv_malloc2(i, sizeof(Id));
+      memcpy(sids, lids, 64 * sizeof(Id));
+      for (; ids[len]; len++)
+       {
+         Id id = ids[len];
+         if (needid)
+            id = needid[NEEDIDOFF(id)].need;
+         sids[len] = id;
+       }
+    }
+  else
+    sids = lids;
+
+  /* That bloody solvable:prereqmarker needs to stay in position :-(  */
+  if (needid)
+    marker = needid[marker].need;
+  for (i = 0; i < len; i++)
+    if (sids[i] == marker)
+      break;
+  if (i > 1)
+    solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
+  if ((len - i) > 2)
+    solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
+
+  old = 0;
+
+  /* The differencing above produces many runs of ones and twos.  I tried
+     fairly elaborate schemes to RLE those, but they give only very mediocre
+     improvements in compression, as coding the escapes costs quite some
+     space.  Even if they are coded only as bits in IDs.  The best improvement
+     was about 2.7% for the whole .solv file.  It's probably better to
+     invest some complexity into sharing idarrays, than RLEing.  */
+  for (i = 0; i < len - 1; i++)
+    {
+      id = sids[i];
+    /* Ugly PREREQ handling.  A "difference" of 0 is the prereq marker,
+       hence all real differences are offsetted by 1.  Otherwise we would
+       have to handle negative differences, which would cost code space for
+       the encoding of the sign.  We loose the exact mapping of prereq here,
+       but we know the result, so we can recover from that in the reader.  */
+      if (id == marker)
+       id = old = 0;
+      else
+       {
+          id = id - old + 1;
+         old = sids[i];
+       }
+      /* XXX If difference is zero we have multiple equal elements,
+        we might want to skip writing them out.  */
+      data_addideof(xd, id, 0);
+    }
+  id = sids[i];
+  if (id == marker)
+    id = 0;
+  else
+    id = id - old + 1;
+  data_addideof(xd, id, 1);
+  if (sids != lids)
+    solv_free(sids);
+}
+
+#else
+
+static void
+data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
+{
+  Id id;
+  if (!ids || !*ids)
+    {
+      data_addid(xd, 0);
+      return;
+    }
+  while ((id = *ids++) != 0)
+    {
+      if (needid)
+        id = needid[NEEDIDOFF(id)].need;
+      data_addideof(xd, id, *ids ? 0 : 1);
+    }
+}
+
+#endif
+
+static inline void
+data_addblob(struct extdata *xd, unsigned char *blob, int len)
+{
+  xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
+  memcpy(xd->buf + xd->len, blob, len);
+  xd->len += len;
+}
+
+/* grow needid array so that it contains the specified id */
+static void
+grow_needid(struct cbdata *cbdata, Id id)
+{
+  int oldoff = cbdata->needid[0].map;
+  int newoff = (id + 1 + NEEDID_BLOCK) & ~NEEDID_BLOCK;
+  int nrels = cbdata->pool->nrels;
+  cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
+  if (nrels)
+    memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
+  memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
+  cbdata->needid[0].map = newoff;
+}
+
+static Id
+putinownpool(struct cbdata *cbdata, Repodata *data, Id id)
+{
+  Stringpool *ss = data->localpool ? &data->spool : &cbdata->pool->ss;
+  const char *str = stringpool_id2str(ss, id);
+  id = stringpool_str2id(cbdata->ownspool, str, 1);
+  if (id >= cbdata->needid[0].map)
+    grow_needid(cbdata, id);
+  return id;
+}
+
+static Id
+putinowndirpool_slow(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
+{
+  Id compid, parent;
+
+  parent = dirpool_parent(dp, dir);
+  if (parent)
+    parent = putinowndirpool_slow(cbdata, data, dp, parent);
+  compid = dirpool_compid(dp, dir);
+  if (cbdata->ownspool && compid > 1 && (!cbdata->clonepool || data->localpool))
+    compid = putinownpool(cbdata, data, compid);
+  return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
+}
+
+static inline Id
+putinowndirpool(struct cbdata *cbdata, Repodata *data, Id dir)
+{
+  if (dir && dir == cbdata->lastdirid)
+    return cbdata->lastdirid_own;
+  cbdata->lastdirid = dir;
+  cbdata->lastdirid_own = putinowndirpool_slow(cbdata, data, &data->dirpool, dir);
+  return cbdata->lastdirid_own;
+}
+
+/*
+ * pass 1 callback:
+ * collect key/id/dirid usage information, create needed schemas
+ */
+static int
+collect_needed_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  struct cbdata *cbdata = vcbdata;
+  Id id;
+  int rm;
+
+#if 0
+    fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? (int)(s - cbdata->pool->solvables) : 0, s ? pool_id2str(cbdata->pool, s->name) : "", key->name, pool_id2str(cbdata->pool, key->name), key->type);
+#endif
+  if (key->name == REPOSITORY_SOLVABLES)
+    return SEARCH_NEXT_KEY;    /* we do not want this one */
+
+  rm = cbdata->keymap[key - data->keys];
+  if (!rm)
+    return SEARCH_NEXT_KEY;    /* we do not want this one */
+
+  /* record key in schema */
+  if (cbdata->sp[-1] != rm)
+    *cbdata->sp++ = rm;
+
+  switch(key->type)
+    {
+      case REPOKEY_TYPE_ID:
+      case REPOKEY_TYPE_IDARRAY:
+       id = kv->id;
+       if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool))
+         id = putinownpool(cbdata, data, id);
+       incneedid(id, cbdata->needid);
+       break;
+      case REPOKEY_TYPE_DIR:
+      case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      case REPOKEY_TYPE_DIRSTRARRAY:
+       id = kv->id;
+       if (cbdata->owndirpool)
+         putinowndirpool(cbdata, data, id);
+       else
+         cbdata->dirused[id] = 1;
+       break;
+      case REPOKEY_TYPE_FIXARRAY:
+      case REPOKEY_TYPE_FLEXARRAY:
+       if (kv->entry == 0)
+         {
+           if (kv->eof != 2)
+             *cbdata->sp++ = 0;        /* mark start */
+         }
+       else
+         {
+           /* just finished a schema, rewind to start */
+           Id *sp = cbdata->sp - 1;
+           *sp = 0;
+           while (sp[-1])
+             sp--;
+           if (kv->entry == 1 || key->type == REPOKEY_TYPE_FLEXARRAY)
+             {
+               cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
+               cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
+             }
+           cbdata->sp = kv->eof == 2 ? sp - 1: sp;
+         }
+       break;
+      default:
+       break;
+    }
+  return 0;
+}
+
+static void
+collect_needed_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap)
+{
+  /* set schema info, keep in sync with collect_data_solvable */
+  Repo *repo = s->repo;
+  Id *sp = cbdata->sp;
+  NeedId *needid = cbdata->needid;
+  Repodata *target = cbdata->target;
+  Id *idarraydata = repo->idarraydata;
+
+  if (keymap[SOLVABLE_NAME])
+    {
+      *sp++ = keymap[SOLVABLE_NAME];
+      needid[s->name].need++;
+    }
+  if (keymap[SOLVABLE_ARCH])
+    {
+      *sp++ = keymap[SOLVABLE_ARCH];
+      needid[s->arch].need++;
+    }
+  if (keymap[SOLVABLE_EVR])
+    {
+      *sp++ = keymap[SOLVABLE_EVR];
+      needid[s->evr].need++;
+    }
+  if (s->vendor && keymap[SOLVABLE_VENDOR])
+    {
+      *sp++ = keymap[SOLVABLE_VENDOR];
+      needid[s->vendor].need++;
+    }
+  if (s->provides && keymap[SOLVABLE_PROVIDES])
+    {
+      *sp++ = keymap[SOLVABLE_PROVIDES];
+      target->keys[keymap[SOLVABLE_PROVIDES]].size += incneedidarray(idarraydata + s->provides, needid);
+    }
+  if (s->obsoletes && keymap[SOLVABLE_OBSOLETES])
+    {
+      *sp++ = keymap[SOLVABLE_OBSOLETES];
+      target->keys[keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(idarraydata + s->obsoletes, needid);
+    }
+  if (s->conflicts && keymap[SOLVABLE_CONFLICTS])
+    {
+      *sp++ = keymap[SOLVABLE_CONFLICTS];
+      target->keys[keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(idarraydata + s->conflicts, needid);
+    }
+  if (s->requires && keymap[SOLVABLE_REQUIRES])
+    {
+      *sp++ = keymap[SOLVABLE_REQUIRES];
+      target->keys[keymap[SOLVABLE_REQUIRES]].size += incneedidarray(idarraydata + s->requires, needid);
+    }
+  if (s->recommends && keymap[SOLVABLE_RECOMMENDS])
+    {
+      *sp++ = keymap[SOLVABLE_RECOMMENDS];
+      target->keys[keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(idarraydata + s->recommends, needid);
+    }
+  if (s->suggests && keymap[SOLVABLE_SUGGESTS])
+    {
+      *sp++ = keymap[SOLVABLE_SUGGESTS];
+      target->keys[keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(idarraydata + s->suggests, needid);
+    }
+  if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS])
+    {
+      *sp++ = keymap[SOLVABLE_SUPPLEMENTS];
+      target->keys[keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(idarraydata + s->supplements, needid);
+    }
+  if (s->enhances && keymap[SOLVABLE_ENHANCES])
+    {
+      *sp++ = keymap[SOLVABLE_ENHANCES];
+      target->keys[keymap[SOLVABLE_ENHANCES]].size += incneedidarray(idarraydata + s->enhances, needid);
+    }
+  if (repo->rpmdbid && keymap[RPM_RPMDBID])
+    {
+      *sp++ = keymap[RPM_RPMDBID];
+      target->keys[keymap[RPM_RPMDBID]].size++;
+    }
+  cbdata->sp = sp;
+}
+
+
+/*
+ * pass 2 callback:
+ * encode all of the data into the correct buffers
+ */
+static int
+collect_data_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  struct cbdata *cbdata = vcbdata;
+  int rm;
+  Id id, storage;
+  struct extdata *xd;
+  NeedId *needid;
+
+  if (key->name == REPOSITORY_SOLVABLES)
+    return SEARCH_NEXT_KEY;
+
+  rm = cbdata->keymap[key - data->keys];
+  if (!rm)
+    return SEARCH_NEXT_KEY;    /* we do not want this one */
+  storage = cbdata->target->keys[rm].storage;
+
+  xd = cbdata->extdata + 0;            /* incore buffer */
+  if (storage == KEY_STORAGE_VERTICAL_OFFSET)
+    {
+      xd += rm;                /* vertical buffer */
+      if (cbdata->vstart == -1)
+        cbdata->vstart = xd->len;
+    }
+  switch(key->type)
+    {
+      case REPOKEY_TYPE_DELETED:
+      case REPOKEY_TYPE_VOID:
+      case REPOKEY_TYPE_CONSTANT:
+      case REPOKEY_TYPE_CONSTANTID:
+       break;
+      case REPOKEY_TYPE_ID:
+       id = kv->id;
+       if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool))
+         id = putinownpool(cbdata, data, id);
+        needid = cbdata->needid;
+       id = needid[NEEDIDOFF(id)].need;
+       data_addid(xd, id);
+       break;
+      case REPOKEY_TYPE_IDARRAY:
+       id = kv->id;
+       if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool))
+         id = putinownpool(cbdata, data, id);
+        needid = cbdata->needid;
+       id = needid[NEEDIDOFF(id)].need;
+       data_addideof(xd, id, kv->eof);
+       break;
+      case REPOKEY_TYPE_STR:
+       data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
+       break;
+      case REPOKEY_TYPE_MD5:
+       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
+       break;
+      case REPOKEY_TYPE_SHA1:
+       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
+       break;
+      case REPOKEY_TYPE_SHA224:
+       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA224);
+       break;
+      case REPOKEY_TYPE_SHA256:
+       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
+       break;
+      case REPOKEY_TYPE_SHA384:
+       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA384);
+       break;
+      case REPOKEY_TYPE_SHA512:
+       data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA512);
+       break;
+       break;
+      case REPOKEY_TYPE_NUM:
+       data_addid64(xd, kv->num, kv->num2);
+       break;
+      case REPOKEY_TYPE_DIR:
+       id = kv->id;
+       if (cbdata->owndirpool)
+         id = putinowndirpool(cbdata, data, id);
+       id = cbdata->dirused[id];
+       data_addid(xd, id);
+       break;
+      case REPOKEY_TYPE_BINARY:
+       data_addid(xd, kv->num);
+       if (kv->num)
+         data_addblob(xd, (unsigned char *)kv->str, kv->num);
+       break;
+      case REPOKEY_TYPE_DIRNUMNUMARRAY:
+       id = kv->id;
+       if (cbdata->owndirpool)
+         id = putinowndirpool(cbdata, data, id);
+       id = cbdata->dirused[id];
+       data_addid(xd, id);
+       data_addid(xd, kv->num);
+       data_addideof(xd, kv->num2, kv->eof);
+       break;
+      case REPOKEY_TYPE_DIRSTRARRAY:
+       id = kv->id;
+       if (cbdata->owndirpool)
+         id = putinowndirpool(cbdata, data, id);
+       id = cbdata->dirused[id];
+       if (rm == cbdata->filelistmode)
+         {
+           /* postpone adding to xd, just update len to get the correct offsets into the incore data*/
+           xd->len += data_addideof_len(id) + strlen(kv->str) + 1;
+           break;
+         }
+       data_addideof(xd, id, kv->eof);
+       data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
+       break;
+      case REPOKEY_TYPE_FIXARRAY:
+      case REPOKEY_TYPE_FLEXARRAY:
+       if (!kv->entry)
+         data_addid(xd, kv->num);
+       if (kv->eof != 2 && (!kv->entry || key->type == REPOKEY_TYPE_FLEXARRAY))
+         data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
+       if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
+         {
+           if (xd->len - cbdata->lastlen > cbdata->maxdata)
+             cbdata->maxdata = xd->len - cbdata->lastlen;
+           cbdata->lastlen = xd->len;
+         }
+       break;
+      default:
+       cbdata->target->error = pool_error(cbdata->pool, -1, "unknown type for %d: %d\n", key->name, key->type);
+       break;
+    }
+  if (storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
+    {
+      /* we can re-use old data in the blob here! */
+      data_addid(cbdata->extdata + 0, cbdata->vstart);                 /* add offset into incore data */
+      data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart);       /* add length into incore data */
+      cbdata->vstart = -1;
+    }
+  return 0;
+}
+
+/* special version of collect_data_cb that collects just one single REPOKEY_TYPE_DIRSTRARRAY vertical data */
+static int
+collect_filelist_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  struct cbdata *cbdata = vcbdata;
+  int rm;
+  Id id;
+  struct extdata *xd;
+
+  rm = cbdata->keymap[key - data->keys];
+  if (rm != cbdata->filelistmode)
+    return SEARCH_NEXT_KEY;    /* we do not want this one */
+  id = kv->id;
+  if (cbdata->owndirpool)
+    id = putinowndirpool(cbdata, data, id);
+  id = cbdata->dirused[id];
+  xd = cbdata->extdata + rm;   /* vertical buffer */
+  data_addideof(xd, id, kv->eof);
+  data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
+  return 0;
+}
+
+static void
+collect_data_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap)
+{
+  Repo *repo = s->repo;
+  Pool *pool = repo->pool;
+  struct extdata *xd = cbdata->extdata;
+  NeedId *needid = cbdata->needid;
+  Id *idarraydata = repo->idarraydata;
+
+  if (keymap[SOLVABLE_NAME])
+    data_addid(xd, needid[s->name].need);
+  if (keymap[SOLVABLE_ARCH])
+    data_addid(xd, needid[s->arch].need);
+  if (keymap[SOLVABLE_EVR])
+    data_addid(xd, needid[s->evr].need);
+  if (s->vendor && keymap[SOLVABLE_VENDOR])
+    data_addid(xd, needid[s->vendor].need);
+  if (s->provides && keymap[SOLVABLE_PROVIDES])
+    data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
+  if (s->obsoletes && keymap[SOLVABLE_OBSOLETES])
+    data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0);
+  if (s->conflicts && keymap[SOLVABLE_CONFLICTS])
+    data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0);
+  if (s->requires && keymap[SOLVABLE_REQUIRES])
+    data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
+  if (s->recommends && keymap[SOLVABLE_RECOMMENDS])
+    data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0);
+  if (s->suggests && keymap[SOLVABLE_SUGGESTS])
+    data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0);
+  if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS])
+    data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0);
+  if (s->enhances && keymap[SOLVABLE_ENHANCES])
+    data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0);
+  if (repo->rpmdbid && keymap[RPM_RPMDBID])
+    data_addid(xd, repo->rpmdbid[(s - pool->solvables) - repo->start]);
+}
+
+/* traverse through directory with first child "dir" */
+static int
+traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
+{
+  Id sib, child;
+  Id parent, lastn;
+
+  parent = n;
+  /* special case for '/', which has to come first */
+  if (parent == 1)
+    dirmap[n++] = 1;
+  for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
+    {
+      if (used && !used[sib])
+       continue;
+      if (sib == 1 && parent == 1)
+       continue;       /* already did that one above */
+      dirmap[n++] = sib;
+    }
+
+  /* check if our block has some content */
+  if (parent == n)
+    return n - 1;      /* nope, drop parent id again */
+
+  /* now go through all the siblings we just added and
+   * do recursive calls on them */
+  lastn = n;
+  for (; parent < lastn; parent++)
+    {
+      sib = dirmap[parent];
+      if (used && used[sib] != 2)      /* 2: used as parent */
+       continue;
+      child = dirpool_child(dp, sib);
+      if (child)
+       {
+         dirmap[n++] = -parent;        /* start new block */
+         n = traverse_dirs(dp, dirmap, n, child, used);
+       }
+    }
+  return n;
+}
+
+static void
+write_compressed_page(Repodata *data, unsigned char *page, int len)
+{
+  int clen;
+  unsigned char cpage[REPOPAGE_BLOBSIZE];
+
+  clen = repopagestore_compress_page(page, len, cpage, len - 1);
+  if (!clen)
+    {
+      write_u32(data, len * 2);
+      write_blob(data, page, len);
+    }
+  else
+    {
+      write_u32(data, clen * 2 + 1);
+      write_blob(data, cpage, clen);
+    }
+}
+
+static Id verticals[] = {
+  SOLVABLE_AUTHORS,
+  SOLVABLE_DESCRIPTION,
+  SOLVABLE_MESSAGEDEL,
+  SOLVABLE_MESSAGEINS,
+  SOLVABLE_EULA,
+  SOLVABLE_DISKUSAGE,
+  SOLVABLE_FILELIST,
+  SOLVABLE_CHECKSUM,
+  DELTA_CHECKSUM,
+  DELTA_SEQ_NUM,
+  SOLVABLE_PKGID,
+  SOLVABLE_HDRID,
+  SOLVABLE_LEADSIGID,
+  SOLVABLE_CHANGELOG_AUTHOR,
+  SOLVABLE_CHANGELOG_TEXT,
+  0
+};
+
+static char *languagetags[] = {
+  "solvable:summary:",
+  "solvable:description:",
+  "solvable:messageins:",
+  "solvable:messagedel:",
+  "solvable:eula:",
+  0
+};
+
+int
+repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
+{
+  const char *keyname;
+  int i;
+
+  for (i = 0; verticals[i]; i++)
+    if (key->name == verticals[i])
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  keyname = pool_id2str(repo->pool, key->name);
+  for (i = 0; languagetags[i] != 0; i++)
+    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
+      return KEY_STORAGE_VERTICAL_OFFSET;
+  return KEY_STORAGE_INCORE;
+}
+
+static int
+write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vpage, int lpage)
+{
+  unsigned char *dp = xd->buf;
+  int l = xd->len;
+  while (l)
+    {
+      int ll = REPOPAGE_BLOBSIZE - lpage;
+      if (l < ll)
+       ll = l;
+      memcpy(vpage + lpage, dp, ll);
+      dp += ll;
+      lpage += ll;
+      l -= ll;
+      if (lpage == REPOPAGE_BLOBSIZE)
+       {
+         write_compressed_page(target, vpage, lpage);
+         lpage = 0;
+       }
+    }
+  return lpage;
+}
+
+
+static Id *
+create_keyskip(Repo *repo, Id entry, unsigned char *repodataused, Id **oldkeyskip)
+{
+  Repodata *data, *last = 0;
+  Id *keyskip;
+  int rdid, cnt = 0;
+
+  if (repo->nrepodata <= 2)
+    return 0;
+  keyskip = *oldkeyskip;
+  if (keyskip)
+    {
+      if (keyskip[1] >= 0x10000000)
+       keyskip = solv_free(keyskip);
+      else
+        keyskip[1] = keyskip[2];
+    }
+  FOR_REPODATAS(repo, rdid, data)
+    {
+      if (!repodataused[rdid])
+        continue;
+      if (entry != SOLVID_META)
+       {
+         if (entry < data->start || entry >= data->end)
+           continue;
+         /* if repodataused is set we know that the state is AVAILABLE */
+         if (!data->incoreoffset[entry - data->start])
+           continue;
+       }
+      if (last)
+        keyskip = repodata_fill_keyskip(last, entry, keyskip);
+      last = data;
+      cnt++;
+    }
+  if (cnt <= 1)                /* just one repodata means we don't need a keyskip */
+    {
+      *oldkeyskip = keyskip;
+      return 0;
+    }
+  keyskip = repodata_fill_keyskip(last, entry, keyskip);
+  if (keyskip)
+    keyskip[2] = keyskip[1] + repo->nrepodata;
+  *oldkeyskip = keyskip;
+  return keyskip;
+}
+
+/*
+ * Repo
+ */
+
+Repowriter *
+repowriter_create(Repo *repo)
+{
+  Repowriter *writer = solv_calloc(1, sizeof(*writer));
+  writer->repo = repo;
+  writer->keyfilter = repo_write_stdkeyfilter;
+  writer->repodatastart = 1;
+  writer->repodataend = repo->nrepodata;
+  writer->solvablestart = repo->start;
+  writer->solvableend = repo->end;
+  return writer;
+}
+
+Repowriter *
+repowriter_free(Repowriter *writer)
+{
+  return solv_free(writer);
+}
+
+void
+repowriter_set_flags(Repowriter *writer, int flags)
+{
+  writer->flags = flags;
+}
+
+void
+repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata)
+{
+  writer->keyfilter = keyfilter;
+  writer->kfdata = kfdata;
+}
+
+void
+repowriter_set_keyqueue(Repowriter *writer, Queue *keyq)
+{
+  writer->keyq = keyq;
+}
+
+void
+repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend)
+{
+  writer->repodatastart = repodatastart;
+  writer->repodataend = repodataend;
+}
+
+void
+repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend)
+{
+  writer->solvablestart = solvablestart;
+  writer->solvableend = solvableend;
+}
+
+/*
+ * the code works the following way:
+ *
+ * 1) find which keys should be written
+ * 2) collect usage information for keys/ids/dirids, create schema
+ *    data
+ * 3) use usage information to create mapping tables, so that often
+ *    used ids get a lower number
+ * 4) encode data into buffers using the mapping tables
+ * 5) write everything to disk
+ */
+int
+repowriter_write(Repowriter *writer, FILE *fp)
+{
+  Repo *repo = writer->repo;
+  Pool *pool = repo->pool;
+  int i, j, n;
+  Solvable *s;
+  NeedId *needid, *needidp;
+  int nstrings, nrels;
+  unsigned int sizeid;
+  unsigned int solv_flags;
+  Id *oldkeyskip = 0;
+  Id *keyskip = 0;
+  int searchflags = 0;
+
+  Id id, *sp;
+
+  Id *keymap;  /* maps repo key to my key, 0 -> not used */
+  int nkeymap;
+  int *keymapstart;    /* maps repo number to keymap offset */
+
+  Id *dirmap;
+  int ndirmap;
+  Id *keyused;
+
+  unsigned char *repodataused;
+  int anyrepodataused = 0;
+
+  int solvablestart, solvableend;
+  Id *solvschemata;
+  int anysolvableused = 0;
+  int nsolvables;
+
+  struct cbdata cbdata;
+
+  int clonepool;
+  Repokey *key;
+  int poolusage, dirpoolusage;
+  int reloff;
+
+  Repodata *data, *dirpooldata;
+
+  Repodata target;
+
+  Stringpool *spool;
+  Dirpool *dirpool;
+
+  Id mainschema, *mainschemakeys;
+
+  struct extdata *xd;
+
+  Id type_constantid = 0;
+
+
+  memset(&cbdata, 0, sizeof(cbdata));
+  cbdata.pool = pool;
+  cbdata.repo = repo;
+  cbdata.target = &target;
+
+  repodata_initdata(&target, repo, 1);
+
+  /* go through all repodata and find the keys we need */
+  /* also unify keys */
+
+  /* start with all KEY_STORAGE_SOLVABLE ids */
+
+  n = ID_NUM_INTERNAL;
+  FOR_REPODATAS(repo, i, data)
+    n += data->nkeys;
+  nkeymap = n;
+  keymap = solv_calloc(nkeymap, sizeof(Id));
+  keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
+  repodataused = solv_calloc(repo->nrepodata, 1);
+
+  clonepool = 0;
+  poolusage = 0;
+
+  if (!(writer->flags & REPOWRITER_NO_STORAGE_SOLVABLE))
+    {
+      /* add keys for STORAGE_SOLVABLE */
+      for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
+       {
+         Repokey keyd;
+         keyd.name = i;
+         if (i < SOLVABLE_PROVIDES)
+           keyd.type = REPOKEY_TYPE_ID;
+         else if (i < RPM_RPMDBID)
+#ifdef USE_REL_IDARRAY
+           keyd.type = REPOKEY_TYPE_REL_IDARRAY;
+#else
+           keyd.type = REPOKEY_TYPE_IDARRAY;
+#endif
+         else
+           keyd.type = REPOKEY_TYPE_NUM;
+         keyd.size = 0;
+         keyd.storage = KEY_STORAGE_SOLVABLE;
+         if (writer->keyfilter)
+           {
+             keyd.storage = writer->keyfilter(repo, &keyd, writer->kfdata);
+             if (keyd.storage == KEY_STORAGE_DROPPED)
+               continue;
+             keyd.storage = KEY_STORAGE_SOLVABLE;
+           }
+         poolusage = 1;
+         clonepool = 1;
+         keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
+       }
+    }
+
+  if (repo->nsolvables)
+    {
+      Repokey keyd;
+      keyd.name = REPOSITORY_SOLVABLES;
+      keyd.type = REPOKEY_TYPE_FLEXARRAY;
+      keyd.size = 0;
+      keyd.storage = KEY_STORAGE_INCORE;
+      keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
+    }
+
+  dirpoolusage = 0;
+
+  spool = 0;
+  dirpool = 0;
+  dirpooldata = 0;
+  n = ID_NUM_INTERNAL;
+  FOR_REPODATAS(repo, i, data)
+    {
+      int idused, dirused;
+      if (i < writer->repodatastart || i >= writer->repodataend)
+       continue;
+      if (writer->keyfilter && (writer->flags & REPOWRITER_LEGACY) != 0)
+       {
+         /* ask keyfilter if we want this repodata */
+         Repokey keyd;
+         /* check if we want this repodata */
+         memset(&keyd, 0, sizeof(keyd));
+         keyd.name = 1;
+         keyd.type = 1;
+         keyd.size = i;
+         if (writer->keyfilter(repo, &keyd, writer->kfdata) == -1)
+           continue;
+       }
+      keymapstart[i] = n;
+      keymap[n++] = 0; /* key 0 */
+      idused = dirused = 0;
+      for (j = 1; j < data->nkeys; j++, n++)
+       {
+         key = data->keys + j;
+         if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
+           {
+             keymap[n] = keymap[key->name];
+             continue;
+           }
+         if (key->type == REPOKEY_TYPE_DELETED && (writer->flags & REPOWRITER_KEEP_TYPE_DELETED) == 0)
+           {
+             keymap[n] = 0;
+             continue;
+           }
+         if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool)
+           {
+             Repokey keyd = *key;
+             keyd.size = repodata_globalize_id(data, key->size, 1);
+             id = repodata_key2id(&target, &keyd, 0);
+           }
+         else
+           id = repodata_key2id(&target, key, 0);
+         if (!id)
+           {
+             /* a new key. ask keyfilter if we want it before creating it */
+             Repokey keyd = *key;
+             keyd.storage = KEY_STORAGE_INCORE;
+             if (keyd.type == REPOKEY_TYPE_CONSTANTID)
+               keyd.size = repodata_globalize_id(data, key->size, 1);
+             else if (keyd.type != REPOKEY_TYPE_CONSTANT)
+               keyd.size = 0;
+             if (writer->keyfilter)
+               {
+                 keyd.storage = writer->keyfilter(repo, &keyd, writer->kfdata);
+                 if (keyd.storage == KEY_STORAGE_DROPPED)
+                   {
+                     keymap[n] = 0;
+                     continue;
+                   }
+               }
+             if (data->state != REPODATA_STUB)
+               id = repodata_key2id(&target, &keyd, 1);
+           }
+         keymap[n] = id;
+         /* load repodata if not already loaded */
+         if (data->state == REPODATA_STUB)
+           {
+             int oldnkeys = data->nkeys;
+             repodata_load(data);
+             if (oldnkeys != data->nkeys)
+               {
+                 nkeymap += data->nkeys - oldnkeys;            /* grow/shrink keymap */
+                 keymap = solv_realloc2(keymap, nkeymap, sizeof(Id));
+               }
+             if (data->state == REPODATA_AVAILABLE)
+               {
+                 /* redo this repodata! */
+                 j = 0;
+                 n = keymapstart[i];
+                 continue;
+               }
+           }
+         if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING)
+           {
+             /* too bad! */
+             keymap[n] = 0;
+             continue;
+           }
+
+         repodataused[i] = 1;
+         anyrepodataused = 1;
+         if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID ||
+              key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
+           idused = 1;
+         else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
+           {
+             idused = 1;       /* dirs also use ids */
+             dirused = 1;
+           }
+       }
+      if (idused)
+       {
+         if (data->localpool)
+           {
+             if (poolusage)
+               poolusage = 3;  /* need own pool */
+             else
+               {
+                 poolusage = 2;
+                 spool = &data->spool;
+               }
+           }
+         else
+           {
+             if (poolusage == 0)
+               poolusage = 1;
+             else if (poolusage != 1)
+               poolusage = 3;  /* need own pool */
+           }
+       }
+      if (dirused)
+       {
+         if (dirpoolusage)
+           dirpoolusage = 3;   /* need own dirpool */
+         else
+           {
+             dirpoolusage = 2;
+             dirpool = &data->dirpool;
+             dirpooldata = data;
+           }
+       }
+    }
+  nkeymap = n;         /* update */
+
+  /* 0: no pool needed at all */
+  /* 1: use global pool */
+  /* 2: use repodata local pool */
+  /* 3: need own pool */
+  if (poolusage != 3)
+    clonepool = 0;
+  if (poolusage == 3)
+    {
+      spool = &target.spool;
+      target.localpool = 1;    /* so we can use repodata_translate */
+      /* hack: reuse global pool data so we don't have to map pool ids */
+      if (clonepool)
+       {
+         stringpool_free(spool);
+         stringpool_clone(spool, &pool->ss);
+         cbdata.clonepool = 1;
+       }
+      cbdata.ownspool = spool;
+    }
+  else if (poolusage == 0 || poolusage == 1)
+    {
+      poolusage = 1;
+      spool = &pool->ss;
+    }
+
+  if (dirpoolusage == 3)
+    {
+      /* dirpoolusage == 3 means that at least two repodata
+       * areas have dir keys. This means that two areas have
+       * idused set to 1, which results in poolusage being
+       * either 1 (global pool) or 3 (own pool) */
+      dirpool = &target.dirpool;
+      dirpooldata = 0;
+      cbdata.owndirpool = dirpool;
+    }
+  else if (dirpool)
+    cbdata.dirused = solv_calloc(dirpool->ndirs, sizeof(Id));
+
+
+/********************************************************************/
+#if 0
+fprintf(stderr, "poolusage: %d\n", poolusage);
+fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
+fprintf(stderr, "clonepool: %d\n", clonepool);
+fprintf(stderr, "nkeys: %d\n", target.nkeys);
+for (i = 1; i < target.nkeys; i++)
+  fprintf(stderr, "  %2d: %s[%d] %d %d %d\n", i, pool_id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage);
+#endif
+
+/********************************************************************/
+
+  searchflags = SEARCH_SUB|SEARCH_ARRAYSENTINEL;
+  if ((writer->flags & REPOWRITER_KEEP_TYPE_DELETED) != 0)
+    searchflags |= SEARCH_KEEP_TYPE_DELETED;
+
+  /* set needed count of all strings and rels,
+   * find which keys are used in the solvables
+   * put all strings in own spool
+   */
+
+  reloff = spool->nstrings;
+  if (cbdata.ownspool)
+    reloff = (reloff + NEEDID_BLOCK) & ~NEEDID_BLOCK;
+  else if (poolusage == 2)
+    {
+      /* we'll need to put the key data into the spool,
+       * so leave some room. 3 * nkeys is an upper bound */
+      reloff += 3 * target.nkeys;
+    }
+
+  needid = calloc(reloff + pool->nrels, sizeof(*needid));
+  needid[0].map = reloff;      /* remember size in case we need to grow */
+
+  cbdata.needid = needid;
+  cbdata.schema = solv_calloc(target.nkeys + 2, sizeof(Id));
+
+  /* create main schema */
+  cbdata.sp = cbdata.schema + 1;
+
+  /* collect meta data from all repodatas */
+  /* XXX: merge arrays of equal keys? */
+  keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip);
+  FOR_REPODATAS(repo, j, data)
+    {
+      if (!repodataused[j])
+       continue;
+      cbdata.keymap = keymap + keymapstart[j];
+      cbdata.lastdirid = 0;            /* clear dir mapping cache */
+      repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_needed_cb, &cbdata);
+    }
+  needid = cbdata.needid;              /* maybe relocated */
+  sp = cbdata.sp;
+  /* add solvables if needed (may revert later) */
+  if (repo->nsolvables)
+    {
+      *sp++ = keymap[REPOSITORY_SOLVABLES];
+      target.keys[keymap[REPOSITORY_SOLVABLES]].size++;
+    }
+  *sp = 0;
+  /* stash away main schema (including terminating zero) */
+  mainschemakeys = solv_memdup2(cbdata.schema + 1, sp - cbdata.schema, sizeof(Id));
+
+  /* collect data for all solvables */
+  solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));    /* allocate upper bound */
+  solvablestart = writer->solvablestart < repo->start ? repo->start : writer->solvablestart;
+  solvableend = writer->solvableend > repo->end ? repo->end : writer->solvableend;
+  anysolvableused = 0;
+  nsolvables = 0;              /* solvables we are going to write, will be <= repo->nsolvables */
+  cbdata.doingsolvables = 1;
+  for (i = solvablestart, s = pool->solvables + i; i < solvableend; i++, s++)
+    {
+      if (s->repo != repo)
+       continue;
+
+      cbdata.sp = cbdata.schema + 1;
+      collect_needed_solvable(&cbdata, s, keymap);
+
+      if (anyrepodataused)
+       {
+         keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip);
+         FOR_REPODATAS(repo, j, data)
+           {
+             if (!repodataused[j] || i < data->start || i >= data->end)
+               continue;
+             cbdata.keymap = keymap + keymapstart[j];
+             cbdata.lastdirid = 0;
+             repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_needed_cb, &cbdata);
+           }
+         needid = cbdata.needid;               /* maybe relocated */
+       }
+      *cbdata.sp = 0;
+      solvschemata[nsolvables] = repodata_schema2id(cbdata.target, cbdata.schema + 1, 1);
+      if (solvschemata[nsolvables])
+       anysolvableused = 1;
+      nsolvables++;
+    }
+  cbdata.doingsolvables = 0;
+
+  if (repo->nsolvables && !anysolvableused)
+    {
+      /* strip off REPOSITORY_SOLVABLES from the main schema */
+      for (sp = mainschemakeys; *sp; sp++)
+       ;
+      sp[-1] = 0;      /* strip last entry */
+    }
+  mainschema = repodata_schema2id(cbdata.target, mainschemakeys, 1);
+  mainschemakeys = solv_free(mainschemakeys);
+
+/********************************************************************/
+
+  /* remove unused keys */
+  keyused = solv_calloc(target.nkeys, sizeof(Id));
+  for (i = 1; i < (int)target.schemadatalen; i++)
+    keyused[target.schemadata[i]] = 1;
+  keyused[0] = 0;
+  for (n = i = 1; i < target.nkeys; i++)
+    {
+      if (!keyused[i])
+       continue;
+      if (i != n)
+       target.keys[n] = target.keys[i];
+      keyused[i] = n++;
+    }
+  target.nkeys = n;
+
+  /* update schema data to the new key ids */
+  for (i = 1; i < (int)target.schemadatalen; i++)
+    target.schemadata[i] = keyused[target.schemadata[i]];
+  /* update keymap to the new key ids */
+  for (i = 0; i < nkeymap; i++)
+    keymap[i] = keyused[keymap[i]];
+  keyused = solv_free(keyused);
+
+  /* copy keys if requested */
+  if (writer->keyq)
+    {
+      queue_empty(writer->keyq);
+      for (i = 1; i < target.nkeys; i++)
+       queue_push2(writer->keyq, target.keys[i].name, target.keys[i].type);
+    }
+
+/********************************************************************/
+
+  /* check if we can do the special filelist memory optimization
+   * we do the check before the keys are mapped.
+   * The optimization is done if there is just one vertical key and
+   * it is of type REPOKEY_TYPE_DIRSTRARRAY */
+  if (anysolvableused && anyrepodataused)
+    {
+      for (i = 1; i < target.nkeys; i++)
+       {
+         if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
+           continue;
+         if (target.keys[i].type != REPOKEY_TYPE_DIRSTRARRAY || cbdata.filelistmode != 0)
+           {
+             cbdata.filelistmode = 0;
+             break;
+           }
+         cbdata.filelistmode = i;
+       }
+    }
+
+/********************************************************************/
+
+  if (poolusage > 1)
+    {
+      /* put all the keys in our string pool */
+      /* put mapped ids right into target.keys */
+      for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
+       {
+         key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
+         id = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
+         if (key->type == REPOKEY_TYPE_CONSTANTID)
+           {
+             type_constantid = id;
+             key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
+           }
+         key->type = id;
+       }
+      if (poolusage == 2)
+       stringpool_freehash(spool);     /* free some mem */
+      if (cbdata.ownspool && spool->nstrings > needid[0].map)
+       {
+         grow_needid(&cbdata, spool->nstrings - 1);
+         needid = cbdata.needid;               /* we relocated */
+       }
+    }
+  else
+    type_constantid = REPOKEY_TYPE_CONSTANTID;
+
+  /* increment needid of the keys */
+  for (i = 1; i < target.nkeys; i++)
+    {
+      if (target.keys[i].type == type_constantid)
+       needid[target.keys[i].size].need++;
+      needid[target.keys[i].name].need++;
+      needid[target.keys[i].type].need++;
+    }
+
+/********************************************************************/
+
+  /* increment need id of all relations
+   * if we refer to another relation, make sure that the
+   * need value is it is bigger than our value so that
+   * ordering works.
+   */
+  reloff = needid[0].map;
+  for (i = pool->nrels - 1, needidp = needid + (reloff + i); i > 0; i--, needidp--)
+    if (needidp->need)
+      break;
+  if (i)
+    {
+      /* we have some relations with a non-zero need */
+      Reldep *rd;
+
+      for (rd = pool->rels + i; i > 0; i--, rd--)
+       {
+         int need = needid[reloff + i].need;
+         if (!need)
+           continue;
+         id = rd->name;
+         if (ISRELDEP(id))
+           {
+             id = GETRELID(id);
+             if (needid[reloff + id].need < need + 1)
+               needid[reloff + id].need = need + 1;
+           }
+         else
+           {
+             if (cbdata.ownspool && id > 1 && !cbdata.clonepool)
+               {
+                 id = stringpool_str2id(cbdata.ownspool, pool_id2str(pool, id), 1);
+                 if (id >= cbdata.needid[0].map)
+                   {
+                     grow_needid(&cbdata, id);
+                     needid = cbdata.needid;           /* we relocated */
+                     reloff = needid[0].map;           /* we have a new offset */
+                   }
+               }
+             needid[id].need++;
+           }
+
+         id = rd->evr;
+         if (ISRELDEP(id))
+           {
+             id = GETRELID(id);
+             if (needid[reloff + id].need < need + 1)
+               needid[reloff + id].need = need + 1;
+           }
+         else
+           {
+             if (cbdata.ownspool && id > 1 && !cbdata.clonepool)
+               {
+                 id = stringpool_str2id(cbdata.ownspool, pool_id2str(pool, id), 1);
+                 if (id >= cbdata.needid[0].map)
+                   {
+                     grow_needid(&cbdata, id);
+                     needid = cbdata.needid;           /* we relocated */
+                     reloff = needid[0].map;           /* we have a new offset */
+                   }
+               }
+             needid[id].need++;
+           }
+       }
+  }
+
+/********************************************************************/
+
+  /* increment need id for used dir components */
+  if (cbdata.owndirpool)
+    {
+      /* if we have own dirpool, all entries in it are used.
+        also, all comp ids are already mapped by putinowndirpool(),
+        so we can simply increment needid.
+        (owndirpool != 0, dirused == 0, dirpooldata == 0) */
+      for (i = 1; i < dirpool->ndirs; i++)
+       {
+         id = dirpool->dirs[i];
+         if (id <= 0)
+           continue;
+         needid[id].need++;
+       }
+    }
+  else if (dirpool)
+    {
+      Id parent;
+      /* else we re-use a dirpool of repodata "dirpooldata".
+        dirused tells us which of the ids are used.
+        we need to map comp ids if we generate a new pool.
+        (owndirpool == 0, dirused != 0, dirpooldata != 0) */
+      for (i = dirpool->ndirs - 1; i > 0; i--)
+       {
+         if (!cbdata.dirused[i])
+           continue;
+         parent = dirpool_parent(dirpool, i);  /* always < i */
+         cbdata.dirused[parent] = 2;           /* 2: used as parent */
+         id = dirpool->dirs[i];
+         if (id <= 0)
+           continue;
+         if (cbdata.ownspool && id > 1 && (!cbdata.clonepool || dirpooldata->localpool))
+           {
+             id = putinownpool(&cbdata, dirpooldata, id);
+             needid = cbdata.needid;
+           }
+         needid[id].need++;
+       }
+      if (!cbdata.dirused[0])
+       {
+          cbdata.dirused = solv_free(cbdata.dirused);
+          dirpool = 0;
+       }
+    }
+
+
+/********************************************************************/
+
+  /*
+   * create mapping table, new keys are sorted by needid[].need
+   *
+   * needid[key].need : old key -> new key
+   * needid[key].map  : new key -> old key
+   */
+
+  /* zero out id 0 and rel 0 just in case */
+  reloff = needid[0].map;
+  needid[0].need = 0;
+  needid[reloff].need = 0;
+
+  for (i = 1; i < reloff + pool->nrels; i++)
+    needid[i].map = i;
+
+  /* make first entry '' */
+  needid[1].need = 1;
+  solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
+  solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
+  /* now needid is in new order, needid[newid].map -> oldid */
+
+  /* calculate string space size, also zero out needid[].need */
+  sizeid = 0;
+  for (i = 1; i < reloff; i++)
+    {
+      if (!needid[i].need)
+        break; /* as we have sorted, every entry after this also has need == 0 */
+      needid[i].need = 0;
+      sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
+    }
+  nstrings = i;        /* our new string id end */
+
+  /* make needid[oldid].need point to newid */
+  for (i = 1; i < nstrings; i++)
+    needid[needid[i].map].need = i;
+
+  /* same as above for relations */
+  for (i = 0; i < pool->nrels; i++)
+    {
+      if (!needid[reloff + i].need)
+        break;
+      needid[reloff + i].need = 0;
+    }
+  nrels = i;   /* our new rel id end */
+
+  for (i = 0; i < nrels; i++)
+    needid[needid[reloff + i].map].need = nstrings + i;
+
+  /* now we have: needid[oldid].need -> newid
+                  needid[newid].map  -> oldid
+     both for strings and relations  */
+
+
+/********************************************************************/
+
+  ndirmap = 0;
+  dirmap = 0;
+  if (dirpool && dirpool->ndirs)
+    {
+      /* create our new target directory structure by traversing through all
+       * used dirs. This will concatenate blocks with the same parent
+       * directory into single blocks.
+       * Instead of components, traverse_dirs stores the old dirids,
+       * we will change this in the second step below */
+      /* (dirpooldata and dirused are 0 if we have our own dirpool) */
+      if (cbdata.dirused && !cbdata.dirused[1])
+       {
+         cbdata.dirused[1] = 1;        /* always want / entry */
+         cbdata.dirused[0] = 2;        /* always want / entry */
+       }
+      dirmap = solv_calloc(dirpool->ndirs, sizeof(Id));
+      dirmap[0] = 0;
+      ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
+
+      /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */
+      /* change dirmap so that it maps from "new dirid" to "new compid" */
+      if (!cbdata.dirused)
+       cbdata.dirused = solv_malloc2(dirpool->ndirs, sizeof(Id));
+      memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
+      for (i = 1; i < ndirmap; i++)
+       {
+         if (dirmap[i] <= 0)
+           continue;
+         cbdata.dirused[dirmap[i]] = i;
+         id = dirpool->dirs[dirmap[i]];
+         if (dirpooldata && cbdata.ownspool && id > 1)
+           id = putinownpool(&cbdata, dirpooldata, id);
+         dirmap[i] = needid[id].need;
+       }
+      /* now the new target directory structure is complete (dirmap), and we have
+       * dirused[olddirid] -> newdirid */
+    }
+
+/********************************************************************/
+
+  /* collect all data
+   * we use extdata[0] for incore data and extdata[keyid] for vertical data
+   *
+   * this must match the code above that creates the schema data!
+   */
+
+  cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
+
+  xd = cbdata.extdata;
+  cbdata.current_sub = 0;
+  /* add main schema */
+  cbdata.lastlen = 0;
+  data_addid(xd, mainschema);
+
+  keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip);
+  FOR_REPODATAS(repo, j, data)
+    {
+      if (!repodataused[j])
+       continue;
+      cbdata.keymap = keymap + keymapstart[j];
+      cbdata.lastdirid = 0;
+      repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_data_cb, &cbdata);
+    }
+  if (xd->len - cbdata.lastlen > cbdata.maxdata)
+    cbdata.maxdata = xd->len - cbdata.lastlen;
+  cbdata.lastlen = xd->len;
+
+  if (anysolvableused)
+    {
+      data_addid(xd, nsolvables);      /* FLEXARRAY nentries */
+      cbdata.doingsolvables = 1;
+
+      for (i = solvablestart, s = pool->solvables + i, n = 0; i < solvableend; i++, s++)
+       {
+         if (s->repo != repo)
+           continue;
+         data_addid(xd, solvschemata[n]);
+          collect_data_solvable(&cbdata, s, keymap);
+         if (anyrepodataused)
+           {
+             keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip);
+             cbdata.vstart = -1;
+             FOR_REPODATAS(repo, j, data)
+               {
+                 if (!repodataused[j] || i < data->start || i >= data->end)
+                   continue;
+                 cbdata.keymap = keymap + keymapstart[j];
+                 cbdata.lastdirid = 0;
+                 repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_data_cb, &cbdata);
+               }
+           }
+         if (xd->len - cbdata.lastlen > cbdata.maxdata)
+           cbdata.maxdata = xd->len - cbdata.lastlen;
+         cbdata.lastlen = xd->len;
+         n++;
+       }
+      cbdata.doingsolvables = 0;
+    }
+
+  assert(cbdata.current_sub == cbdata.nsubschemata);
+  cbdata.subschemata = solv_free(cbdata.subschemata);
+  cbdata.nsubschemata = 0;
+
+/********************************************************************/
+
+  target.fp = fp;
+
+  /* write header */
+
+  /* write file header */
+  write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
+  write_u32(&target, SOLV_VERSION_8);
+
+
+  /* write counts */
+  write_u32(&target, nstrings);
+  write_u32(&target, nrels);
+  write_u32(&target, ndirmap);
+  write_u32(&target, anysolvableused ? nsolvables : 0);
+  write_u32(&target, target.nkeys);
+  write_u32(&target, target.nschemata);
+  solv_flags = 0;
+  solv_flags |= SOLV_FLAG_PREFIX_POOL;
+  solv_flags |= SOLV_FLAG_SIZE_BYTES;
+  write_u32(&target, solv_flags);
+
+  if (nstrings)
+    {
+      /*
+       * calculate prefix encoding of the strings
+       */
+      unsigned char *prefixcomp = solv_malloc(nstrings);
+      unsigned int compsum = 0;
+      char *old_str = "";
+
+      prefixcomp[0] = 0;
+      for (i = 1; i < nstrings; i++)
+       {
+         char *str = spool->stringspace + spool->strings[needid[i].map];
+         int same;
+         for (same = 0; same < 255; same++)
+           if (!old_str[same] || old_str[same] != str[same])
+             break;
+         prefixcomp[i] = same;
+         compsum += same;
+         old_str = str;
+       }
+
+      /*
+       * write strings
+       */
+      write_u32(&target, sizeid);
+      /* we save compsum bytes but need 1 extra byte for every string */
+      write_u32(&target, sizeid + nstrings - 1 - compsum);
+      for (i = 1; i < nstrings; i++)
+       {
+         char *str = spool->stringspace + spool->strings[needid[i].map];
+         write_u8(&target, prefixcomp[i]);
+         write_str(&target, str + prefixcomp[i]);
+       }
+      solv_free(prefixcomp);
+    }
+  else
+    {
+      write_u32(&target, 0);
+      write_u32(&target, 0);
+    }
+
+  /*
+   * write RelDeps
+   */
+  for (i = 0; i < nrels; i++)
+    {
+      Reldep *ran = pool->rels + (needid[reloff + i].map - reloff);
+      write_id(&target, needid[NEEDIDOFF(ran->name)].need);
+      write_id(&target, needid[NEEDIDOFF(ran->evr)].need);
+      write_u8(&target, ran->flags);
+    }
+
+  /*
+   * write dirs (skip both root and / entry)
+   */
+  for (i = 2; i < ndirmap; i++)
+    {
+      if (dirmap[i] > 0)
+        write_id(&target, dirmap[i]);
+      else
+        write_id(&target, nstrings - dirmap[i]);
+    }
+  solv_free(dirmap);
+
+  /*
+   * write keys
+   */
+  for (i = 1; i < target.nkeys; i++)
+    {
+      write_id(&target, needid[target.keys[i].name].need);
+      write_id(&target, needid[target.keys[i].type].need);
+      if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
+       {
+         if (target.keys[i].type == type_constantid)
+            write_id(&target, needid[target.keys[i].size].need);
+         else
+            write_id(&target, target.keys[i].size);
+       }
+      else
+        write_id(&target, cbdata.extdata[i].len);
+      write_id(&target, target.keys[i].storage);
+    }
+
+  /*
+   * write schemata
+   */
+  write_id(&target, target.schemadatalen);     /* XXX -1? */
+  for (i = 1; i < target.nschemata; i++)
+    write_idarray(&target, pool, 0, repodata_id2schema(&target, i));
+
+  /*
+   * write incore data
+   */
+  write_id(&target, cbdata.maxdata);
+  write_id(&target, cbdata.extdata[0].len);
+  if (cbdata.extdata[0].len)
+    write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len);
+  solv_free(cbdata.extdata[0].buf);
+
+  /*
+   * write vertical data if we have any
+   */
+  for (i = 1; i < target.nkeys; i++)
+    if (cbdata.extdata[i].len)
+      break;
+  if (i < target.nkeys)
+    {
+      /* have vertical data, write it in pages */
+      unsigned char vpage[REPOPAGE_BLOBSIZE];
+      int lpage = 0;
+
+      write_u32(&target, REPOPAGE_BLOBSIZE);
+      if (!cbdata.filelistmode)
+       {
+         for (i = 1; i < target.nkeys; i++)
+           if (cbdata.extdata[i].len)
+             lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage);
+       }
+      else
+       {
+         /* ok, just one single extdata which is of type REPOKEY_TYPE_DIRSTRARRAY */
+         xd = cbdata.extdata + i;
+         xd->len = 0;
+         keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip);
+         FOR_REPODATAS(repo, j, data)
+           {
+             if (!repodataused[j])
+               continue;
+             cbdata.keymap = keymap + keymapstart[j];
+             cbdata.lastdirid = 0;
+             repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_filelist_cb, &cbdata);
+           }
+         for (i = solvablestart, s = pool->solvables + i; i < solvableend; i++, s++)
+           {
+             if (s->repo != repo)
+               continue;
+             keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip);
+             FOR_REPODATAS(repo, j, data)
+               {
+                 if (!repodataused[j] || i < data->start || i >= data->end)
+                   continue;
+                 cbdata.keymap = keymap + keymapstart[j];
+                 cbdata.lastdirid = 0;
+                 repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_filelist_cb, &cbdata);
+               }
+             if (xd->len > 1024 * 1024)
+               {
+                 lpage = write_compressed_extdata(&target, xd, vpage, lpage);
+                 xd->len = 0;
+               }
+           }
+         if (xd->len)
+           lpage = write_compressed_extdata(&target, xd, vpage, lpage);
+       }
+      if (lpage)
+       write_compressed_page(&target, vpage, lpage);
+    }
+
+  for (i = 1; i < target.nkeys; i++)
+    solv_free(cbdata.extdata[i].buf);
+  solv_free(cbdata.extdata);
+
+  target.fp = 0;
+  repodata_freedata(&target);
+
+  solv_free(needid);
+  solv_free(solvschemata);
+  solv_free(cbdata.schema);
+
+  solv_free(keymap);
+  solv_free(keymapstart);
+  solv_free(cbdata.dirused);
+  solv_free(repodataused);
+  solv_free(oldkeyskip);
+  return target.error;
+}
+
+int
+repo_write(Repo *repo, FILE *fp)
+{
+  int res;
+  Repowriter *writer = repowriter_create(repo);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
+}
+
+int
+repodata_write(Repodata *data, FILE *fp)
+{
+  int res;
+  Repowriter *writer = repowriter_create(data->repo);
+  repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1);
+  repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
+}
+
+/* deprecated functions, do not use in new code! */
+int
+repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
+{
+  int res;
+  Repowriter *writer = repowriter_create(repo);
+  repowriter_set_flags(writer, REPOWRITER_LEGACY);
+  repowriter_set_keyfilter(writer, keyfilter, kfdata);
+  repowriter_set_keyqueue(writer, keyq);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
+}
+
+int
+repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
+{
+  int res;
+  Repowriter *writer = repowriter_create(data->repo);
+  repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1);
+  repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE | REPOWRITER_LEGACY);
+  repowriter_set_keyfilter(writer, keyfilter, kfdata);
+  repowriter_set_keyqueue(writer, keyq);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
+}
+
diff --git a/libsolv-0.7.2/src/repo_write.h b/libsolv-0.7.2/src/repo_write.h
new file mode 100644 (file)
index 0000000..3471670
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_write.h
+ *
+ */
+
+#ifndef REPO_WRITE_H
+#define REPO_WRITE_H
+
+#include <stdio.h>
+
+#include "repo.h"
+#include "queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct s_Repowriter {
+  Repo *repo;
+  int flags;
+  int repodatastart;
+  int repodataend;
+  int solvablestart;
+  int solvableend;
+  int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
+  void *kfdata;
+  Queue *keyq;
+} Repowriter;
+
+/* repowriter flags */
+#define REPOWRITER_NO_STORAGE_SOLVABLE (1 << 0)
+#define REPOWRITER_KEEP_TYPE_DELETED   (1 << 1)
+#define REPOWRITER_LEGACY              (1 << 30)
+
+Repowriter *repowriter_create(Repo *repo);
+Repowriter *repowriter_free(Repowriter *writer);
+void repowriter_set_flags(Repowriter *writer, int flags);
+void repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata);
+void repowriter_set_keyqueue(Repowriter *writer, Queue *keyq);
+void repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend);
+void repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend);
+int repowriter_write(Repowriter *writer, FILE *fp);
+
+/* convenience functions */
+extern int repo_write(Repo *repo, FILE *fp);
+extern int repodata_write(Repodata *data , FILE *fp);
+
+extern int repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata);
+
+/* deprecated functions, do not use in new code! */
+extern int repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
+extern int repodata_write_filtered(Repodata *data , FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsolv-0.7.2/src/repodata.c b/libsolv-0.7.2/src/repodata.c
new file mode 100644 (file)
index 0000000..71e8175
--- /dev/null
@@ -0,0 +1,3824 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repodata.c
+ *
+ * Manage data coming from one repository
+ *
+ * a repository can contain multiple repodata entries, consisting of
+ * different sets of keys and different sets of solvables
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <regex.h>
+
+#include "repo.h"
+#include "pool.h"
+#include "poolid_private.h"
+#include "util.h"
+#include "hash.h"
+#include "chksum.h"
+
+#include "repopack.h"
+#include "repopage.h"
+
+#define REPODATA_BLOCK 255
+
+static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
+
+void
+repodata_initdata(Repodata *data, Repo *repo, int localpool)
+{
+  memset(data, 0, sizeof (*data));
+  data->repodataid = data - repo->repodata;
+  data->repo = repo;
+  data->localpool = localpool;
+  if (localpool)
+    stringpool_init_empty(&data->spool);
+  /* dirpool_init(&data->dirpool);     just zeros out again */
+  data->keys = solv_calloc(1, sizeof(Repokey));
+  data->nkeys = 1;
+  data->schemata = solv_calloc(1, sizeof(Id));
+  data->schemadata = solv_calloc(1, sizeof(Id));
+  data->nschemata = 1;
+  data->schemadatalen = 1;
+  repopagestore_init(&data->store);
+}
+
+void
+repodata_freedata(Repodata *data)
+{
+  int i;
+
+  solv_free(data->keys);
+
+  solv_free(data->schemata);
+  solv_free(data->schemadata);
+  solv_free(data->schematahash);
+
+  stringpool_free(&data->spool);
+  dirpool_free(&data->dirpool);
+
+  solv_free(data->mainschemaoffsets);
+  solv_free(data->incoredata);
+  solv_free(data->incoreoffset);
+  solv_free(data->verticaloffset);
+
+  repopagestore_free(&data->store);
+
+  solv_free(data->vincore);
+
+  if (data->attrs)
+    for (i = 0; i < data->end - data->start; i++)
+      solv_free(data->attrs[i]);
+  solv_free(data->attrs);
+  if (data->xattrs)
+    for (i = 0; i < data->nxattrs; i++)
+      solv_free(data->xattrs[i]);
+  solv_free(data->xattrs);
+
+  solv_free(data->attrdata);
+  solv_free(data->attriddata);
+  solv_free(data->attrnum64data);
+
+  solv_free(data->dircache);
+
+  repodata_free_filelistfilter(data);
+}
+
+void
+repodata_free(Repodata *data)
+{
+  Repo *repo = data->repo;
+  int i = data - repo->repodata;
+  if (i == 0)
+    return;
+  repodata_freedata(data);
+  if (i < repo->nrepodata - 1)
+    {
+      /* whoa! this changes the repodataids! */
+      memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
+      for (; i < repo->nrepodata - 1; i++)
+       repo->repodata[i].repodataid = i;
+    }
+  repo->nrepodata--;
+  if (repo->nrepodata == 1)
+    {
+      repo->repodata = solv_free(repo->repodata);
+      repo->nrepodata = 0;
+    }
+}
+
+void
+repodata_empty(Repodata *data, int localpool)
+{
+  void (*loadcallback)(Repodata *) = data->loadcallback;
+  int state = data->state;
+  repodata_freedata(data);
+  repodata_initdata(data, data->repo, localpool);
+  data->state = state;
+  data->loadcallback = loadcallback;
+}
+
+
+/***************************************************************
+ * key pool management
+ */
+
+/* this is not so time critical that we need a hash, so we do a simple
+ * linear search */
+Id
+repodata_key2id(Repodata *data, Repokey *key, int create)
+{
+  Id keyid;
+
+  for (keyid = 1; keyid < data->nkeys; keyid++)
+    if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
+      {
+        if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
+          continue;
+        break;
+      }
+  if (keyid == data->nkeys)
+    {
+      if (!create)
+       return 0;
+      /* allocate new key */
+      data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
+      data->keys[data->nkeys++] = *key;
+      if (data->verticaloffset)
+        {
+          data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
+          data->verticaloffset[data->nkeys - 1] = 0;
+        }
+      data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
+    }
+  return keyid;
+}
+
+
+/***************************************************************
+ * schema pool management
+ */
+
+#define SCHEMATA_BLOCK 31
+#define SCHEMATADATA_BLOCK 255
+
+Id
+repodata_schema2id(Repodata *data, Id *schema, int create)
+{
+  int h, len, i;
+  Id *sp, cid;
+  Id *schematahash;
+
+  if (!*schema)
+    return 0;  /* XXX: allow empty schema? */
+  if ((schematahash = data->schematahash) == 0)
+    {
+      data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
+      for (i = 1; i < data->nschemata; i++)
+       {
+         for (sp = data->schemadata + data->schemata[i], h = 0; *sp;)
+           h = h * 7 + *sp++;
+         h &= 255;
+         schematahash[h] = i;
+       }
+      data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
+      data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
+    }
+
+  for (sp = schema, len = 0, h = 0; *sp; len++)
+    h = h * 7 + *sp++;
+  h &= 255;
+  len++;
+
+  cid = schematahash[h];
+  if (cid)
+    {
+      if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
+        return cid;
+      /* cache conflict, do a slow search */
+      for (cid = 1; cid < data->nschemata; cid++)
+        if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
+          return cid;
+    }
+  /* a new one */
+  if (!create)
+    return 0;
+  data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
+  data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
+  /* add schema */
+  memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
+  data->schemata[data->nschemata] = data->schemadatalen;
+  data->schemadatalen += len;
+  schematahash[h] = data->nschemata;
+#if 0
+fprintf(stderr, "schema2id: new schema\n");
+#endif
+  return data->nschemata++;
+}
+
+void
+repodata_free_schemahash(Repodata *data)
+{
+  data->schematahash = solv_free(data->schematahash);
+  /* shrink arrays */
+  data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
+  data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
+}
+
+
+/***************************************************************
+ * dir pool management
+ */
+
+#ifndef HAVE_STRCHRNUL
+static inline const char *strchrnul(const char *str, char x)
+{
+  const char *p = strchr(str, x);
+  return p ? p : str + strlen(str);
+}
+#endif
+
+#define DIRCACHE_SIZE 41       /* < 1k */
+
+#ifdef DIRCACHE_SIZE
+struct dircache {
+  Id ids[DIRCACHE_SIZE];
+  char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
+};
+#endif
+
+Id
+repodata_str2dir(Repodata *data, const char *dir, int create)
+{
+  Id id, parent;
+#ifdef DIRCACHE_SIZE
+  const char *dirs;
+#endif
+  const char *dire;
+
+  if (!*dir)
+    return data->dirpool.ndirs ? 0 : dirpool_add_dir(&data->dirpool, 0, 0, create);
+  while (*dir == '/' && dir[1] == '/')
+    dir++;
+  if (*dir == '/' && !dir[1])
+    return data->dirpool.ndirs ? 1 : dirpool_add_dir(&data->dirpool, 0, 1, create);
+  parent = 0;
+#ifdef DIRCACHE_SIZE
+  dirs = dir;
+  if (data->dircache)
+    {
+      int l;
+      struct dircache *dircache = data->dircache;
+      l = strlen(dir);
+      while (l > 0)
+       {
+         if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
+           {
+             parent = dircache->ids[l];
+             dir += l;
+             if (!*dir)
+               return parent;
+             while (*dir == '/')
+               dir++;
+             break;
+           }
+         while (--l)
+           if (dir[l] == '/')
+             break;
+       }
+    }
+#endif
+  while (*dir)
+    {
+      dire = strchrnul(dir, '/');
+      if (data->localpool)
+        id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
+      else
+       id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
+      if (!id)
+       return 0;
+      parent = dirpool_add_dir(&data->dirpool, parent, id, create);
+      if (!parent)
+       return 0;
+#ifdef DIRCACHE_SIZE
+      if (!data->dircache)
+       data->dircache = solv_calloc(1, sizeof(struct dircache));
+      if (data->dircache)
+       {
+         int l = dire - dirs;
+         if (l < DIRCACHE_SIZE)
+           {
+             data->dircache->ids[l] = parent;
+             memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
+           }
+       }
+#endif
+      if (!*dire)
+       break;
+      dir = dire + 1;
+      while (*dir == '/')
+       dir++;
+    }
+  return parent;
+}
+
+void
+repodata_free_dircache(Repodata *data)
+{
+  data->dircache = solv_free(data->dircache);
+}
+
+const char *
+repodata_dir2str(Repodata *data, Id did, const char *suf)
+{
+  Pool *pool = data->repo->pool;
+  int l = 0;
+  Id parent, comp;
+  const char *comps;
+  char *p;
+
+  if (!did)
+    return suf ? suf : "";
+  if (did == 1 && !suf)
+    return "/";
+  parent = did;
+  while (parent)
+    {
+      comp = dirpool_compid(&data->dirpool, parent);
+      comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
+      l += strlen(comps);
+      parent = dirpool_parent(&data->dirpool, parent);
+      if (parent)
+       l++;
+    }
+  if (suf)
+    l += strlen(suf) + 1;
+  p = pool_alloctmpspace(pool, l + 1) + l;
+  *p = 0;
+  if (suf)
+    {
+      p -= strlen(suf);
+      strcpy(p, suf);
+      *--p = '/';
+    }
+  parent = did;
+  while (parent)
+    {
+      comp = dirpool_compid(&data->dirpool, parent);
+      comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
+      l = strlen(comps);
+      p -= l;
+      strncpy(p, comps, l);
+      parent = dirpool_parent(&data->dirpool, parent);
+      if (parent)
+        *--p = '/';
+    }
+  return p;
+}
+
+
+/***************************************************************
+ * data management
+ */
+
+static inline unsigned char *
+data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
+{
+  Id *keyp = data->schemadata + data->schemata[schema];
+  for (; *keyp; keyp++)
+    dp = data_skip_key(data, dp, data->keys + *keyp);
+  return dp;
+}
+
+static unsigned char *
+data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
+{
+  int nentries, schema;
+  switch(key->type)
+    {
+    case REPOKEY_TYPE_FIXARRAY:
+      dp = data_read_id(dp, &nentries);
+      if (!nentries)
+       return dp;
+      dp = data_read_id(dp, &schema);
+      while (nentries--)
+       dp = data_skip_schema(data, dp, schema);
+      return dp;
+    case REPOKEY_TYPE_FLEXARRAY:
+      dp = data_read_id(dp, &nentries);
+      while (nentries--)
+       {
+         dp = data_read_id(dp, &schema);
+         dp = data_skip_schema(data, dp, schema);
+       }
+      return dp;
+    default:
+      if (key->storage == KEY_STORAGE_INCORE)
+        dp = data_skip(dp, key->type);
+      else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+       {
+         dp = data_skip(dp, REPOKEY_TYPE_ID);
+         dp = data_skip(dp, REPOKEY_TYPE_ID);
+       }
+      return dp;
+    }
+}
+
+static unsigned char *
+forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
+{
+  Id k;
+
+  if (!keyid)
+    return 0;
+  if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
+    {
+      int i;
+      for (i = 0; (k = *keyp++) != 0; i++)
+        if (k == keyid)
+         return data->incoredata + data->mainschemaoffsets[i];
+      return 0;
+    }
+  while ((k = *keyp++) != 0)
+    {
+      if (k == keyid)
+       return dp;
+      if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
+       {
+         dp = data_skip(dp, REPOKEY_TYPE_ID);  /* skip offset */
+         dp = data_skip(dp, REPOKEY_TYPE_ID);  /* skip length */
+         continue;
+       }
+      if (data->keys[k].storage != KEY_STORAGE_INCORE)
+       continue;
+      dp = data_skip_key(data, dp, data->keys + k);
+    }
+  return 0;
+}
+
+static unsigned char *
+get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
+{
+  unsigned char *dp;
+  if (len <= 0)
+    return 0;
+  if (off >= data->lastverticaloffset)
+    {
+      off -= data->lastverticaloffset;
+      if ((unsigned int)off + len > data->vincorelen)
+       return 0;
+      return data->vincore + off;
+    }
+  if ((unsigned int)off + len > key->size)
+    return 0;
+  /* we now have the offset, go into vertical */
+  off += data->verticaloffset[key - data->keys];
+  /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
+  dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
+  data->storestate++;
+  if (dp)
+    dp += off % REPOPAGE_BLOBSIZE;
+  return dp;
+}
+
+static inline unsigned char *
+get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
+{
+  unsigned char *dp = *dpp;
+
+  if (!dp)
+    return 0;
+  if (key->storage == KEY_STORAGE_INCORE)
+    {
+      if (advance)
+        *dpp = data_skip_key(data, dp, key);
+      return dp;
+    }
+  else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+    {
+      Id off, len;
+      dp = data_read_id(dp, &off);
+      dp = data_read_id(dp, &len);
+      if (advance)
+        *dpp = dp;
+      return get_vertical_data(data, key, off, len);
+    }
+  return 0;
+}
+
+void
+repodata_load(Repodata *data)
+{
+  if (data->state != REPODATA_STUB)
+    return;
+  if (data->loadcallback)
+    data->loadcallback(data);
+  else
+    data->state = REPODATA_ERROR;
+}
+
+static int
+maybe_load_repodata_stub(Repodata *data, Id keyname)
+{
+  if (data->state != REPODATA_STUB)
+    {
+      data->state = REPODATA_ERROR;
+      return 0;
+    }
+  if (keyname)
+    {
+      int i;
+      for (i = 1; i < data->nkeys; i++)
+       if (keyname == data->keys[i].name)
+         break;
+      if (i == data->nkeys)
+       return 0;
+    }
+  repodata_load(data);
+  return data->state == REPODATA_AVAILABLE ? 1 : 0;
+}
+
+static inline int
+maybe_load_repodata(Repodata *data, Id keyname)
+{
+  if (keyname && !repodata_precheck_keyname(data, keyname))
+    return 0;  /* do not bother... */
+  if (data->state == REPODATA_AVAILABLE || data->state == REPODATA_LOADING)
+    return 1;
+  if (data->state == REPODATA_ERROR)
+    return 0;
+  return maybe_load_repodata_stub(data, keyname);
+}
+
+static inline unsigned char *
+solvid2data(Repodata *data, Id solvid, Id *schemap)
+{
+  unsigned char *dp = data->incoredata;
+  if (!dp)
+    return 0;
+  if (solvid == SOLVID_META)
+    dp += 1;   /* offset of "meta" solvable */
+  else if (solvid == SOLVID_POS)
+    {
+      Pool *pool = data->repo->pool;
+      if (data->repo != pool->pos.repo)
+       return 0;
+      if (data != data->repo->repodata + pool->pos.repodataid)
+       return 0;
+      dp += pool->pos.dp;
+      if (pool->pos.dp != 1)
+        {
+          *schemap = pool->pos.schema;
+          return dp;
+       }
+    }
+  else
+    {
+      if (solvid < data->start || solvid >= data->end)
+       return 0;
+      dp += data->incoreoffset[solvid - data->start];
+    }
+  return data_read_id(dp, schemap);
+}
+
+/************************************************************************
+ * data lookup
+ */
+
+static unsigned char *
+find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
+{
+  unsigned char *dp;
+  Id schema, *keyp, *kp;
+  Repokey *key;
+
+  if (!maybe_load_repodata(data, keyname))
+    return 0;
+  dp = solvid2data(data, solvid, &schema);
+  if (!dp)
+    return 0;
+  keyp = data->schemadata + data->schemata[schema];
+  for (kp = keyp; *kp; kp++)
+    if (data->keys[*kp].name == keyname)
+      break;
+  if (!*kp)
+    return 0;
+  *keypp = key = data->keys + *kp;
+  if (key->type == REPOKEY_TYPE_DELETED)
+    return 0;
+  if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
+    return dp; /* no need to forward... */
+  if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
+    return 0;  /* get_data will not work, no need to forward */
+  dp = forward_to_key(data, *kp, keyp, dp);
+  if (!dp)
+    return 0;
+  return get_data(data, key, &dp, 0);
+}
+
+static const Id *
+repodata_lookup_schemakeys(Repodata *data, Id solvid)
+{
+  Id schema;
+  if (!maybe_load_repodata(data, 0))
+    return 0;
+  if (!solvid2data(data, solvid, &schema))
+    return 0;
+  return data->schemadata + data->schemata[schema];
+}
+
+static Id *
+alloc_keyskip()
+{
+  Id *keyskip = solv_calloc(3 + 256, sizeof(Id));
+  keyskip[0] = 256; 
+  keyskip[1] = keyskip[2] = 1; 
+  return keyskip;
+}
+
+Id *
+repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip)
+{
+  const Id *keyp;
+  Id maxkeyname, value;
+  keyp = repodata_lookup_schemakeys(data, solvid);
+  if (!keyp)
+    return keyskip;    /* no keys for this solvid */
+  if (!keyskip)
+    keyskip = alloc_keyskip();
+  maxkeyname = keyskip[0];
+  value = keyskip[1] + data->repodataid;
+  for (; *keyp; keyp++)
+    {
+      Id keyname = data->keys[*keyp].name;
+      if (keyname >= maxkeyname)
+       {
+         int newmax = (keyname | 255) + 1; 
+         keyskip = solv_realloc2(keyskip, 3 + newmax, sizeof(Id));
+         memset(keyskip + (3 + maxkeyname), 0, (newmax - maxkeyname) * sizeof(Id));
+         keyskip[0] = maxkeyname = newmax;
+       }
+      keyskip[3 + keyname] = value;
+    }
+  return keyskip;
+}
+
+Id
+repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
+{
+  Id schema, *keyp, *kp;
+  if (!maybe_load_repodata(data, keyname))
+    return 0;
+  if (!solvid2data(data, solvid, &schema))
+    return 0;
+  keyp = data->schemadata + data->schemata[schema];
+  for (kp = keyp; *kp; kp++)
+    if (data->keys[*kp].name == keyname)
+      return data->keys[*kp].type;
+  return 0;
+}
+
+Id
+repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
+{
+  unsigned char *dp;
+  Repokey *key;
+  Id id;
+
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp)
+    return 0;
+  if (key->type == REPOKEY_TYPE_CONSTANTID)
+    return key->size;
+  if (key->type != REPOKEY_TYPE_ID)
+    return 0;
+  dp = data_read_id(dp, &id);
+  return id;
+}
+
+const char *
+repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
+{
+  unsigned char *dp;
+  Repokey *key;
+  Id id;
+
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp)
+    return 0;
+  if (key->type == REPOKEY_TYPE_STR)
+    return (const char *)dp;
+  if (key->type == REPOKEY_TYPE_CONSTANTID)
+    id = key->size;
+  else if (key->type == REPOKEY_TYPE_ID)
+    dp = data_read_id(dp, &id);
+  else
+    return 0;
+  if (data->localpool)
+    return stringpool_id2str(&data->spool, id);
+  return pool_id2str(data->repo->pool, id);
+}
+
+unsigned long long
+repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound)
+{
+  unsigned char *dp;
+  Repokey *key;
+  unsigned int high, low;
+
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp)
+    return notfound;
+  switch (key->type)
+    {
+    case REPOKEY_TYPE_NUM:
+      data_read_num64(dp, &low, &high);
+      return (unsigned long long)high << 32 | low;
+    case REPOKEY_TYPE_CONSTANT:
+      return key->size;
+    default:
+      return notfound;
+    }
+}
+
+int
+repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
+{
+  return repodata_lookup_type(data, solvid, keyname) == REPOKEY_TYPE_VOID ? 1 : 0;
+}
+
+const unsigned char *
+repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
+{
+  unsigned char *dp;
+  Repokey *key;
+
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp)
+    return 0;
+  switch (key->type)
+    {
+    case_CHKSUM_TYPES:
+      break;
+    default:
+      return 0;
+    }
+  *typep = key->type;
+  return dp;
+}
+
+int
+repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
+{
+  unsigned char *dp;
+  Repokey *key;
+  Id id;
+  int eof = 0;
+
+  queue_empty(q);
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp || key->type != REPOKEY_TYPE_IDARRAY)
+    return 0;
+  for (;;)
+    {
+      dp = data_read_ideof(dp, &id, &eof);
+      queue_push(q, id);
+      if (eof)
+       break;
+    }
+  return 1;
+}
+
+const void *
+repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
+{
+  unsigned char *dp;
+  Repokey *key;
+  Id len;
+
+  dp = find_key_data(data, solvid, keyname, &key);
+  if (!dp || key->type != REPOKEY_TYPE_BINARY)
+    {
+      *lenp = 0;
+      return 0;
+    }
+  dp = data_read_id(dp, &len);
+  *lenp = len;
+  return dp;
+}
+
+/* highly specialized function to speed up fileprovides adding.
+ * - repodata must be available
+ * - solvid must be >= data->start and < data->end
+ * - returns NULL is not found, a "" entry if wrong type
+ * - also returns wrong type for REPOKEY_TYPE_DELETED
+ */
+const unsigned char *
+repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname)
+{
+  static unsigned char wrongtype[2] = { 0x00 /* dir id 0 */, 0 /* "" */ };
+  unsigned char *dp;
+  Id schema, *keyp, *kp;
+  Repokey *key;
+
+  if (!data->incoredata || !data->incoreoffset[solvid - data->start])
+    return 0;
+  dp = data->incoredata + data->incoreoffset[solvid - data->start];
+  dp = data_read_id(dp, &schema);
+  keyp = data->schemadata + data->schemata[schema];
+  for (kp = keyp; *kp; kp++)
+    if (data->keys[*kp].name == keyname)
+      break;
+  if (!*kp)
+    return 0;
+  key = data->keys + *kp;
+  if (key->type != REPOKEY_TYPE_DIRSTRARRAY)
+    return wrongtype;
+  dp = forward_to_key(data, *kp, keyp, dp);
+  if (key->storage == KEY_STORAGE_INCORE)
+    return dp;
+  if (key->storage == KEY_STORAGE_VERTICAL_OFFSET && dp)
+    {
+      Id off, len;
+      dp = data_read_id(dp, &off);
+      data_read_id(dp, &len);
+      return get_vertical_data(data, key, off, len);
+    }
+  return 0;
+}
+
+/* id translation functions */
+
+Id
+repodata_globalize_id(Repodata *data, Id id, int create)
+{
+  if (!id || !data || !data->localpool)
+    return id;
+  return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
+}
+
+Id
+repodata_localize_id(Repodata *data, Id id, int create)
+{
+  if (!id || !data || !data->localpool)
+    return id;
+  return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
+}
+
+Id
+repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
+{
+  const char *s;
+  if (!id || !data || !fromdata)
+    return id;
+  if (data == fromdata || (!data->localpool && !fromdata->localpool))
+    return id;
+  if (fromdata->localpool)
+    s = stringpool_id2str(&fromdata->spool, id);
+  else
+    s = pool_id2str(data->repo->pool, id);
+  if (data->localpool)
+    return stringpool_str2id(&data->spool, s, create);
+  else
+    return pool_str2id(data->repo->pool, s, create);
+}
+
+Id
+repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache)
+{
+  Id parent, compid;
+  if (!dir)
+    {
+      /* make sure that the dirpool has an entry */
+      if (create && !data->dirpool.ndirs)
+        dirpool_add_dir(&data->dirpool, 0, 0, create);
+      return 0;
+    }
+  parent = dirpool_parent(&fromdata->dirpool, dir);
+  if (parent)
+    {
+      if (!(parent = repodata_translate_dir(data, fromdata, parent, create, cache)))
+       return 0;
+    }
+  compid = dirpool_compid(&fromdata->dirpool, dir);
+  if (compid > 1 && (data->localpool || fromdata->localpool))
+    {
+      if (!(compid = repodata_translate_id(data, fromdata, compid, create)))
+       return 0;
+    }
+  if (!(compid = dirpool_add_dir(&data->dirpool, parent, compid, create)))
+    return 0;
+  if (cache)
+    {
+      cache[(dir & 255) * 2] = dir;
+      cache[(dir & 255) * 2 + 1] = compid;
+    }
+  return compid;
+}
+
+/************************************************************************
+ * uninternalized lookup / search
+ */
+
+static void
+data_fetch_uninternalized(Repodata *data, Repokey *key, Id value, KeyValue *kv)
+{
+  Id *array;
+  kv->eof = 1;
+  switch (key->type)
+    {
+    case REPOKEY_TYPE_STR:
+      kv->str = (const char *)data->attrdata + value;
+      return;
+    case REPOKEY_TYPE_CONSTANT:
+      kv->num2 = 0;
+      kv->num = key->size;
+      return;
+    case REPOKEY_TYPE_CONSTANTID:
+      kv->id = key->size;
+      return;
+    case REPOKEY_TYPE_NUM:
+      kv->num2 = 0;
+      kv->num = value;
+      if (value & 0x80000000)
+       {
+         kv->num = (unsigned int)data->attrnum64data[value ^ 0x80000000];
+         kv->num2 = (unsigned int)(data->attrnum64data[value ^ 0x80000000] >> 32);
+       }
+      return;
+    case_CHKSUM_TYPES:
+      kv->num = 0;     /* not stringified */
+      kv->str = (const char *)data->attrdata + value;
+      return;
+    case REPOKEY_TYPE_BINARY:
+      kv->str = (const char *)data_read_id(data->attrdata + value, (Id *)&kv->num);
+      return;
+    case REPOKEY_TYPE_IDARRAY:
+      array = data->attriddata + (value + kv->entry);
+      kv->id = array[0];
+      kv->eof = array[1] ? 0 : 1;
+      return;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      kv->num = 0;     /* not stringified */
+      array = data->attriddata + (value + kv->entry * 2);
+      kv->id = array[0];
+      kv->str = (const char *)data->attrdata + array[1];
+      kv->eof = array[2] ? 0 : 1;
+      return;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      array = data->attriddata + (value + kv->entry * 3);
+      kv->id = array[0];
+      kv->num = array[1];
+      kv->num2 = array[2];
+      kv->eof = array[3] ? 0 : 1;
+      return;
+    case REPOKEY_TYPE_FIXARRAY:
+    case REPOKEY_TYPE_FLEXARRAY:
+      array = data->attriddata + (value + kv->entry);
+      kv->id = array[0];               /* the handle */
+      kv->eof = array[1] ? 0 : 1;
+      return;
+    default:
+      kv->id = value;
+      return;
+    }
+}
+
+Repokey *
+repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, KeyValue *kv)
+{
+  Id *ap;
+  if (!data->attrs || solvid < data->start || solvid >= data->end)
+    return 0;
+  ap = data->attrs[solvid - data->start];
+  if (!ap)
+    return 0;
+  for (; *ap; ap += 2)
+    {
+      Repokey *key = data->keys + *ap;
+      if (key->name != keyname)
+       continue;
+      data_fetch_uninternalized(data, key, ap[1], kv);
+      return key;
+    }
+  return 0;
+}
+
+void
+repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  Id *ap;
+  int stop;
+  Solvable *s;
+  KeyValue kv;
+
+  if (!data->attrs || solvid < data->start || solvid >= data->end)
+    return;
+  ap = data->attrs[solvid - data->start];
+  if (!ap)
+    return;
+  for (; *ap; ap += 2)
+    {
+      Repokey *key = data->keys + *ap;
+      if (keyname && key->name != keyname)
+       continue;
+      s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
+      kv.entry = 0;
+      do
+       {
+         data_fetch_uninternalized(data, key, ap[1], &kv);
+         stop = callback(cbdata, s, data, key, &kv);
+         kv.entry++;
+       }
+      while (!kv.eof && !stop);
+      if (keyname || stop > SEARCH_NEXT_KEY)
+       return;
+    }
+}
+
+/************************************************************************
+ * data search
+ */
+
+
+const char *
+repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
+{
+  switch (key->type)
+    {
+    case REPOKEY_TYPE_ID:
+    case REPOKEY_TYPE_CONSTANTID:
+    case REPOKEY_TYPE_IDARRAY:
+      if (data && data->localpool)
+       kv->str = stringpool_id2str(&data->spool, kv->id);
+      else
+       kv->str = pool_id2str(pool, kv->id);
+      if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE && (key->name == SOLVABLE_NAME || key->type == REPOKEY_TYPE_IDARRAY))
+       {
+         const char *s;
+         for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
+           ;
+         if (*s == ':' && s > kv->str)
+           kv->str = s + 1;
+       }
+      return kv->str;
+    case REPOKEY_TYPE_STR:
+      return kv->str;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      if (!(flags & SEARCH_FILES))
+       return kv->str; /* match just the basename */
+      if (kv->num)
+       return kv->str; /* already stringified */
+      /* Put the full filename into kv->str.  */
+      kv->str = repodata_dir2str(data, kv->id, kv->str);
+      kv->num = 1;     /* mark stringification */
+      return kv->str;
+    case_CHKSUM_TYPES:
+      if (!(flags & SEARCH_CHECKSUMS))
+       return 0;       /* skip em */
+      if (kv->num)
+       return kv->str; /* already stringified */
+      kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
+      kv->num = 1;     /* mark stringification */
+      return kv->str;
+    default:
+      return 0;
+    }
+}
+
+
+/* this is an internal hack to pass the parent kv to repodata_search_keyskip */
+struct subschema_data {
+  void *cbdata;
+  Id solvid;
+  KeyValue *parent;
+};
+
+void
+repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata);
+}
+
+static int
+repodata_search_array(Repodata *data, Id solvid, Id keyname, int flags, Repokey *key, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  Solvable *s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
+  unsigned char *dp = (unsigned char *)kv->str;
+  int stop;
+  Id schema = 0;
+
+  if (!dp || kv->entry != -1)
+    return 0;
+  while (++kv->entry < kv->num)
+    {
+      if (kv->entry)
+       dp = data_skip_schema(data, dp, schema);
+      if (kv->entry == 0 || key->type == REPOKEY_TYPE_FLEXARRAY)
+       dp = data_read_id(dp, &schema);
+      kv->id = schema;
+      kv->str = (const char *)dp;
+      kv->eof = kv->entry == kv->num - 1 ? 1 : 0;
+      stop = callback(cbdata, s, data, key, kv);
+      if (stop && stop != SEARCH_ENTERSUB)
+       return stop;
+      if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
+        repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata);
+    }
+  if ((flags & SEARCH_ARRAYSENTINEL) != 0)
+    {
+      if (kv->entry)
+       dp = data_skip_schema(data, dp, schema);
+      kv->id = 0;
+      kv->str = (const char *)dp;
+      kv->eof = 2;
+      return callback(cbdata, s, data, key, kv);
+    }
+  return 0;
+}
+
+/* search a specific repodata */
+void
+repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  Id schema;
+  Repokey *key;
+  Id keyid, *kp, *keyp;
+  unsigned char *dp, *ddp;
+  int onekey = 0;
+  int stop;
+  KeyValue kv;
+  Solvable *s;
+
+  if (!maybe_load_repodata(data, keyname))
+    return;
+  if ((flags & SEARCH_SUBSCHEMA) != 0)
+    {
+      flags ^= SEARCH_SUBSCHEMA;
+      kv.parent = (KeyValue *)keyskip;
+      keyskip = 0;
+      schema = kv.parent->id;
+      dp = (unsigned char *)kv.parent->str;
+    }
+  else
+    {
+      schema = 0;
+      dp = solvid2data(data, solvid, &schema);
+      if (!dp)
+       return;
+      kv.parent = 0;
+    }
+  s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
+  keyp = data->schemadata + data->schemata[schema];
+  if (keyname)
+    {
+      /* search for a specific key */
+      for (kp = keyp; *kp; kp++)
+       if (data->keys[*kp].name == keyname)
+         break;
+      if (!*kp)
+       return;
+      dp = forward_to_key(data, *kp, keyp, dp);
+      if (!dp)
+       return;
+      keyp = kp;
+      onekey = 1;
+    }
+  while ((keyid = *keyp++) != 0)
+    {
+      stop = 0;
+      key = data->keys + keyid;
+      ddp = get_data(data, key, &dp, *keyp && !onekey ? 1 : 0);
+
+      if (keyskip && (key->name >= keyskip[0] || keyskip[3 + key->name] != keyskip[1] + data->repodataid))
+       {
+         if (onekey)
+           return;
+         continue;
+       }
+      if (key->type == REPOKEY_TYPE_DELETED && !(flags & SEARCH_KEEP_TYPE_DELETED))
+       {
+         if (onekey)
+           return;
+         continue;
+       }
+      if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
+       {
+         kv.entry = -1;
+         ddp = data_read_id(ddp, (Id *)&kv.num);
+         kv.str = (const char *)ddp;
+         stop = repodata_search_array(data, solvid, 0, flags, key, &kv, callback, cbdata);
+         if (onekey || stop > SEARCH_NEXT_KEY)
+           return;
+         continue;
+       }
+      kv.entry = 0;
+      do
+       {
+         ddp = data_fetch(ddp, &kv, key);
+         if (!ddp)
+           break;
+         stop = callback(cbdata, s, data, key, &kv);
+         kv.entry++;
+       }
+      while (!kv.eof && !stop);
+      if (onekey || stop > SEARCH_NEXT_KEY)
+       return;
+    }
+}
+
+void
+repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  repodata_search_keyskip(data, solvid, keyname, flags, 0, callback, cbdata);
+}
+
+void
+repodata_setpos_kv(Repodata *data, KeyValue *kv)
+{
+  Pool *pool = data->repo->pool;
+  if (!kv)
+    pool_clear_pos(pool);
+  else
+    {
+      pool->pos.repo = data->repo;
+      pool->pos.repodataid = data - data->repo->repodata;
+      pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
+      pool->pos.schema = kv->id;
+    }
+}
+
+/************************************************************************
+ * data iterator functions
+ */
+
+static inline Id *
+solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
+{
+  kv->id = keyname;
+  switch (keyname)
+    {
+    case SOLVABLE_NAME:
+      kv->eof = 1;
+      return &s->name;
+    case SOLVABLE_ARCH:
+      kv->eof = 1;
+      return &s->arch;
+    case SOLVABLE_EVR:
+      kv->eof = 1;
+      return &s->evr;
+    case SOLVABLE_VENDOR:
+      kv->eof = 1;
+      return &s->vendor;
+    case SOLVABLE_PROVIDES:
+      kv->eof = 0;
+      return s->provides ? s->repo->idarraydata + s->provides : 0;
+    case SOLVABLE_OBSOLETES:
+      kv->eof = 0;
+      return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
+    case SOLVABLE_CONFLICTS:
+      kv->eof = 0;
+      return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
+    case SOLVABLE_REQUIRES:
+      kv->eof = 0;
+      return s->requires ? s->repo->idarraydata + s->requires : 0;
+    case SOLVABLE_RECOMMENDS:
+      kv->eof = 0;
+      return s->recommends ? s->repo->idarraydata + s->recommends : 0;
+    case SOLVABLE_SUPPLEMENTS:
+      kv->eof = 0;
+      return s->supplements ? s->repo->idarraydata + s->supplements : 0;
+    case SOLVABLE_SUGGESTS:
+      kv->eof = 0;
+      return s->suggests ? s->repo->idarraydata + s->suggests : 0;
+    case SOLVABLE_ENHANCES:
+      kv->eof = 0;
+      return s->enhances ? s->repo->idarraydata + s->enhances : 0;
+    case RPM_RPMDBID:
+      kv->eof = 1;
+      return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
+    default:
+      return 0;
+    }
+}
+
+int
+datamatcher_init(Datamatcher *ma, const char *match, int flags)
+{
+  match = match ? solv_strdup(match) : 0;
+  ma->match = match;
+  ma->flags = flags;
+  ma->error = 0;
+  ma->matchdata = 0;
+  if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
+    {
+      ma->matchdata = solv_calloc(1, sizeof(regex_t));
+      ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
+      if (ma->error)
+       {
+         solv_free(ma->matchdata);
+         ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
+       }
+    }
+  if ((flags & SEARCH_FILES) != 0 && match)
+    {
+      /* prepare basename check */
+      if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
+       {
+         const char *p = strrchr(match, '/');
+         ma->matchdata = (void *)(p ? p + 1 : match);
+       }
+      else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
+       {
+         const char *p;
+         for (p = match + strlen(match) - 1; p >= match; p--)
+           if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
+             break;
+         ma->matchdata = (void *)(p + 1);
+       }
+    }
+  return ma->error;
+}
+
+void
+datamatcher_free(Datamatcher *ma)
+{
+  if (ma->match)
+    ma->match = solv_free((char *)ma->match);
+  if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
+    {
+      regfree(ma->matchdata);
+      solv_free(ma->matchdata);
+    }
+  ma->matchdata = 0;
+}
+
+int
+datamatcher_match(Datamatcher *ma, const char *str)
+{
+  int l;
+  switch ((ma->flags & SEARCH_STRINGMASK))
+    {
+    case SEARCH_SUBSTRING:
+      if (ma->flags & SEARCH_NOCASE)
+       return strcasestr(str, ma->match) != 0;
+      else
+       return strstr(str, ma->match) != 0;
+    case SEARCH_STRING:
+      if (ma->flags & SEARCH_NOCASE)
+       return !strcasecmp(ma->match, str);
+      else
+       return !strcmp(ma->match, str);
+    case SEARCH_STRINGSTART:
+      if (ma->flags & SEARCH_NOCASE)
+        return !strncasecmp(ma->match, str, strlen(ma->match));
+      else
+        return !strncmp(ma->match, str, strlen(ma->match));
+    case SEARCH_STRINGEND:
+      l = strlen(str) - strlen(ma->match);
+      if (l < 0)
+       return 0;
+      if (ma->flags & SEARCH_NOCASE)
+       return !strcasecmp(ma->match, str + l);
+      else
+       return !strcmp(ma->match, str + l);
+    case SEARCH_GLOB:
+      return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
+    case SEARCH_REGEX:
+      return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
+    default:
+      return 0;
+    }
+}
+
+/* check if the matcher can match the provides basename */
+
+int
+datamatcher_checkbasename(Datamatcher *ma, const char *basename)
+{
+  int l;
+  const char *match = ma->matchdata;
+  if (!match)
+    return 1;
+  switch (ma->flags & SEARCH_STRINGMASK)
+    {
+    case SEARCH_STRING:
+      break;
+    case SEARCH_STRINGEND:
+      if (match != ma->match)
+       break;          /* had slash, do exact match on basename */
+      /* FALLTHROUGH */
+    case SEARCH_GLOB:
+      /* check if the basename ends with match */
+      l = strlen(basename) - strlen(match);
+      if (l < 0)
+       return 0;
+      basename += l;
+      break;
+    default:
+      return 1;        /* maybe matches */
+    }
+  if ((ma->flags & SEARCH_NOCASE) != 0)
+    return !strcasecmp(match, basename);
+  else
+    return !strcmp(match, basename);
+}
+
+enum {
+  di_bye,
+
+  di_enterrepo,
+  di_entersolvable,
+  di_enterrepodata,
+  di_enterschema,
+  di_enterkey,
+
+  di_nextattr,
+  di_nextkey,
+  di_nextrepodata,
+  di_nextsolvable,
+  di_nextrepo,
+
+  di_enterarray,
+  di_nextarrayelement,
+
+  di_entersub,
+  di_leavesub,
+
+  di_nextsolvablekey,
+  di_entersolvablekey,
+  di_nextsolvableattr
+};
+
+/* see dataiterator.h for documentation */
+int
+dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
+{
+  memset(di, 0, sizeof(*di));
+  di->pool = pool;
+  di->flags = flags & ~SEARCH_THISSOLVID;
+  if (!pool || (repo && repo->pool != pool))
+    {
+      di->state = di_bye;
+      return -1;
+    }
+  if (match)
+    {
+      int error;
+      if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
+       {
+         di->state = di_bye;
+         return error;
+       }
+    }
+  di->keyname = keyname;
+  di->keynames[0] = keyname;
+  dataiterator_set_search(di, repo, p);
+  return 0;
+}
+
+void
+dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
+{
+  *di = *from;
+  if (di->dupstr)
+    {
+      if (di->dupstr == di->kv.str)
+        di->dupstr = solv_memdup(di->dupstr, di->dupstrn);
+      else
+       {
+         di->dupstr = 0;
+         di->dupstrn = 0;
+       }
+    }
+  memset(&di->matcher, 0, sizeof(di->matcher));
+  if (from->matcher.match)
+    datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
+  if (di->nparents)
+    {
+      /* fix pointers */
+      int i;
+      for (i = 1; i < di->nparents; i++)
+       di->parents[i].kv.parent = &di->parents[i - 1].kv;
+      di->kv.parent = &di->parents[di->nparents - 1].kv;
+    }
+  if (di->oldkeyskip)
+    di->oldkeyskip = solv_memdup2(di->oldkeyskip, 3 + di->oldkeyskip[0], sizeof(Id));
+  if (di->keyskip)
+    di->keyskip = di->oldkeyskip;
+}
+
+int
+dataiterator_set_match(Dataiterator *di, const char *match, int flags)
+{
+  di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
+  datamatcher_free(&di->matcher);
+  memset(&di->matcher, 0, sizeof(di->matcher));
+  if (match)
+    {
+      int error;
+      if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
+       {
+         di->state = di_bye;
+         return error;
+       }
+    }
+  return 0;
+}
+
+void
+dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
+{
+  di->repo = repo;
+  di->repoid = 0;
+  di->flags &= ~SEARCH_THISSOLVID;
+  di->nparents = 0;
+  di->rootlevel = 0;
+  di->repodataid = 1;
+  if (!di->pool->urepos)
+    {
+      di->state = di_bye;
+      return;
+    }
+  if (!repo)
+    {
+      di->repoid = 1;
+      di->repo = di->pool->repos[di->repoid];
+    }
+  di->state = di_enterrepo;
+  if (p)
+    dataiterator_jump_to_solvid(di, p);
+}
+
+void
+dataiterator_set_keyname(Dataiterator *di, Id keyname)
+{
+  di->nkeynames = 0;
+  di->keyname = keyname;
+  di->keynames[0] = keyname;
+}
+
+void
+dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
+{
+  int i;
+
+  if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
+    {
+      di->state = di_bye;      /* sorry */
+      return;
+    }
+  for (i = di->nkeynames + 1; i > 0; i--)
+    di->keynames[i] = di->keynames[i - 1];
+  di->keynames[0] = di->keyname = keyname;
+  di->nkeynames++;
+}
+
+void
+dataiterator_free(Dataiterator *di)
+{
+  if (di->matcher.match)
+    datamatcher_free(&di->matcher);
+  if (di->dupstr)
+    solv_free(di->dupstr);
+  if (di->oldkeyskip)
+    solv_free(di->oldkeyskip);
+}
+
+static unsigned char *
+dataiterator_find_keyname(Dataiterator *di, Id keyname)
+{
+  Id *keyp;
+  Repokey *keys = di->data->keys, *key;
+  unsigned char *dp;
+
+  for (keyp = di->keyp; *keyp; keyp++)
+    if (keys[*keyp].name == keyname)
+      break;
+  if (!*keyp)
+    return 0;
+  key = keys + *keyp;
+  if (key->type == REPOKEY_TYPE_DELETED)
+    return 0;
+  if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
+    return 0;          /* get_data will not work, no need to forward */
+  dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
+  if (!dp)
+    return 0;
+  di->keyp = keyp;
+  return dp;
+}
+
+int
+dataiterator_step(Dataiterator *di)
+{
+  Id schema;
+
+  if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate)
+    {
+      unsigned int ddpoff = di->ddp - di->vert_ddp;
+      di->vert_off += ddpoff;
+      di->vert_len -= ddpoff;
+      di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
+      di->vert_storestate = di->data->storestate;
+      if (!di->ddp)
+       di->state = di_nextkey;
+    }
+  for (;;)
+    {
+      switch (di->state)
+       {
+       case di_enterrepo: di_enterrepo:
+         if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
+           goto di_nextrepo;
+         if (!(di->flags & SEARCH_THISSOLVID))
+           {
+             di->solvid = di->repo->start - 1; /* reset solvid iterator */
+             goto di_nextsolvable;
+           }
+         /* FALLTHROUGH */
+
+       case di_entersolvable: di_entersolvable:
+         if (!di->repodataid)
+           goto di_enterrepodata;      /* POS case, repodata is set */
+         if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
+           {
+             extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
+             di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
+             di->data = 0;
+             goto di_entersolvablekey;
+           }
+
+         if (di->keyname)
+           {
+             di->data = di->keyname == SOLVABLE_FILELIST ? repo_lookup_filelist_repodata(di->repo, di->solvid, &di->matcher) : repo_lookup_repodata_opt(di->repo, di->solvid, di->keyname);
+             if (!di->data)
+               goto di_nextsolvable;
+             di->repodataid = di->data - di->repo->repodata;
+             di->keyskip = 0;
+             goto di_enterrepodata;
+           }
+       di_leavesolvablekey:
+         di->repodataid = 1;   /* reset repodata iterator */
+         di->keyskip = repo_create_keyskip(di->repo, di->solvid, &di->oldkeyskip);
+         /* FALLTHROUGH */
+
+       case di_enterrepodata: di_enterrepodata:
+         if (di->repodataid)
+           {
+             if (di->repodataid >= di->repo->nrepodata)
+               goto di_nextsolvable;
+             di->data = di->repo->repodata + di->repodataid;
+           }
+         if (!maybe_load_repodata(di->data, di->keyname))
+           goto di_nextrepodata;
+         di->dp = solvid2data(di->data, di->solvid, &schema);
+         if (!di->dp)
+           goto di_nextrepodata;
+         if (di->solvid == SOLVID_POS)
+           di->solvid = di->pool->pos.solvid;
+         /* reset key iterator */
+         di->keyp = di->data->schemadata + di->data->schemata[schema];
+         /* FALLTHROUGH */
+
+       case di_enterschema: di_enterschema:
+         if (di->keyname)
+           di->dp = dataiterator_find_keyname(di, di->keyname);
+         if (!di->dp || !*di->keyp)
+           {
+             if (di->kv.parent)
+               goto di_leavesub;
+             goto di_nextrepodata;
+           }
+         /* FALLTHROUGH */
+
+       case di_enterkey: di_enterkey:
+         di->kv.entry = -1;
+         di->key = di->data->keys + *di->keyp;
+         if (!di->dp)
+           goto di_nextkey;
+         /* this is get_data() modified to store vert_ data */
+         if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+           {
+             Id off, len;
+             di->dp = data_read_id(di->dp, &off);
+             di->dp = data_read_id(di->dp, &len);
+             di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
+             di->vert_off = off;
+             di->vert_len = len;
+             di->vert_storestate = di->data->storestate;
+           }
+         else if (di->key->storage == KEY_STORAGE_INCORE)
+           {
+             di->ddp = di->dp;         /* start of data */
+             if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
+               di->dp = data_skip_key(di->data, di->dp, di->key);      /* advance to next key */
+           }
+         else
+           di->ddp = 0;
+         if (!di->ddp)
+           goto di_nextkey;
+         if (di->keyskip && (di->key->name >= di->keyskip[0] || di->keyskip[3 + di->key->name] != di->keyskip[1] + di->data->repodataid))
+           goto di_nextkey;
+          if (di->key->type == REPOKEY_TYPE_DELETED && !(di->flags & SEARCH_KEEP_TYPE_DELETED))
+           goto di_nextkey;
+         if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
+           goto di_enterarray;
+         if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
+           goto di_nextkey;
+         /* FALLTHROUGH */
+
+       case di_nextattr:
+          di->kv.entry++;
+         di->ddp = data_fetch(di->ddp, &di->kv, di->key);
+         di->state = di->kv.eof ? di_nextkey : di_nextattr;
+         break;
+
+       case di_nextkey: di_nextkey:
+         if (!di->keyname && *++di->keyp)
+           goto di_enterkey;
+         if (di->kv.parent)
+           goto di_leavesub;
+         /* FALLTHROUGH */
+
+       case di_nextrepodata: di_nextrepodata:
+         if (!di->keyname && di->repodataid && ++di->repodataid < di->repo->nrepodata)
+             goto di_enterrepodata;
+         /* FALLTHROUGH */
+
+       case di_nextsolvable: di_nextsolvable:
+         if (!(di->flags & SEARCH_THISSOLVID))
+           {
+             if (di->solvid < 0)
+               di->solvid = di->repo->start;
+             else
+               di->solvid++;
+             for (; di->solvid < di->repo->end; di->solvid++)
+               {
+                 if (di->pool->solvables[di->solvid].repo == di->repo)
+                   goto di_entersolvable;
+               }
+           }
+         /* FALLTHROUGH */
+
+       case di_nextrepo: di_nextrepo:
+         if (di->repoid > 0)
+           {
+             di->repoid++;
+             di->repodataid = 1;
+             if (di->repoid < di->pool->nrepos)
+               {
+                 di->repo = di->pool->repos[di->repoid];
+                 goto di_enterrepo;
+               }
+           }
+       /* FALLTHROUGH */
+
+       case di_bye: di_bye:
+         di->state = di_bye;
+         return 0;
+
+       case di_enterarray: di_enterarray:
+         if (di->key->name == REPOSITORY_SOLVABLES)
+           goto di_nextkey;
+         di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
+         di->kv.eof = 0;
+         di->kv.entry = -1;
+         /* FALLTHROUGH */
+
+       case di_nextarrayelement: di_nextarrayelement:
+         di->kv.entry++;
+         if (di->kv.entry)
+           di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
+         if (di->kv.entry == di->kv.num)
+           {
+             if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
+               goto di_nextkey;
+             if (!(di->flags & SEARCH_ARRAYSENTINEL))
+               goto di_nextkey;
+             di->kv.str = (char *)di->ddp;
+             di->kv.eof = 2;
+             di->state = di_nextkey;
+             break;
+           }
+         if (di->kv.entry == di->kv.num - 1)
+           di->kv.eof = 1;
+         if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
+           di->ddp = data_read_id(di->ddp, &di->kv.id);
+         di->kv.str = (char *)di->ddp;
+         if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
+           goto di_entersub;
+         if ((di->flags & SEARCH_SUB) != 0)
+           di->state = di_entersub;
+         else
+           di->state = di_nextarrayelement;
+         break;
+
+       case di_entersub: di_entersub:
+         if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
+           goto di_nextarrayelement;   /* sorry, full */
+         di->parents[di->nparents].kv = di->kv;
+         di->parents[di->nparents].dp = di->dp;
+         di->parents[di->nparents].keyp = di->keyp;
+         di->dp = (unsigned char *)di->kv.str;
+         di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
+         memset(&di->kv, 0, sizeof(di->kv));
+         di->kv.parent = &di->parents[di->nparents].kv;
+         di->nparents++;
+         di->keyname = di->keynames[di->nparents - di->rootlevel];
+         goto di_enterschema;
+
+       case di_leavesub: di_leavesub:
+         if (di->nparents - 1 < di->rootlevel)
+           goto di_bye;
+         di->nparents--;
+         di->dp = di->parents[di->nparents].dp;
+         di->kv = di->parents[di->nparents].kv;
+         di->keyp = di->parents[di->nparents].keyp;
+         di->key = di->data->keys + *di->keyp;
+         di->ddp = (unsigned char *)di->kv.str;
+         di->keyname = di->keynames[di->nparents - di->rootlevel];
+         goto di_nextarrayelement;
+
+        /* special solvable attr handling follows */
+
+       case di_nextsolvablekey: di_nextsolvablekey:
+         if (di->keyname)
+           goto di_nextsolvable;
+         if (di->key->name == RPM_RPMDBID)     /* reached end of list? */
+           goto di_leavesolvablekey;
+         di->key++;
+         /* FALLTHROUGH */
+
+       case di_entersolvablekey: di_entersolvablekey:
+         di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
+         if (!di->idp || !*di->idp)
+           goto di_nextsolvablekey;
+         if (di->kv.eof)
+           {
+             /* not an array */
+             di->kv.id = *di->idp;
+             di->kv.num = *di->idp;    /* for rpmdbid */
+             di->kv.num2 = 0;          /* for rpmdbid */
+             di->kv.entry = 0;
+             di->state = di_nextsolvablekey;
+             break;
+           }
+         di->kv.entry = -1;
+         /* FALLTHROUGH */
+
+       case di_nextsolvableattr:
+         di->state = di_nextsolvableattr;
+         di->kv.id = *di->idp++;
+         di->kv.entry++;
+         if (!*di->idp)
+           {
+             di->kv.eof = 1;
+             di->state = di_nextsolvablekey;
+           }
+         break;
+
+       }
+
+      /* we have a potential match */
+      if (di->matcher.match)
+       {
+         const char *str;
+         /* simple pre-check so that we don't need to stringify */
+         if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
+           if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
+             continue;
+         /* now stringify so that we can do the matching */
+         if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
+           {
+             if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
+               return 1;
+             continue;
+           }
+         if (!datamatcher_match(&di->matcher, str))
+           continue;
+       }
+      else
+       {
+         /* stringify filelist if requested */
+         if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
+           repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
+       }
+      /* found something! */
+      return 1;
+    }
+}
+
+void
+dataiterator_entersub(Dataiterator *di)
+{
+  if (di->state == di_nextarrayelement)
+    di->state = di_entersub;
+}
+
+void
+dataiterator_setpos(Dataiterator *di)
+{
+  if (di->kv.eof == 2)
+    {
+      pool_clear_pos(di->pool);
+      return;
+    }
+  di->pool->pos.solvid = di->solvid;
+  di->pool->pos.repo = di->repo;
+  di->pool->pos.repodataid = di->data - di->repo->repodata;
+  di->pool->pos.schema = di->kv.id;
+  di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
+}
+
+void
+dataiterator_setpos_parent(Dataiterator *di)
+{
+  if (!di->kv.parent || di->kv.parent->eof == 2)
+    {
+      pool_clear_pos(di->pool);
+      return;
+    }
+  di->pool->pos.solvid = di->solvid;
+  di->pool->pos.repo = di->repo;
+  di->pool->pos.repodataid = di->data - di->repo->repodata;
+  di->pool->pos.schema = di->kv.parent->id;
+  di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
+}
+
+/* clones just the position, not the search keys/matcher */
+void
+dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
+{
+  di->state = from->state;
+  di->flags &= ~SEARCH_THISSOLVID;
+  di->flags |= (from->flags & SEARCH_THISSOLVID);
+  di->repo = from->repo;
+  di->data = from->data;
+  di->dp = from->dp;
+  di->ddp = from->ddp;
+  di->idp = from->idp;
+  di->keyp = from->keyp;
+  di->key = from->key;
+  di->kv = from->kv;
+  di->repodataid = from->repodataid;
+  di->solvid = from->solvid;
+  di->repoid = from->repoid;
+  di->rootlevel = from->rootlevel;
+  memcpy(di->parents, from->parents, sizeof(from->parents));
+  di->nparents = from->nparents;
+  if (di->nparents)
+    {
+      int i;
+      for (i = 1; i < di->nparents; i++)
+       di->parents[i].kv.parent = &di->parents[i - 1].kv;
+      di->kv.parent = &di->parents[di->nparents - 1].kv;
+    }
+  di->dupstr = 0;
+  di->dupstrn = 0;
+  if (from->dupstr && from->dupstr == from->kv.str)
+    {
+      di->dupstrn = from->dupstrn;
+      di->dupstr = solv_memdup(from->dupstr, from->dupstrn);
+    }
+}
+
+void
+dataiterator_seek(Dataiterator *di, int whence)
+{
+  if ((whence & DI_SEEK_STAY) != 0)
+    di->rootlevel = di->nparents;
+  switch (whence & ~DI_SEEK_STAY)
+    {
+    case DI_SEEK_CHILD:
+      if (di->state != di_nextarrayelement)
+       break;
+      if ((whence & DI_SEEK_STAY) != 0)
+       di->rootlevel = di->nparents + 1;       /* XXX: dangerous! */
+      di->state = di_entersub;
+      break;
+    case DI_SEEK_PARENT:
+      if (!di->nparents)
+       {
+         di->state = di_bye;
+         break;
+       }
+      di->nparents--;
+      if (di->rootlevel > di->nparents)
+       di->rootlevel = di->nparents;
+      di->dp = di->parents[di->nparents].dp;
+      di->kv = di->parents[di->nparents].kv;
+      di->keyp = di->parents[di->nparents].keyp;
+      di->key = di->data->keys + *di->keyp;
+      di->ddp = (unsigned char *)di->kv.str;
+      di->keyname = di->keynames[di->nparents - di->rootlevel];
+      di->state = di_nextarrayelement;
+      break;
+    case DI_SEEK_REWIND:
+      if (!di->nparents)
+       {
+         di->state = di_bye;
+         break;
+       }
+      di->dp = (unsigned char *)di->kv.parent->str;
+      di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
+      di->state = di_enterschema;
+      break;
+    default:
+      break;
+    }
+}
+
+void
+dataiterator_skip_attribute(Dataiterator *di)
+{
+  if (di->state == di_nextsolvableattr)
+    di->state = di_nextsolvablekey;
+  else
+    di->state = di_nextkey;
+}
+
+void
+dataiterator_skip_solvable(Dataiterator *di)
+{
+  di->nparents = 0;
+  di->kv.parent = 0;
+  di->rootlevel = 0;
+  di->keyname = di->keynames[0];
+  di->state = di_nextsolvable;
+}
+
+void
+dataiterator_skip_repo(Dataiterator *di)
+{
+  di->nparents = 0;
+  di->kv.parent = 0;
+  di->rootlevel = 0;
+  di->keyname = di->keynames[0];
+  di->state = di_nextrepo;
+}
+
+void
+dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
+{
+  di->nparents = 0;
+  di->kv.parent = 0;
+  di->rootlevel = 0;
+  di->keyname = di->keynames[0];
+  if (solvid == SOLVID_POS)
+    {
+      di->repo = di->pool->pos.repo;
+      if (!di->repo)
+       {
+         di->state = di_bye;
+         return;
+       }
+      di->repoid = 0;
+      if (!di->pool->pos.repodataid && di->pool->pos.solvid == SOLVID_META) {
+       solvid = SOLVID_META;           /* META pos hack */
+      } else {
+        di->data = di->repo->repodata + di->pool->pos.repodataid;
+        di->repodataid = 0;
+      }
+    }
+  else if (solvid > 0)
+    {
+      di->repo = di->pool->solvables[solvid].repo;
+      di->repoid = 0;
+    }
+  if (di->repoid > 0)
+    {
+      if (!di->pool->urepos)
+       {
+         di->state = di_bye;
+         return;
+       }
+      di->repoid = 1;
+      di->repo = di->pool->repos[di->repoid];
+    }
+  if (solvid != SOLVID_POS)
+    di->repodataid = 1;
+  di->solvid = solvid;
+  if (solvid)
+    di->flags |= SEARCH_THISSOLVID;
+  di->state = di_enterrepo;
+}
+
+void
+dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
+{
+  di->nparents = 0;
+  di->kv.parent = 0;
+  di->rootlevel = 0;
+  di->repo = repo;
+  di->repoid = 0;      /* 0 means stay at repo */
+  di->repodataid = 1;
+  di->solvid = 0;
+  di->flags &= ~SEARCH_THISSOLVID;
+  di->state = di_enterrepo;
+}
+
+int
+dataiterator_match(Dataiterator *di, Datamatcher *ma)
+{
+  const char *str;
+  if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
+    return 0;
+  return ma ? datamatcher_match(ma, str) : 1;
+}
+
+void
+dataiterator_strdup(Dataiterator *di)
+{
+  int l = -1;
+
+  if (!di->kv.str || di->kv.str == di->dupstr)
+    return;
+  switch (di->key->type)
+    {
+    case_CHKSUM_TYPES:
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      if (di->kv.num)  /* was it stringified into tmp space? */
+        l = strlen(di->kv.str) + 1;
+      break;
+    default:
+      break;
+    }
+  if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+    {
+      switch (di->key->type)
+       {
+       case REPOKEY_TYPE_STR:
+       case REPOKEY_TYPE_DIRSTRARRAY:
+         l = strlen(di->kv.str) + 1;
+         break;
+       case_CHKSUM_TYPES:
+         l = solv_chksum_len(di->key->type);
+         break;
+       case REPOKEY_TYPE_BINARY:
+         l = di->kv.num;
+         break;
+       }
+    }
+  if (l >= 0)
+    {
+      if (!di->dupstrn || di->dupstrn < l)
+       {
+         di->dupstrn = l + 16;
+         di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
+       }
+      if (l)
+        memcpy(di->dupstr, di->kv.str, l);
+      di->kv.str = di->dupstr;
+    }
+}
+
+/************************************************************************
+ * data modify functions
+ */
+
+/* extend repodata so that it includes solvables p */
+void
+repodata_extend(Repodata *data, Id p)
+{
+  if (data->start == data->end)
+    data->start = data->end = p;
+  if (p >= data->end)
+    {
+      int old = data->end - data->start;
+      int new = p - data->end + 1;
+      if (data->attrs)
+       {
+         data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
+         memset(data->attrs + old, 0, new * sizeof(Id *));
+       }
+      data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
+      memset(data->incoreoffset + old, 0, new * sizeof(Id));
+      data->end = p + 1;
+    }
+  if (p < data->start)
+    {
+      int old = data->end - data->start;
+      int new = data->start - p;
+      if (data->attrs)
+       {
+         data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
+         memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
+         memset(data->attrs, 0, new * sizeof(Id *));
+       }
+      data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
+      memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
+      memset(data->incoreoffset, 0, new * sizeof(Id));
+      data->start = p;
+    }
+}
+
+/* shrink end of repodata */
+void
+repodata_shrink(Repodata *data, int end)
+{
+  int i;
+
+  if (data->end <= end)
+    return;
+  if (data->start >= end)
+    {
+      if (data->attrs)
+       {
+         for (i = 0; i < data->end - data->start; i++)
+           solv_free(data->attrs[i]);
+          data->attrs = solv_free(data->attrs);
+       }
+      data->incoreoffset = solv_free(data->incoreoffset);
+      data->start = data->end = 0;
+      return;
+    }
+  if (data->attrs)
+    {
+      for (i = end; i < data->end; i++)
+       solv_free(data->attrs[i - data->start]);
+      data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
+    }
+  if (data->incoreoffset)
+    data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
+  data->end = end;
+}
+
+/* extend repodata so that it includes solvables from start to start + num - 1 */
+void
+repodata_extend_block(Repodata *data, Id start, Id num)
+{
+  if (!num)
+    return;
+  if (!data->incoreoffset)
+    {
+      /* this also means that data->attrs is NULL */
+      data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
+      data->start = start;
+      data->end = start + num;
+      return;
+    }
+  repodata_extend(data, start);
+  if (num > 1)
+    repodata_extend(data, start + num - 1);
+}
+
+/**********************************************************************/
+
+
+#define REPODATA_ATTRS_BLOCK 31
+#define REPODATA_ATTRDATA_BLOCK 1023
+#define REPODATA_ATTRIDDATA_BLOCK 63
+#define REPODATA_ATTRNUM64DATA_BLOCK 15
+
+
+Id
+repodata_new_handle(Repodata *data)
+{
+  if (!data->nxattrs)
+    {
+      data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
+      data->nxattrs = 2;       /* -1: SOLVID_META */
+    }
+  data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
+  data->xattrs[data->nxattrs] = 0;
+  return -(data->nxattrs++);
+}
+
+static inline Id **
+repodata_get_attrp(Repodata *data, Id handle)
+{
+  if (handle < 0)
+    {
+      if (handle == SOLVID_META && !data->xattrs)
+       {
+         data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
+          data->nxattrs = 2;
+       }
+      return data->xattrs - handle;
+    }
+  if (handle < data->start || handle >= data->end)
+    repodata_extend(data, handle);
+  if (!data->attrs)
+    data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
+  return data->attrs + (handle - data->start);
+}
+
+static void
+repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
+{
+  Id *pp;
+  Id *ap, **app;
+  int i;
+
+  app = repodata_get_attrp(data, handle);
+  ap = *app;
+  i = 0;
+  if (ap)
+    {
+      /* Determine equality based on the name only, allows us to change
+         type (when overwrite is set), and makes TYPE_CONSTANT work.  */
+      for (pp = ap; *pp; pp += 2)
+        if (data->keys[*pp].name == data->keys[keyid].name)
+          break;
+      if (*pp)
+        {
+         if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
+           {
+             pp[0] = keyid;
+              pp[1] = val;
+           }
+          return;
+        }
+      i = pp - ap;
+    }
+  ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
+  *app = ap;
+  pp = ap + i;
+  *pp++ = keyid;
+  *pp++ = val;
+  *pp = 0;
+}
+
+
+static void
+repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
+{
+  Id keyid;
+
+  keyid = repodata_key2id(data, key, 1);
+  repodata_insert_keyid(data, solvid, keyid, val, 1);
+}
+
+void
+repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
+{
+  Repokey key;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_ID;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, id);
+}
+
+void
+repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
+{
+  Repokey key;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_NUM;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  if (num >= 0x80000000)
+    {
+      data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
+      data->attrnum64data[data->attrnum64datalen] = num;
+      num = 0x80000000 | data->attrnum64datalen++;
+    }
+  repodata_set(data, solvid, &key, (Id)num);
+}
+
+void
+repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
+{
+  Repokey key;
+  Id id;
+  if (data->localpool)
+    id = stringpool_str2id(&data->spool, str, 1);
+  else
+    id = pool_str2id(data->repo->pool, str, 1);
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_ID;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, id);
+}
+
+void
+repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
+{
+  Repokey key;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_CONSTANT;
+  key.size = constant;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, 0);
+}
+
+void
+repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
+{
+  Repokey key;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_CONSTANTID;
+  key.size = id;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, 0);
+}
+
+void
+repodata_set_void(Repodata *data, Id solvid, Id keyname)
+{
+  Repokey key;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_VOID;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, 0);
+}
+
+void
+repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
+{
+  Repokey key;
+  int l;
+
+  l = strlen(str) + 1;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_STR;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
+  memcpy(data->attrdata + data->attrdatalen, str, l);
+  repodata_set(data, solvid, &key, data->attrdatalen);
+  data->attrdatalen += l;
+}
+
+void
+repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
+{
+  Repokey key;
+  unsigned char *dp;
+
+  if (len < 0)
+    return;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_BINARY;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
+  dp = data->attrdata + data->attrdatalen;
+  if (len >= (1 << 14))
+    {
+      if (len >= (1 << 28))
+        *dp++ = (len >> 28) | 128;
+      if (len >= (1 << 21))
+        *dp++ = (len >> 21) | 128;
+      *dp++ = (len >> 14) | 128;
+    }
+  if (len >= (1 << 7))
+    *dp++ = (len >> 7) | 128;
+  *dp++ = len & 127;
+  if (len)
+    memcpy(dp, buf, len);
+  repodata_set(data, solvid, &key, data->attrdatalen);
+  data->attrdatalen = dp + len - data->attrdata;
+}
+
+/* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
+ * so that the caller can append entrysize new elements plus the termination zero there */
+static void
+repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
+{
+  int oldsize;
+  Id *ida, *pp, **ppp;
+
+  /* check if it is the same as last time, this speeds things up a lot */
+  if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
+    {
+      /* great! just append the new data */
+      data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      data->attriddatalen--;   /* overwrite terminating 0  */
+      data->lastdatalen += entrysize;
+      return;
+    }
+
+  ppp = repodata_get_attrp(data, handle);
+  pp = *ppp;
+  if (pp)
+    {
+      for (; *pp; pp += 2)
+        if (data->keys[*pp].name == keyname)
+          break;
+    }
+  if (!pp || !*pp || data->keys[*pp].type != keytype)
+    {
+      /* not found. allocate new key */
+      Repokey key;
+      Id keyid;
+      key.name = keyname;
+      key.type = keytype;
+      key.size = 0;
+      key.storage = KEY_STORAGE_INCORE;
+      data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      keyid = repodata_key2id(data, &key, 1);
+      repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
+      data->lasthandle = handle;
+      data->lastkey = keyid;
+      data->lastdatalen = data->attriddatalen + entrysize + 1;
+      return;
+    }
+  oldsize = 0;
+  for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
+    oldsize += entrysize;
+  if (ida + 1 == data->attriddata + data->attriddatalen)
+    {
+      /* this was the last entry, just append it */
+      data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      data->attriddatalen--;   /* overwrite terminating 0  */
+    }
+  else
+    {
+      /* too bad. move to back. */
+      data->attriddata = solv_extend(data->attriddata, data->attriddatalen,  oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+      memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
+      pp[1] = data->attriddatalen;
+      data->attriddatalen += oldsize;
+    }
+  data->lasthandle = handle;
+  data->lastkey = *pp;
+  data->lastdatalen = data->attriddatalen + entrysize + 1;
+}
+
+void
+repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
+                     const unsigned char *str)
+{
+  Repokey key;
+  int l;
+
+  if (!(l = solv_chksum_len(type)))
+    return;
+  key.name = keyname;
+  key.type = type;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
+  memcpy(data->attrdata + data->attrdatalen, str, l);
+  repodata_set(data, solvid, &key, data->attrdatalen);
+  data->attrdatalen += l;
+}
+
+void
+repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
+                     const char *str)
+{
+  unsigned char buf[64];
+  int l;
+
+  if (!(l = solv_chksum_len(type)))
+    return;
+  if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
+    return;
+  repodata_set_bin_checksum(data, solvid, keyname, type, buf);
+}
+
+const char *
+repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
+{
+  int l;
+
+  if (!(l = solv_chksum_len(type)))
+    return "";
+  return pool_bin2hex(data->repo->pool, buf, l);
+}
+
+/* rpm filenames don't contain the epoch, so strip it */
+static inline const char *
+evrid2vrstr(Pool *pool, Id evrid)
+{
+  const char *p, *evr = pool_id2str(pool, evrid);
+  if (!evr)
+    return evr;
+  for (p = evr; *p >= '0' && *p <= '9'; p++)
+    ;
+  return p != evr && *p == ':' && p[1] ? p + 1 : evr;
+}
+
+static inline void
+repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
+{
+  Id id;
+  if (data->localpool)
+    id = stringpool_strn2id(&data->spool, str, l, 1);
+  else
+    id = pool_strn2id(data->repo->pool, str, l, 1);
+  repodata_set_id(data, solvid, keyname, id);
+}
+
+static inline void
+repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
+{
+  if (!str[l])
+    repodata_set_str(data, solvid, keyname, str);
+  else
+    {
+      char *s = solv_strdup(str);
+      s[l] = 0;
+      repodata_set_str(data, solvid, keyname, s);
+      free(s);
+    }
+}
+
+void
+repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
+{
+  Pool *pool = data->repo->pool;
+  Solvable *s;
+  const char *str, *fp;
+  int l = 0;
+
+  if (medianr)
+    repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
+  if (!dir)
+    {
+      if ((dir = strrchr(file, '/')) != 0)
+       {
+          l = dir - file;
+         dir = file;
+         file = dir + l + 1;
+         if (!l)
+           l++;
+       }
+    }
+  else
+    l = strlen(dir);
+  if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
+    {
+      dir += 2;
+      l -= 2;
+    }
+  if (l == 1 && dir[0] == '.')
+    l = 0;
+  s = pool->solvables + solvid;
+  if (dir && l)
+    {
+      str = pool_id2str(pool, s->arch);
+      if (!strncmp(dir, str, l) && !str[l])
+       repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
+      else
+       repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
+    }
+  fp = file;
+  str = pool_id2str(pool, s->name);
+  l = strlen(str);
+  if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
+    {
+      fp += l + 1;
+      str = evrid2vrstr(pool, s->evr);
+      l = strlen(str);
+      if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
+       {
+         fp += l + 1;
+         str = pool_id2str(pool, s->arch);
+         l = strlen(str);
+         if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
+           {
+             repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
+             return;
+           }
+       }
+    }
+  repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
+}
+
+/* XXX: medianr is currently not stored */
+void
+repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
+{
+  int l = 0;
+  const char *evr, *suf, *s;
+
+  if (!dir)
+    {
+      if ((dir = strrchr(file, '/')) != 0)
+       {
+          l = dir - file;
+         dir = file;
+         file = dir + l + 1;
+         if (!l)
+           l++;
+       }
+    }
+  else
+    l = strlen(dir);
+  if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
+    {
+      dir += 2;
+      l -= 2;
+    }
+  if (l == 1 && dir[0] == '.')
+    l = 0;
+  if (dir && l)
+    repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
+  evr = strchr(file, '-');
+  if (evr)
+    {
+      for (s = evr - 1; s > file; s--)
+       if (*s == '-')
+         {
+           evr = s;
+           break;
+         }
+    }
+  suf = strrchr(file, '.');
+  if (suf)
+    {
+      for (s = suf - 1; s > file; s--)
+       if (*s == '.')
+         {
+           suf = s;
+           break;
+         }
+      if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
+       {
+         /* We accept one more item as suffix.  */
+         for (s = suf - 1; s > file; s--)
+           if (*s == '.')
+             {
+               suf = s;
+               break;
+             }
+       }
+    }
+  if (!evr)
+    suf = 0;
+  if (suf && evr && suf < evr)
+    suf = 0;
+  repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
+  if (evr)
+    repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
+  if (suf)
+    repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
+}
+
+void
+repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
+{
+  Pool *pool = data->repo->pool;
+  Solvable *s = pool->solvables + solvid;
+  const char *p, *sevr, *sarch, *name, *evr;
+
+  p = strrchr(sourcepkg, '.');
+  if (!p || strcmp(p, ".rpm") != 0)
+    {
+      if (*sourcepkg)
+        repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
+      return;
+    }
+  p--;
+  while (p > sourcepkg && *p != '.')
+    p--;
+  if (*p != '.' || p == sourcepkg)
+    return;
+  sarch = p-- + 1;
+  while (p > sourcepkg && *p != '-')
+    p--;
+  if (*p != '-' || p == sourcepkg)
+    return;
+  p--;
+  while (p > sourcepkg && *p != '-')
+    p--;
+  if (*p != '-' || p == sourcepkg)
+    return;
+  sevr = p + 1;
+  pool = s->repo->pool;
+
+  name = pool_id2str(pool, s->name);
+  if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
+    repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
+  else
+    repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
+
+  evr = evrid2vrstr(pool, s->evr);
+  if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
+    repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
+  else
+    repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
+
+  if (!strcmp(sarch, "src.rpm"))
+    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
+  else if (!strcmp(sarch, "nosrc.rpm"))
+    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
+  else
+    repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
+}
+
+void
+repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
+{
+  Repokey key;
+  int i;
+
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_IDARRAY;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, data->attriddatalen);
+  data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+  for (i = 0; i < q->count; i++)
+    data->attriddata[data->attriddatalen++] = q->elements[i];
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
+{
+  assert(dir);
+#if 0
+fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
+#endif
+  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
+  data->attriddata[data->attriddatalen++] = dir;
+  data->attriddata[data->attriddatalen++] = num;
+  data->attriddata[data->attriddatalen++] = num2;
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
+{
+  Id stroff;
+  int l;
+
+  assert(dir);
+  l = strlen(str) + 1;
+  data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
+  memcpy(data->attrdata + data->attrdatalen, str, l);
+  stroff = data->attrdatalen;
+  data->attrdatalen += l;
+
+#if 0
+fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str,  data->attriddatalen);
+#endif
+  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
+  data->attriddata[data->attriddatalen++] = dir;
+  data->attriddata[data->attriddatalen++] = stroff;
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
+{
+#if 0
+fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
+#endif
+  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
+  data->attriddata[data->attriddatalen++] = id;
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
+                          const char *str)
+{
+  Id id;
+  if (data->localpool)
+    id = stringpool_str2id(&data->spool, str, 1);
+  else
+    id = pool_str2id(data->repo->pool, str, 1);
+  repodata_add_idarray(data, solvid, keyname, id);
+}
+
+void
+repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id handle)
+{
+  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
+  data->attriddata[data->attriddatalen++] = handle;
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id handle)
+{
+  repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
+  data->attriddata[data->attriddatalen++] = handle;
+  data->attriddata[data->attriddatalen++] = 0;
+}
+
+void
+repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, KeyValue *kv)
+{
+  switch (keytype)
+    {
+    case REPOKEY_TYPE_ID:
+      repodata_set_id(data, solvid, keyname, kv->id);
+      break;
+    case REPOKEY_TYPE_CONSTANTID:
+      repodata_set_constantid(data, solvid, keyname, kv->id);
+      break;
+    case REPOKEY_TYPE_IDARRAY:
+      repodata_add_idarray(data, solvid, keyname, kv->id);
+      break;
+    case REPOKEY_TYPE_STR:
+      repodata_set_str(data, solvid, keyname, kv->str);
+      break;
+    case REPOKEY_TYPE_VOID:
+      repodata_set_void(data, solvid, keyname);
+      break;
+    case REPOKEY_TYPE_NUM:
+      repodata_set_num(data, solvid, keyname, SOLV_KV_NUM64(kv));
+      break;
+    case REPOKEY_TYPE_CONSTANT:
+      repodata_set_constant(data, solvid, keyname, kv->num);
+      break;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      if (kv->id)
+        repodata_add_dirnumnum(data, solvid, keyname, kv->id, kv->num, kv->num2);
+      break;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      repodata_add_dirstr(data, solvid, keyname, kv->id, kv->str);
+      break;
+    case_CHKSUM_TYPES:
+      repodata_set_bin_checksum(data, solvid, keyname, keytype, (const unsigned char *)kv->str);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
+{
+  Id *pp, *ap, **app;
+  app = repodata_get_attrp(data, solvid);
+  ap = *app;
+  if (!ap)
+    return;
+  for (; *ap; ap += 2)
+    if (data->keys[*ap].name == keyname)
+      break;
+  if (!*ap)
+    return;
+  pp = ap;
+  ap += 2;
+  for (; *ap; ap += 2)
+    {
+      if (data->keys[*ap].name == keyname)
+       continue;
+      *pp++ = ap[0];
+      *pp++ = ap[1];
+    }
+  *pp = 0;
+}
+
+void
+repodata_unset(Repodata *data, Id solvid, Id keyname)
+{
+  Repokey key;
+  key.name = keyname;
+  key.type = REPOKEY_TYPE_DELETED;
+  key.size = 0;
+  key.storage = KEY_STORAGE_INCORE;
+  repodata_set(data, solvid, &key, 0);
+}
+
+/* add all (uninternalized) attrs from src to dest */
+void
+repodata_merge_attrs(Repodata *data, Id dest, Id src)
+{
+  Id *keyp;
+  if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
+    return;
+  for (; *keyp; keyp += 2)
+    repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
+}
+
+/* add some (uninternalized) attrs from src to dest */
+void
+repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
+{
+  Id *keyp;
+  if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
+    return;
+  for (; *keyp; keyp += 2)
+    if (!keyidmap || MAPTST(keyidmap, keyp[0]))
+      repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
+}
+
+/* swap (uninternalized) attrs from src and dest */
+void
+repodata_swap_attrs(Repodata *data, Id dest, Id src)
+{
+  Id *tmpattrs;
+  if (!data->attrs || dest == src)
+    return;
+  if (dest < data->start || dest >= data->end)
+    repodata_extend(data, dest);
+  if (src < data->start || src >= data->end)
+    repodata_extend(data, src);
+  tmpattrs = data->attrs[dest - data->start];
+  data->attrs[dest - data->start] = data->attrs[src - data->start];
+  data->attrs[src - data->start] = tmpattrs;
+}
+
+
+/**********************************************************************/
+
+/* TODO: unify with repo_write and repo_solv! */
+
+#define EXTDATA_BLOCK 1023
+
+struct extdata {
+  unsigned char *buf;
+  int len;
+};
+
+static void
+data_addid(struct extdata *xd, Id sx)
+{
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+
+  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
+  dp = xd->buf + xd->len;
+
+  if (x >= (1 << 14))
+    {
+      if (x >= (1 << 28))
+        *dp++ = (x >> 28) | 128;
+      if (x >= (1 << 21))
+        *dp++ = (x >> 21) | 128;
+      *dp++ = (x >> 14) | 128;
+    }
+  if (x >= (1 << 7))
+    *dp++ = (x >> 7) | 128;
+  *dp++ = x & 127;
+  xd->len = dp - xd->buf;
+}
+
+static void
+data_addid64(struct extdata *xd, unsigned long long x)
+{
+  if (x >= 0x100000000)
+    {
+      if ((x >> 35) != 0)
+       {
+         data_addid(xd, (Id)(x >> 35));
+         xd->buf[xd->len - 1] |= 128;
+       }
+      data_addid(xd, (Id)((unsigned int)x | 0x80000000));
+      xd->buf[xd->len - 5] = (x >> 28) | 128;
+    }
+  else
+    data_addid(xd, (Id)x);
+}
+
+static void
+data_addideof(struct extdata *xd, Id sx, int eof)
+{
+  unsigned int x = (unsigned int)sx;
+  unsigned char *dp;
+
+  xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
+  dp = xd->buf + xd->len;
+
+  if (x >= (1 << 13))
+    {
+      if (x >= (1 << 27))
+        *dp++ = (x >> 27) | 128;
+      if (x >= (1 << 20))
+        *dp++ = (x >> 20) | 128;
+      *dp++ = (x >> 13) | 128;
+    }
+  if (x >= (1 << 6))
+    *dp++ = (x >> 6) | 128;
+  *dp++ = eof ? (x & 63) : (x & 63) | 64;
+  xd->len = dp - xd->buf;
+}
+
+static void
+data_addblob(struct extdata *xd, unsigned char *blob, int len)
+{
+  xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
+  memcpy(xd->buf + xd->len, blob, len);
+  xd->len += len;
+}
+
+/*********************************/
+
+/* this is to reduct memory usage when internalizing oversized repos */
+static void
+compact_attrdata(Repodata *data, int entry, int nentry)
+{
+  int i;
+  unsigned int attrdatastart = data->attrdatalen;
+  unsigned int attriddatastart = data->attriddatalen;
+  if (attrdatastart < 1024 * 1024 * 4 && attriddatastart < 1024 * 1024)
+    return;
+  for (i = entry; i < nentry; i++)
+    {
+      Id v, *attrs = data->attrs[i];
+      if (!attrs)
+       continue;
+      for (; *attrs; attrs += 2)
+       {
+         switch (data->keys[*attrs].type)
+           {
+           case REPOKEY_TYPE_STR:
+           case REPOKEY_TYPE_BINARY:
+           case_CHKSUM_TYPES:
+             if ((unsigned int)attrs[1] < attrdatastart)
+                attrdatastart = attrs[1];
+             break;
+           case REPOKEY_TYPE_DIRSTRARRAY:
+             for (v = attrs[1]; data->attriddata[v] ; v += 2)
+               if (data->attriddata[v + 1] < attrdatastart)
+                 attrdatastart = data->attriddata[v + 1];
+             /* FALLTHROUGH */
+           case REPOKEY_TYPE_IDARRAY:
+           case REPOKEY_TYPE_DIRNUMNUMARRAY:
+             if ((unsigned int)attrs[1] < attriddatastart)
+               attriddatastart = attrs[1];
+             break;
+           case REPOKEY_TYPE_FIXARRAY:
+           case REPOKEY_TYPE_FLEXARRAY:
+             return;
+           default:
+             break;
+           }
+       }
+    }
+#if 0
+  printf("compact_attrdata %d %d\n", entry, nentry);
+  printf("attrdatastart: %d\n", attrdatastart);
+  printf("attriddatastart: %d\n", attriddatastart);
+#endif
+  if (attrdatastart < 1024 * 1024 * 4 && attriddatastart < 1024 * 1024)
+    return;
+  for (i = entry; i < nentry; i++)
+    {
+      Id v, *attrs = data->attrs[i];
+      if (!attrs)
+       continue;
+      for (; *attrs; attrs += 2)
+       {
+         switch (data->keys[*attrs].type)
+           {
+           case REPOKEY_TYPE_STR:
+           case REPOKEY_TYPE_BINARY:
+           case_CHKSUM_TYPES:
+             attrs[1] -= attrdatastart;
+             break;
+           case REPOKEY_TYPE_DIRSTRARRAY:
+             for (v = attrs[1]; data->attriddata[v] ; v += 2)
+               data->attriddata[v + 1] -= attrdatastart;
+             /* FALLTHROUGH */
+           case REPOKEY_TYPE_IDARRAY:
+           case REPOKEY_TYPE_DIRNUMNUMARRAY:
+             attrs[1] -= attriddatastart;
+             break;
+           default:
+             break;
+           }
+       }
+    }
+  if (attrdatastart)
+    {
+      data->attrdatalen -= attrdatastart;
+      memmove(data->attrdata, data->attrdata + attrdatastart, data->attrdatalen);
+      data->attrdata = solv_extend_resize(data->attrdata, data->attrdatalen, 1, REPODATA_ATTRDATA_BLOCK);
+    }
+  if (attriddatastart)
+    {
+      data->attriddatalen -= attriddatastart;
+      memmove(data->attriddata, data->attriddata + attriddatastart, data->attriddatalen * sizeof(Id));
+      data->attriddata = solv_extend_resize(data->attriddata, data->attriddatalen, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
+    }
+}
+
+/* internalalize some key into incore/vincore data */
+
+static void
+repodata_serialize_key(Repodata *data, struct extdata *newincore,
+                      struct extdata *newvincore,
+                      Id *schema,
+                      Repokey *key, Id val)
+{
+  Id *ida;
+  struct extdata *xd;
+  unsigned int oldvincorelen = 0;
+  Id schemaid, *sp;
+
+  xd = newincore;
+  if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+    {
+      xd = newvincore;
+      oldvincorelen = xd->len;
+    }
+  switch (key->type)
+    {
+    case REPOKEY_TYPE_VOID:
+    case REPOKEY_TYPE_CONSTANT:
+    case REPOKEY_TYPE_CONSTANTID:
+    case REPOKEY_TYPE_DELETED:
+      break;
+    case REPOKEY_TYPE_STR:
+      data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
+      break;
+    case REPOKEY_TYPE_MD5:
+      data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
+      break;
+    case REPOKEY_TYPE_SHA1:
+      data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
+      break;
+    case REPOKEY_TYPE_SHA224:
+      data_addblob(xd, data->attrdata + val, SIZEOF_SHA224);
+      break;
+    case REPOKEY_TYPE_SHA256:
+      data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
+      break;
+    case REPOKEY_TYPE_SHA384:
+      data_addblob(xd, data->attrdata + val, SIZEOF_SHA384);
+      break;
+    case REPOKEY_TYPE_SHA512:
+      data_addblob(xd, data->attrdata + val, SIZEOF_SHA512);
+      break;
+    case REPOKEY_TYPE_NUM:
+      if (val & 0x80000000)
+       {
+         data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
+         break;
+       }
+      /* FALLTHROUGH */
+    case REPOKEY_TYPE_ID:
+    case REPOKEY_TYPE_DIR:
+      data_addid(xd, val);
+      break;
+    case REPOKEY_TYPE_BINARY:
+      {
+       Id len;
+       unsigned char *dp = data_read_id(data->attrdata + val, &len);
+       dp += (unsigned int)len;
+       data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
+      }
+      break;
+    case REPOKEY_TYPE_IDARRAY:
+      for (ida = data->attriddata + val; *ida; ida++)
+       data_addideof(xd, ida[0], ida[1] ? 0 : 1);
+      break;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      for (ida = data->attriddata + val; *ida; ida += 3)
+       {
+         data_addid(xd, ida[0]);
+         data_addid(xd, ida[1]);
+         data_addideof(xd, ida[2], ida[3] ? 0 : 1);
+       }
+      break;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      for (ida = data->attriddata + val; *ida; ida += 2)
+       {
+         data_addideof(xd, ida[0], ida[2] ? 0 : 1);
+         data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
+       }
+      break;
+    case REPOKEY_TYPE_FIXARRAY:
+      {
+       int num = 0;
+       schemaid = 0;
+       for (ida = data->attriddata + val; *ida; ida++)
+         {
+           Id *kp;
+           sp = schema;
+           kp = data->xattrs[-*ida];
+           if (!kp)
+             continue;         /* ignore empty elements */
+           num++;
+           for (; *kp; kp += 2)
+             *sp++ = *kp;
+           *sp = 0;
+           if (!schemaid)
+             schemaid = repodata_schema2id(data, schema, 1);
+           else if (schemaid != repodata_schema2id(data, schema, 0))
+             {
+               pool_debug(data->repo->pool, SOLV_ERROR, "repodata_serialize_key: fixarray substructs with different schemas\n");
+               num = 0;
+               break;
+             }
+         }
+       data_addid(xd, num);
+       if (!num)
+         break;
+       data_addid(xd, schemaid);
+       for (ida = data->attriddata + val; *ida; ida++)
+         {
+           Id *kp = data->xattrs[-*ida];
+           if (!kp)
+             continue;
+           for (; *kp; kp += 2)
+             repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
+         }
+       break;
+      }
+    case REPOKEY_TYPE_FLEXARRAY:
+      {
+       int num = 0;
+       for (ida = data->attriddata + val; *ida; ida++)
+         num++;
+       data_addid(xd, num);
+       for (ida = data->attriddata + val; *ida; ida++)
+         {
+           Id *kp = data->xattrs[-*ida];
+           if (!kp)
+             {
+               data_addid(xd, 0);      /* XXX */
+               continue;
+             }
+           sp = schema;
+           for (;*kp; kp += 2)
+             *sp++ = *kp;
+           *sp = 0;
+           schemaid = repodata_schema2id(data, schema, 1);
+           data_addid(xd, schemaid);
+           kp = data->xattrs[-*ida];
+           for (;*kp; kp += 2)
+             repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
+         }
+       break;
+      }
+    default:
+      pool_debug(data->repo->pool, SOLV_FATAL, "repodata_serialize_key: don't know how to handle type %d\n", key->type);
+      exit(1);
+    }
+  if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+    {
+      /* put offset/len in incore */
+      data_addid(newincore, data->lastverticaloffset + oldvincorelen);
+      oldvincorelen = xd->len - oldvincorelen;
+      data_addid(newincore, oldvincorelen);
+    }
+}
+
+/* create a circular linked list of all keys that share
+ * the same keyname */
+static Id *
+calculate_keylink(Repodata *data)
+{
+  int i, j;
+  Id *link;
+  Id maxkeyname = 0, *keytable = 0;
+  link = solv_calloc(data->nkeys, sizeof(Id));
+  if (data->nkeys <= 2)
+    return link;
+  for (i = 1; i < data->nkeys; i++)
+    {
+      Id n = data->keys[i].name;
+      if (n >= maxkeyname)
+       {
+         keytable = solv_realloc2(keytable, n + 128, sizeof(Id));
+         memset(keytable + maxkeyname, 0, (n + 128 - maxkeyname) * sizeof(Id));
+         maxkeyname = n + 128;
+       }
+      j = keytable[n];
+      if (j)
+       link[i] = link[j];
+      else
+       j = i;
+      link[j] = i;
+      keytable[n] = i;
+    }
+  /* remove links that just point to themselfs */
+  for (i = 1; i < data->nkeys; i++)
+    if (link[i] == i)
+      link[i] = 0;
+  solv_free(keytable);
+  return link;
+}
+
+void
+repodata_internalize(Repodata *data)
+{
+  Repokey *key, solvkey;
+  Id entry, nentry;
+  Id schemaid, keyid, *schema, *sp, oldschemaid, *keyp, *seen;
+  Offset *oldincoreoffs = 0;
+  int schemaidx;
+  unsigned char *dp, *ndp;
+  int neednewschema;
+  struct extdata newincore;
+  struct extdata newvincore;
+  Id solvkeyid;
+  Id *keylink;
+  int haveoldkl;
+
+  if (!data->attrs && !data->xattrs)
+    return;
+
+#if 0
+  printf("repodata_internalize %d\n", data->repodataid);
+  printf("  attr data: %d K\n", data->attrdatalen / 1024);
+  printf("  attrid data: %d K\n", data->attriddatalen / (1024 / 4));
+#endif
+  newvincore.buf = data->vincore;
+  newvincore.len = data->vincorelen;
+
+  /* find the solvables key, create if needed */
+  memset(&solvkey, 0, sizeof(solvkey));
+  solvkey.name = REPOSITORY_SOLVABLES;
+  solvkey.type = REPOKEY_TYPE_FLEXARRAY;
+  solvkey.size = 0;
+  solvkey.storage = KEY_STORAGE_INCORE;
+  solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
+
+  schema = solv_malloc2(data->nkeys, sizeof(Id));
+  seen = solv_malloc2(data->nkeys, sizeof(Id));
+
+  /* Merge the data already existing (in data->schemata, ->incoredata and
+     friends) with the new attributes in data->attrs[].  */
+  nentry = data->end - data->start;
+  memset(&newincore, 0, sizeof(newincore));
+  data_addid(&newincore, 0);   /* start data at offset 1 */
+
+  data->mainschema = 0;
+  data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
+
+  keylink = calculate_keylink(data);
+  /* join entry data */
+  /* we start with the meta data, entry -1 */
+  for (entry = -1; entry < nentry; entry++)
+    {
+      oldschemaid = 0;
+      dp = data->incoredata;
+      if (dp)
+       {
+         dp += entry >= 0 ? data->incoreoffset[entry] : 1;
+          dp = data_read_id(dp, &oldschemaid);
+       }
+      memset(seen, 0, data->nkeys * sizeof(Id));
+#if 0
+fprintf(stderr, "oldschemaid %d\n", oldschemaid);
+fprintf(stderr, "schemata %d\n", data->schemata[oldschemaid]);
+fprintf(stderr, "schemadata %p\n", data->schemadata);
+#endif
+
+      /* seen: -1: old data,  0: skipped,  >0: id + 1 */
+      neednewschema = 0;
+      sp = schema;
+      haveoldkl = 0;
+      for (keyp = data->schemadata + data->schemata[oldschemaid]; *keyp; keyp++)
+       {
+         if (seen[*keyp])
+           {
+             /* oops, should not happen */
+             neednewschema = 1;
+             continue;
+           }
+         seen[*keyp] = -1;     /* use old marker */
+         *sp++ = *keyp;
+         if (keylink[*keyp])
+           haveoldkl = 1;      /* potential keylink conflict */
+       }
+
+      /* strip solvables key */
+      if (entry < 0 && solvkeyid && seen[solvkeyid])
+       {
+         *sp = 0;
+         for (sp = keyp = schema; *sp; sp++)
+           if (*sp != solvkeyid)
+             *keyp++ = *sp;
+         sp = keyp;
+         seen[solvkeyid] = 0;
+         neednewschema = 1;
+       }
+
+      /* add new entries */
+      if (entry >= 0)
+       keyp = data->attrs ? data->attrs[entry] : 0;
+      else
+        keyp = data->xattrs ? data->xattrs[1] : 0;
+      if (keyp)
+        for (; *keyp; keyp += 2)
+         {
+           if (!seen[*keyp])
+             {
+               neednewschema = 1;
+               *sp++ = *keyp;
+               if (haveoldkl && keylink[*keyp])                /* this should be pretty rare */
+                 {
+                   Id kl;
+                   for (kl = keylink[*keyp]; kl != *keyp; kl = keylink[kl])
+                     if (seen[kl] == -1)
+                       {
+                         /* replacing old key kl, remove from schema and seen */
+                         Id *osp;
+                         for (osp = schema; osp < sp; osp++)
+                           if (*osp == kl)
+                             {
+                               memmove(osp, osp + 1, (sp - osp) * sizeof(Id));
+                               sp--;
+                               seen[kl] = 0;
+                               break;
+                             }
+                       }
+                 }
+             }
+           seen[*keyp] = keyp[1] + 1;
+         }
+
+      /* add solvables key if needed */
+      if (entry < 0 && data->end != data->start)
+       {
+         *sp++ = solvkeyid;    /* always last in schema */
+         neednewschema = 1;
+       }
+
+      /* commit schema */
+      *sp = 0;
+      if (neednewschema)
+        /* Ideally we'd like to sort the new schema here, to ensure
+          schema equality independend of the ordering. */
+       schemaid = repodata_schema2id(data, schema, 1);
+      else
+       schemaid = oldschemaid;
+
+      if (entry < 0)
+       {
+         data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
+         data->mainschema = schemaid;
+       }
+
+      /* find offsets in old incore data */
+      if (oldschemaid)
+       {
+         Id *lastneeded = 0;
+         for (sp = data->schemadata + data->schemata[oldschemaid]; *sp; sp++)
+           if (seen[*sp] == -1)
+             lastneeded = sp + 1;
+         if (lastneeded)
+           {
+             if (!oldincoreoffs)
+               oldincoreoffs = solv_malloc2(data->nkeys, 2 * sizeof(Offset));
+             for (sp = data->schemadata + data->schemata[oldschemaid]; sp != lastneeded; sp++)
+               {
+                 /* Skip the data associated with this old key.  */
+                 key = data->keys + *sp;
+                 ndp = dp;
+                 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
+                   {
+                     ndp = data_skip(ndp, REPOKEY_TYPE_ID);
+                     ndp = data_skip(ndp, REPOKEY_TYPE_ID);
+                   }
+                 else if (key->storage == KEY_STORAGE_INCORE)
+                   ndp = data_skip_key(data, ndp, key);
+                 oldincoreoffs[*sp * 2] = dp - data->incoredata;
+                 oldincoreoffs[*sp * 2 + 1] = ndp - dp;
+                 dp = ndp;
+               }
+           }
+       }
+
+      /* just copy over the complete old entry (including the schemaid) if there was no new data */
+      if (entry >= 0 && !neednewschema && oldschemaid && (!data->attrs || !data->attrs[entry]) && dp)
+       {
+         ndp = data->incoredata + data->incoreoffset[entry];
+         data->incoreoffset[entry] = newincore.len;
+         data_addblob(&newincore, ndp, dp - ndp);
+         goto entrydone;
+       }
+
+      /* Now create data blob.  We walk through the (possibly new) schema
+        and either copy over old data, or insert the new.  */
+      if (entry >= 0)
+        data->incoreoffset[entry] = newincore.len;
+      data_addid(&newincore, schemaid);
+
+      /* we don't use a pointer to the schemadata here as repodata_serialize_key
+       * may call repodata_schema2id() which might realloc our schemadata */
+      for (schemaidx = data->schemata[schemaid]; (keyid = data->schemadata[schemaidx]) != 0; schemaidx++)
+       {
+         if (entry < 0)
+           {
+             data->mainschemaoffsets[schemaidx - data->schemata[schemaid]] = newincore.len;
+             if (keyid == solvkeyid)
+               {
+                 /* add flexarray entry count */
+                 data_addid(&newincore, data->end - data->start);
+                 break;        /* always the last entry */
+               }
+           }
+         if (seen[keyid] == -1)
+           {
+             if (oldincoreoffs[keyid * 2 + 1])
+               data_addblob(&newincore, data->incoredata + oldincoreoffs[keyid * 2], oldincoreoffs[keyid * 2 + 1]);
+           }
+         else if (seen[keyid])
+           repodata_serialize_key(data, &newincore, &newvincore, schema, data->keys + keyid, seen[keyid] - 1);
+       }
+
+entrydone:
+      /* free memory */
+      if (entry >= 0 && data->attrs)
+       {
+         if (data->attrs[entry])
+           data->attrs[entry] = solv_free(data->attrs[entry]);
+         if (entry && entry % 4096 == 0 && data->nxattrs <= 2 && entry + 64 < nentry)
+           {
+             compact_attrdata(data, entry + 1, nentry);        /* try to free some memory */
+#if 0
+             printf("  attr data: %d K\n", data->attrdatalen / 1024);
+             printf("  attrid data: %d K\n", data->attriddatalen / (1024 / 4));
+             printf("  incore data: %d K\n", newincore.len / 1024);
+             printf("  sum: %d K\n", (newincore.len + data->attrdatalen + data->attriddatalen * 4) / 1024);
+             /* malloc_stats(); */
+#endif
+           }
+       }
+    }
+  /* free all xattrs */
+  for (entry = 0; entry < data->nxattrs; entry++)
+    if (data->xattrs[entry])
+      solv_free(data->xattrs[entry]);
+  data->xattrs = solv_free(data->xattrs);
+  data->nxattrs = 0;
+
+  data->lasthandle = 0;
+  data->lastkey = 0;
+  data->lastdatalen = 0;
+  solv_free(schema);
+  solv_free(seen);
+  solv_free(keylink);
+  solv_free(oldincoreoffs);
+  repodata_free_schemahash(data);
+
+  solv_free(data->incoredata);
+  data->incoredata = newincore.buf;
+  data->incoredatalen = newincore.len;
+  data->incoredatafree = 0;
+
+  data->vincore = newvincore.buf;
+  data->vincorelen = newvincore.len;
+
+  data->attrs = solv_free(data->attrs);
+  data->attrdata = solv_free(data->attrdata);
+  data->attriddata = solv_free(data->attriddata);
+  data->attrnum64data = solv_free(data->attrnum64data);
+  data->attrdatalen = 0;
+  data->attriddatalen = 0;
+  data->attrnum64datalen = 0;
+#if 0
+  printf("repodata_internalize %d done\n", data->repodataid);
+  printf("  incore data: %d K\n", data->incoredatalen / 1024);
+#endif
+}
+
+void
+repodata_disable_paging(Repodata *data)
+{
+  if (maybe_load_repodata(data, 0))
+    {
+      repopagestore_disable_paging(&data->store);
+      data->storestate++;
+    }
+}
+
+/* call the pool's loadcallback to load a stub repodata */
+static void
+repodata_stub_loader(Repodata *data)
+{
+  Repo *repo = data->repo;
+  Pool *pool = repo->pool;
+  int r, i;
+  struct s_Pool_tmpspace oldtmpspace;
+  Datapos oldpos;
+
+  if (!pool->loadcallback)
+    {
+      data->state = REPODATA_ERROR;
+      return;
+    }
+  data->state = REPODATA_LOADING;
+
+  /* save tmp space and pos */
+  oldtmpspace = pool->tmpspace;
+  memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
+  oldpos = pool->pos;
+
+  r = pool->loadcallback(pool, data, pool->loadcallbackdata);
+
+  /* restore tmp space and pos */
+  for (i = 0; i < POOL_TMPSPACEBUF; i++)
+    solv_free(pool->tmpspace.buf[i]);
+  pool->tmpspace = oldtmpspace;
+  if (r && oldpos.repo == repo && oldpos.repodataid == data->repodataid)
+    memset(&oldpos, 0, sizeof(oldpos));
+  pool->pos = oldpos;
+
+  data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
+}
+
+static inline void
+repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
+{
+  Repokey xkey;
+
+  xkey.name = keyname;
+  xkey.type = keytype;
+  xkey.storage = KEY_STORAGE_INCORE;
+  xkey.size = 0;
+  repodata_key2id(data, &xkey, 1);
+}
+
+static Repodata *
+repodata_add_stub(Repodata **datap)
+{
+  Repodata *data = *datap;
+  Repo *repo = data->repo;
+  Id repodataid = data - repo->repodata;
+  Repodata *sdata = repo_add_repodata(repo, 0);
+  data = repo->repodata + repodataid;
+  if (data->end > data->start)
+    repodata_extend_block(sdata, data->start, data->end - data->start);
+  sdata->state = REPODATA_STUB;
+  sdata->loadcallback = repodata_stub_loader;
+  *datap = data;
+  return sdata;
+}
+
+Repodata *
+repodata_create_stubs(Repodata *data)
+{
+  Repo *repo = data->repo;
+  Pool *pool = repo->pool;
+  Repodata *sdata;
+  int *stubdataids;
+  Dataiterator di;
+  Id xkeyname = 0;
+  int i, cnt = 0;
+
+  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
+  while (dataiterator_step(&di))
+    if (di.data == data)
+      cnt++;
+  dataiterator_free(&di);
+  if (!cnt)
+    return data;
+  stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
+  for (i = 0; i < cnt; i++)
+    {
+      sdata = repodata_add_stub(&data);
+      stubdataids[i] = sdata - repo->repodata;
+    }
+  i = 0;
+  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
+  sdata = 0;
+  while (dataiterator_step(&di))
+    {
+      if (di.data != data)
+       continue;
+      if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
+       {
+         dataiterator_entersub(&di);
+         sdata = repo->repodata + stubdataids[i++];
+         xkeyname = 0;
+         continue;
+       }
+      repodata_set_kv(sdata, SOLVID_META, di.key->name, di.key->type, &di.kv);
+      if (di.key->name == REPOSITORY_KEYS && di.key->type == REPOKEY_TYPE_IDARRAY)
+       {
+         if (!xkeyname)
+           {
+             if (!di.kv.eof)
+               xkeyname = di.kv.id;
+           }
+         else
+           {
+             repodata_add_stubkey(sdata, xkeyname, di.kv.id);
+             if (xkeyname == SOLVABLE_FILELIST)
+               repodata_set_filelisttype(sdata, REPODATA_FILELIST_EXTENSION);
+             xkeyname = 0;
+           }
+       }
+    }
+  dataiterator_free(&di);
+  for (i = 0; i < cnt; i++)
+    repodata_internalize(repo->repodata + stubdataids[i]);
+  solv_free(stubdataids);
+  return data;
+}
+
+void
+repodata_set_filelisttype(Repodata *data, int type)
+{
+  data->filelisttype = type;
+}
+
+unsigned int
+repodata_memused(Repodata *data)
+{
+  return data->incoredatalen + data->vincorelen;
+}
+
diff --git a/libsolv-0.7.2/src/repodata.h b/libsolv-0.7.2/src/repodata.h
new file mode 100644 (file)
index 0000000..f204e34
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repodata.h
+ *
+ */
+
+#ifndef LIBSOLV_REPODATA_H
+#define LIBSOLV_REPODATA_H
+
+#include <stdio.h>
+
+#include "pooltypes.h"
+#include "pool.h"
+#include "dirpool.h"
+
+#ifdef LIBSOLV_INTERNAL
+#include "repopage.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SIZEOF_MD5     16
+#define SIZEOF_SHA1    20
+#define SIZEOF_SHA224  28
+#define SIZEOF_SHA256  32
+#define SIZEOF_SHA384  48
+#define SIZEOF_SHA512  64
+
+struct s_Repo;
+struct s_KeyValue;
+
+typedef struct s_Repokey {
+  Id name;
+  Id type;                     /* REPOKEY_TYPE_xxx */
+  unsigned int size;
+  unsigned int storage;                /* KEY_STORAGE_xxx */
+} Repokey;
+
+#define KEY_STORAGE_DROPPED             0
+#define KEY_STORAGE_SOLVABLE            1
+#define KEY_STORAGE_INCORE              2
+#define KEY_STORAGE_VERTICAL_OFFSET     3
+
+#ifdef LIBSOLV_INTERNAL
+struct dircache;
+#endif
+
+/* repodata states */
+#define REPODATA_AVAILABLE     0
+#define REPODATA_STUB          1
+#define REPODATA_ERROR         2
+#define REPODATA_STORE         3
+#define REPODATA_LOADING       4
+
+/* repodata filelist types */
+/* note that FILELIST_FILTERED means that the data contains a filtered
+ * filelist *AND* that it is authoritative for all included solvables. */
+#define REPODATA_FILELIST_FILTERED     1
+#define REPODATA_FILELIST_EXTENSION    2
+
+typedef struct s_Repodata {
+  Id repodataid;               /* our id */
+  struct s_Repo *repo;         /* back pointer to repo */
+
+  int state;                   /* available, stub or error */
+
+  void (*loadcallback)(struct s_Repodata *);
+
+  int start;                   /* start of solvables this repodata is valid for */
+  int end;                     /* last solvable + 1 of this repodata */
+
+  Repokey *keys;               /* keys, first entry is always zero */
+  int nkeys;                   /* length of keys array */
+  unsigned char keybits[32];   /* keyname hash */
+
+  Id *schemata;                        /* schema -> offset into schemadata */
+  int nschemata;               /* number of schemata */
+  Id *schemadata;              /* schema storage */
+
+  Stringpool spool;            /* local string pool */
+  int localpool;               /* is local string pool used */
+
+  Dirpool dirpool;             /* local dir pool */
+
+#ifdef LIBSOLV_INTERNAL
+  FILE *fp;                    /* file pointer of solv file */
+  int error;                   /* corrupt solv file */
+
+  int filelisttype;            /* type of filelist */
+  Id *filelistfilter;          /* filelist filter used */
+  char *filelistfilterdata;    /* filelist filter string space */
+
+  unsigned int schemadatalen;   /* schema storage size */
+  Id *schematahash;            /* unification helper */
+
+  unsigned char *incoredata;   /* in-core data */
+  unsigned int incoredatalen;  /* in-core data used */
+  unsigned int incoredatafree; /* free data len */
+
+  Id mainschema;               /* SOLVID_META schema */
+  Id *mainschemaoffsets;       /* SOLVID_META offsets into incoredata */
+
+  Id *incoreoffset;            /* offset for all entries */
+
+  Id *verticaloffset;          /* offset for all verticals, nkeys elements */
+  Id lastverticaloffset;       /* end of verticals */
+
+  Repopagestore store;         /* our page store */
+  Id storestate;               /* incremented every time the store might change */
+
+  unsigned char *vincore;      /* internal vertical data */
+  unsigned int vincorelen;     /* data size */
+
+  Id **attrs;                  /* un-internalized attributes */
+  Id **xattrs;                 /* anonymous handles */
+  int nxattrs;                 /* number of handles */
+
+  unsigned char *attrdata;     /* their string data space */
+  unsigned int attrdatalen;    /* its len */
+  Id *attriddata;              /* their id space */
+  unsigned int attriddatalen;  /* its len */
+  unsigned long long *attrnum64data;   /* their 64bit num data space */
+  unsigned int attrnum64datalen;       /* its len */
+
+  /* array cache to speed up repodata_add functions*/
+  Id lasthandle;
+  Id lastkey;
+  Id lastdatalen;
+
+  /* directory cache to speed up repodata_str2dir */
+  struct dircache *dircache;
+#endif
+
+} Repodata;
+
+#define SOLVID_META            -1
+#define SOLVID_POS             -2
+
+
+/*-----
+ * management functions
+ */
+void repodata_initdata(Repodata *data, struct s_Repo *repo, int localpool);
+void repodata_freedata(Repodata *data);
+
+void repodata_free(Repodata *data);
+void repodata_empty(Repodata *data, int localpool);
+
+void repodata_load(Repodata *data);
+
+/*
+ * key management functions
+ */
+Id repodata_key2id(Repodata *data, Repokey *key, int create);
+
+static inline Repokey *
+repodata_id2key(Repodata *data, Id keyid)
+{
+  return data->keys + keyid;
+}
+
+/*
+ * schema management functions
+ */
+Id repodata_schema2id(Repodata *data, Id *schema, int create);
+void repodata_free_schemahash(Repodata *data);
+
+static inline Id *
+repodata_id2schema(Repodata *data, Id schemaid)
+{
+  return data->schemadata + data->schemata[schemaid];
+}
+
+/*
+ * data search and access
+ */
+
+/* check if there is a chance that the repodata contains data for
+ * the specified keyname */
+static inline int
+repodata_precheck_keyname(Repodata *data, Id keyname)
+{
+  unsigned char x = data->keybits[(keyname >> 3) & (sizeof(data->keybits) - 1)];
+  return x && (x & (1 << (keyname & 7))) ? 1 : 0;
+}
+
+/* check if the repodata contains data for the specified keyname */
+static inline int
+repodata_has_keyname(Repodata *data, Id keyname)
+{
+  int i;
+  if (!repodata_precheck_keyname(data, keyname))
+    return 0;
+  for (i = 1; i < data->nkeys; i++)
+    if (data->keys[i].name == keyname)
+      return 1;
+  return 0;
+}
+
+/* search key <keyname> (all keys, if keyname == 0) for Id <solvid>
+ * Call <callback> for each match */
+void repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
+void repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
+void repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, struct s_KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
+
+/* Make sure the found KeyValue has the "str" field set. Return "str"
+ * if valid, NULL if not possible */
+const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct s_KeyValue *kv, int flags);
+
+/* filelist filter support */
+void repodata_set_filelisttype(Repodata *data, int filelisttype);
+int repodata_filelistfilter_matches(Repodata *data, const char *str);
+void repodata_free_filelistfilter(Repodata *data);
+
+/* lookup functions */
+Id repodata_lookup_type(Repodata *data, Id solvid, Id keyname);
+Id repodata_lookup_id(Repodata *data, Id solvid, Id keyname);
+const char *repodata_lookup_str(Repodata *data, Id solvid, Id keyname);
+unsigned long long repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound);
+int repodata_lookup_void(Repodata *data, Id solvid, Id keyname);
+const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep);
+int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
+const void *repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp);
+
+/* internal, used in fileprovides code */
+const unsigned char *repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname);
+
+/* internal, fill keyskip array with data */
+Id *repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip);
+
+/*-----
+ * data assignment functions
+ */
+
+/*
+ * extend the data so that it contains the specified solvables
+ * (no longer needed, as the repodata_set functions autoextend)
+ */
+void repodata_extend(Repodata *data, Id p);
+void repodata_extend_block(Repodata *data, Id p, int num);
+void repodata_shrink(Repodata *data, int end);
+
+/* internalize freshly set data, so that it is found by the search
+ * functions and written out */
+void repodata_internalize(Repodata *data);
+
+/* create an anonymous handle. useful for substructures like
+ * fixarray/flexarray  */
+Id repodata_new_handle(Repodata *data);
+
+/* basic types: void, num, string, Id */
+void repodata_set_void(Repodata *data, Id solvid, Id keyname);
+void repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num);
+void repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id);
+void repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str);
+void repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len);
+/* create id from string, then set_id */
+void repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str);
+
+/* set numeric constant */
+void repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant);
+
+/* set Id constant */
+void repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id);
+
+/* checksum */
+void repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
+                              const unsigned char *buf);
+void repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
+                          const char *str);
+void repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
+
+/* directory (for package file list) */
+void repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2);
+void repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str);
+void repodata_free_dircache(Repodata *data);
+
+
+/* arrays */
+void repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id);
+void repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname, const char *str);
+void repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle);
+void repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle);
+
+/* generic */
+void repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, struct s_KeyValue *kv);
+void repodata_unset(Repodata *data, Id solvid, Id keyname);
+void repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname);
+
+/*
+ merge/swap attributes from one solvable to another
+ works only if the data is not yet internalized
+*/
+void repodata_merge_attrs(Repodata *data, Id dest, Id src);
+void repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite);
+void repodata_swap_attrs(Repodata *data, Id dest, Id src);
+
+Repodata *repodata_create_stubs(Repodata *data);
+
+/*
+ * load all paged data, used to speed up copying in repo_rpmdb
+ */
+void repodata_disable_paging(Repodata *data);
+
+/* helper functions */
+Id repodata_globalize_id(Repodata *data, Id id, int create);
+Id repodata_localize_id(Repodata *data, Id id, int create);
+Id repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create);
+Id repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache);
+
+Id repodata_str2dir(Repodata *data, const char *dir, int create);
+const char *repodata_dir2str(Repodata *data, Id did, const char *suf);
+const char *repodata_chk2str(Repodata *data, Id type, const unsigned char *buf);
+void repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file);
+void repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file);
+void repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg);
+
+/* uninternalized data lookup / search */
+Repokey *repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, struct s_KeyValue *kv);
+void repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
+
+/* stats */
+unsigned int repodata_memused(Repodata *data);
+
+static inline Id
+repodata_translate_dir(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache)
+{
+  if (cache && dir && cache[(dir & 255) * 2] == dir)
+    return cache[(dir & 255) * 2 + 1];
+  return repodata_translate_dir_slow(data, fromdata, dir, create, cache);
+}
+
+static inline Id *
+repodata_create_dirtranscache(Repodata *data)
+{
+  return (Id *)solv_calloc(256, sizeof(Id) * 2);
+}
+
+static inline Id *
+repodata_free_dirtranscache(Id *cache)
+{
+  return (Id *)solv_free(cache);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_REPODATA_H */
diff --git a/libsolv-0.7.2/src/repopack.h b/libsolv-0.7.2/src/repopack.h
new file mode 100644 (file)
index 0000000..e63366d
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* pack/unpack functions for key data */
+
+#ifndef LIBSOLV_REPOPACK_H
+#define LIBSOLV_REPOPACK_H
+
+static inline unsigned char *
+data_read_id(unsigned char *dp, Id *idp)
+{
+  Id x;
+  unsigned char c;
+  if (!(dp[0] & 0x80))
+    {
+      *idp = dp[0];
+      return dp + 1;
+    }
+  if (!(dp[1] & 0x80))
+    {
+      *idp = dp[0] << 7 ^ dp[1] ^ 0x4000;
+      return dp + 2;
+    }
+  if (!(dp[2] & 0x80))
+    {
+      *idp = dp[0] << 14 ^ dp[1] << 7 ^ dp[2] ^ 0x204000;
+      return dp + 3;
+    }
+  if (!(dp[3] & 0x80))
+    {
+      *idp = dp[0] << 21 ^ dp[1] << 14 ^ dp[2] << 7 ^ dp[3] ^ 0x10204000;
+      return dp + 4;
+    }
+  x = dp[0] << 28 ^ dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204000;
+  if (!(dp[4] & 0x80))
+    {
+      *idp = x;
+      return dp + 5;
+    }
+  x ^= 80;
+  dp += 5;
+  for (;;)
+    {
+      c = *dp++;
+      if (!(c & 0x80))
+        {
+          *idp = (x << 7) ^ c;
+          return dp;
+        }
+      x = (x << 7) ^ (c ^ 128);
+    }
+}
+
+static inline unsigned char *
+data_read_num64(unsigned char *dp, unsigned int *low, unsigned int *high)
+{
+  unsigned long long int x;
+  unsigned char c;
+
+  *high = 0;
+  if (!(dp[0] & 0x80))
+    {
+      *low = dp[0];
+      return dp + 1;
+    }
+  if (!(dp[1] & 0x80))
+    {
+      *low = dp[0] << 7 ^ dp[1] ^ 0x4000;
+      return dp + 2;
+    }
+  if (!(dp[2] & 0x80))
+    {
+      *low = dp[0] << 14 ^ dp[1] << 7 ^ dp[2] ^ 0x204000;
+      return dp + 3;
+    }
+  if (!(dp[3] & 0x80))
+    {
+      *low = dp[0] << 21 ^ dp[1] << 14 ^ dp[2] << 7 ^ dp[3] ^ 0x10204000;
+      return dp + 4;
+    }
+  if (!(dp[4] & 0x80))
+    {
+      *low = dp[0] << 28 ^ dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204000;
+      *high = (dp[0] ^ 0x80) >> 4;
+      return dp + 5;
+    }
+  x = (unsigned long long)(dp[0] ^ 0x80) << 28 ^ (unsigned int)(dp[1] << 21 ^ dp[2] << 14 ^ dp[3] << 7 ^ dp[4] ^ 0x10204080);
+  dp += 5;
+  for (;;)
+    {
+      c = *dp++;
+      if (!(c & 0x80))
+       {
+         x = (x << 7) ^ c;
+         *low = x;
+         *high = x >> 32;
+         return dp;
+       }
+      x = (x << 7) ^ (c ^ 128);
+    }
+}
+
+static inline unsigned char *
+data_read_ideof(unsigned char *dp, Id *idp, int *eof)
+{
+  Id x = 0;
+  unsigned char c;
+  for (;;)
+    {
+      c = *dp++;
+      if (!(c & 0x80))
+        {
+          if (c & 0x40)
+            {
+              c ^= 0x40;
+              *eof = 0;
+            }
+          else
+            *eof = 1;
+          *idp = (x << 6) ^ c;
+          return dp;
+        }
+      x = (x << 7) ^ c ^ 128;
+    }
+}
+
+static inline unsigned char *
+data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
+{
+  kv->eof = 1;
+  if (!dp)
+    return 0;
+  switch (key->type)
+    {
+    case REPOKEY_TYPE_VOID:
+    case REPOKEY_TYPE_DELETED:
+      return dp;
+    case REPOKEY_TYPE_CONSTANT:
+      kv->num2 = 0;
+      kv->num = key->size;
+      return dp;
+    case REPOKEY_TYPE_CONSTANTID:
+      kv->id = key->size;
+      return dp;
+    case REPOKEY_TYPE_STR:
+      kv->str = (const char *)dp;
+      return dp + strlen(kv->str) + 1;
+    case REPOKEY_TYPE_ID:
+    case REPOKEY_TYPE_DIR:
+      return data_read_id(dp, &kv->id);
+    case REPOKEY_TYPE_NUM:
+      return data_read_num64(dp, &kv->num, &kv->num2);
+    case REPOKEY_TYPE_MD5:
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + SIZEOF_MD5;
+    case REPOKEY_TYPE_SHA1:
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + SIZEOF_SHA1;
+    case REPOKEY_TYPE_SHA224:
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + SIZEOF_SHA224;
+    case REPOKEY_TYPE_SHA256:
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + SIZEOF_SHA256;
+    case REPOKEY_TYPE_SHA384:
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + SIZEOF_SHA384;
+    case REPOKEY_TYPE_SHA512:
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + SIZEOF_SHA512;
+    case REPOKEY_TYPE_BINARY:
+      dp = data_read_id(dp, (Id *)&kv->num);
+      kv->str = (const char *)dp;
+      return dp + kv->num;
+    case REPOKEY_TYPE_IDARRAY:
+      return data_read_ideof(dp, &kv->id, &kv->eof);
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      dp = data_read_ideof(dp, &kv->id, &kv->eof);
+      kv->num = 0;     /* not stringified yet */
+      kv->str = (const char *)dp;
+      return dp + strlen(kv->str) + 1;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      dp = data_read_id(dp, &kv->id);
+      dp = data_read_id(dp, (Id *)&kv->num);
+      return data_read_ideof(dp, (Id *)&kv->num2, &kv->eof);
+    case REPOKEY_TYPE_FIXARRAY:
+    case REPOKEY_TYPE_FLEXARRAY:
+      if (!kv->entry)
+       {
+          dp = data_read_id(dp, (Id *)&kv->num);       /* number of elements */
+         if (!kv->num)
+           return 0;           /* illegal */
+       }
+      if (!kv->entry || key->type == REPOKEY_TYPE_FLEXARRAY)
+        dp = data_read_id(dp, &kv->id);        /* schema */
+      kv->str = (const char *)dp;
+      return dp;
+    default:
+      return 0;
+    }
+}
+
+static inline unsigned char *
+data_skip(unsigned char *dp, int type)
+{
+  unsigned char x;
+  switch (type)
+    {
+    case REPOKEY_TYPE_VOID:
+    case REPOKEY_TYPE_CONSTANT:
+    case REPOKEY_TYPE_CONSTANTID:
+    case REPOKEY_TYPE_DELETED:
+      return dp;
+    case REPOKEY_TYPE_ID:
+    case REPOKEY_TYPE_NUM:
+    case REPOKEY_TYPE_DIR:
+      while ((*dp & 0x80) != 0)
+        dp++;
+      return dp + 1;
+    case REPOKEY_TYPE_MD5:
+      return dp + SIZEOF_MD5;
+    case REPOKEY_TYPE_SHA1:
+      return dp + SIZEOF_SHA1;
+    case REPOKEY_TYPE_SHA224:
+      return dp + SIZEOF_SHA224;
+    case REPOKEY_TYPE_SHA256:
+      return dp + SIZEOF_SHA256;
+    case REPOKEY_TYPE_SHA384:
+      return dp + SIZEOF_SHA384;
+    case REPOKEY_TYPE_SHA512:
+      return dp + SIZEOF_SHA512;
+    case REPOKEY_TYPE_IDARRAY:
+    case REPOKEY_TYPE_REL_IDARRAY:
+      while ((*dp & 0xc0) != 0)
+        dp++;
+      return dp + 1;
+    case REPOKEY_TYPE_STR:
+      while ((*dp) != 0)
+        dp++;
+      return dp + 1;
+    case REPOKEY_TYPE_BINARY:
+      {
+       unsigned int len;
+       dp = data_read_id(dp, (Id *)&len);
+       return dp + len;
+      }
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      for (;;)
+        {
+          while ((*dp & 0x80) != 0)
+            dp++;
+          x = *dp++;
+          while ((*dp) != 0)
+            dp++;
+          dp++;
+          if (!(x & 0x40))
+            return dp;
+        }
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      for (;;)
+        {
+          while ((*dp & 0x80) != 0)
+            dp++;
+          dp++;
+          while ((*dp & 0x80) != 0)
+            dp++;
+          dp++;
+          while ((*dp & 0x80) != 0)
+            dp++;
+          if (!(*dp & 0x40))
+            return dp + 1;
+          dp++;
+        }
+    default:
+      return 0;
+    }
+}
+
+#endif /* LIBSOLV_REPOPACK */
diff --git a/libsolv-0.7.2/src/repopage.c b/libsolv-0.7.2/src/repopage.c
new file mode 100644 (file)
index 0000000..2b7a863
--- /dev/null
@@ -0,0 +1,1037 @@
+/*
+ * Copyright (c) 2007-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repopage.c
+ *
+ * Paging and compression functions for the vertical repository data.
+ * Vertical data is grouped by key, normal data is grouped by solvable.
+ * This makes searching for a string in vertical data fast as there's
+ * no need to skip over data if keys we're not interested in.
+ *
+ * The vertical data is split into pages, each page is compressed with a fast
+ * compression algorithm. These pages are read in on demand, not recently used
+ * pages automatically get dropped.
+ */
+
+#define _XOPEN_SOURCE 500
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "repo.h"
+#include "repopage.h"
+
+
+
+#define BLOCK_SIZE (65536*1)
+#if BLOCK_SIZE <= 65536
+typedef uint16_t Ref;
+#else
+typedef uint32_t Ref;
+#endif
+
+/*
+   The format is tailored for fast decompression (i.e. only byte based),
+   and skewed to ASCII content (highest bit often not set):
+
+   a 0LLLLLLL
+        - self-describing ASCII character hex L
+   b 100lllll <l+1 bytes>
+        - literal run of length l+1
+   c 101oolll <8o>
+        - back ref of length l+2, at offset -(o+1) (o < 1 << 10)
+   d 110lllll <8o>
+        - back ref of length l+2+8, at offset -(o+1) (o < 1 << 8)
+   e 1110llll <8o> <8o>
+        - back ref of length l+3, at offset -(o+1) (o < 1 << 16)
+  f1 1111llll <8l> <8o> <8o>
+        - back ref, length l+19 (l < 1<<12), offset -(o+1) (o < 1<<16)
+  f2 11110lll <8l> <8o> <8o>
+        - back ref, length l+19 (l < 1<<11), offset -(o+1) (o < 1<<16)
+   g 11111lll <8l> <8o> <8o> <8o>
+        - back ref, length l+5 (l < 1<<11), offset -(o+1) (o < 1<<24)
+
+   Generally for a literal of length L we need L+1 bytes, hence it is
+   better to encode also very short backrefs (2 chars) as backrefs if
+   their offset is small, as that only needs two bytes.  Except if we
+   already have a literal run, in that case it's better to append there,
+   instead of breaking it for a backref.  So given a potential backref
+   at offset O, length L the strategy is as follows:
+
+   L < 2 : encode as 1-literal
+   L == 2, O > 1024 : encode as 1-literal
+   L == 2, have already literals: encode as 1-literal
+   O = O - 1
+   L >= 2, L <= 9, O < 1024                            : encode as c
+   L >= 10, L <= 41, O < 256                           : encode as d
+   else we have either O >= 1024, or L >= 42:
+   L < 3 : encode as 1-literal
+   L >= 3, L <= 18, O < 65536                          : encode as e
+   L >= 19, L <= 4095+18, O < 65536                    : encode as f
+   else we have either L >= 4096+18 or O >= 65536.
+   O >= 65536: encode as 1-literal, too bad
+     (with the current block size this can't happen)
+   L >= 4096+18, so reduce to 4095+18                  : encode as f
+*/
+
+
+static unsigned int
+compress_buf(const unsigned char *in, unsigned int in_len,
+             unsigned char *out, unsigned int out_len)
+{
+  unsigned int oo = 0;         /* out-offset */
+  unsigned int io = 0;         /* in-offset */
+#define HS (65536)
+  Ref htab[HS];
+  Ref hnext[BLOCK_SIZE];
+  unsigned int litofs = 0;
+  memset(htab, -1, sizeof (htab));
+  memset(hnext, -1, sizeof (hnext));
+  while (io + 2 < in_len)
+    {
+      /* Search for a match of the string starting at IN, we have at
+         least three characters.  */
+      unsigned int hval = in[io] | in[io + 1] << 8 | in[io + 2] << 16;
+      unsigned int try, mlen, mofs, tries;
+      hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
+      hval = hval & (HS - 1);
+      try = htab[hval];
+      hnext[io] = htab[hval];
+      htab[hval] = io;
+      mlen = 0;
+      mofs = 0;
+
+      for (tries = 0; try != -1 && tries < 12; tries++)
+        {
+         if (try < io
+             && in[try] == in[io] && in[try + 1] == in[io + 1])
+           {
+             mlen = 2;
+             mofs = (io - try) - 1;
+             break;
+           }
+         try = hnext[try];
+       }
+      for (; try != -1 && tries < 12; tries++)
+       {
+         /* assert(mlen >= 2); */
+         /* assert(io + mlen < in_len); */
+         /* Try a match starting from [io] with the strings at [try].
+            That's only sensible if TRY actually is before IO (can happen
+            with uninit hash table).  If we have a previous match already
+            we're only going to take the new one if it's longer, hence
+            check the potentially last character.  */
+         if (try < io && in[try + mlen] == in[io + mlen])
+           {
+             unsigned int this_len, this_ofs;
+             if (memcmp(in + try, in + io, mlen))
+               goto no_match;
+             this_len = mlen + 1;
+             /* Now try extending the match by more characters.  */
+             for (;
+                  io + this_len < in_len
+                  && in[try + this_len] == in[io + this_len]; this_len++)
+               ;
+#if 0
+             unsigned int testi;
+             for (testi = 0; testi < this_len; testi++)
+               assert(in[try + testi] == in[io + testi]);
+#endif
+             this_ofs = (io - try) - 1;
+             /*if (this_ofs > 65535)
+                goto no_match; */
+#if 0
+             assert(this_len >= 2);
+             assert(this_len >= mlen);
+             assert(this_len > mlen || (this_len == mlen && this_ofs > mofs));
+#endif
+             mlen = this_len, mofs = this_ofs;
+             /* If our match extends up to the end of input, no next
+                match can become better.  This is not just an
+                optimization, it establishes a loop invariant
+                (io + mlen < in_len).  */
+             if (io + mlen >= in_len)
+               goto match_done;
+           }
+       no_match:
+         try = hnext[try];
+         /*if (io - try - 1 >= 65536)
+           break;*/
+       }
+
+match_done:
+      if (mlen)
+       {
+         /*fprintf(stderr, "%d %d\n", mlen, mofs);*/
+         if (mlen == 2 && (litofs || mofs >= 1024))
+           mlen = 0;
+         /*else if (mofs >= 65536)
+           mlen = 0;*/
+         else if (mofs >= 65536)
+           {
+             if (mlen >= 2048 + 5)
+               mlen = 2047 + 5;
+             else if (mlen < 5)
+               mlen = 0;
+           }
+         else if (mlen < 3)
+           mlen = 0;
+         /*else if (mlen >= 4096 + 19)
+           mlen = 4095 + 19;*/
+         else if (mlen >= 2048 + 19)
+           mlen = 2047 + 19;
+         /* Skip this match if the next character would deliver a better one,
+            but only do this if we have the chance to really extend the
+            length (i.e. our current length isn't yet the (conservative)
+            maximum).  */
+         if (mlen && mlen < (2048 + 5) && io + 3 < in_len)
+           {
+             unsigned int hval =
+               in[io + 1] | in[io + 2] << 8 | in[io + 3] << 16;
+             unsigned int try;
+             hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
+             hval = hval & (HS - 1);
+             try = htab[hval];
+             if (try < io + 1
+                 && in[try] == in[io + 1] && in[try + 1] == in[io + 2])
+               {
+                 unsigned int this_len;
+                 this_len = 2;
+                 for (;
+                      io + 1 + this_len < in_len
+                      && in[try + this_len] == in[io + 1 + this_len];
+                      this_len++)
+                   ;
+                 if (this_len >= mlen)
+                   mlen = 0;
+               }
+           }
+       }
+      if (!mlen)
+       {
+         if (!litofs)
+           litofs = io + 1;
+         io++;
+       }
+      else
+       {
+         if (litofs)
+           {
+             unsigned litlen;
+             litofs--;
+             litlen = io - litofs;
+             /* fprintf(stderr, "lit: %d\n", litlen); */
+             while (litlen)
+               {
+                 unsigned int easy_sz;
+                 /* Emit everything we can as self-describers.  As soon as
+                    we hit a byte we can't emit as such we're going to emit
+                    a length descriptor anyway, so we can as well include
+                    bytes < 0x80 which might follow afterwards in that run.  */
+                 for (easy_sz = 0;
+                      easy_sz < litlen && in[litofs + easy_sz] < 0x80;
+                      easy_sz++)
+                   ;
+                 if (easy_sz)
+                   {
+                     if (oo + easy_sz >= out_len)
+                       return 0;
+                     memcpy(out + oo, in + litofs, easy_sz);
+                     litofs += easy_sz;
+                     oo += easy_sz;
+                     litlen -= easy_sz;
+                     if (!litlen)
+                       break;
+                   }
+                 if (litlen <= 32)
+                   {
+                     if (oo + 1 + litlen >= out_len)
+                       return 0;
+                     out[oo++] = 0x80 | (litlen - 1);
+                     while (litlen--)
+                       out[oo++] = in[litofs++];
+                     break;
+                   }
+                 else
+                   {
+                     /* Literal length > 32, so chunk it.  */
+                     if (oo + 1 + 32 >= out_len)
+                       return 0;
+                     out[oo++] = 0x80 | 31;
+                     memcpy(out + oo, in + litofs, 32);
+                     oo += 32;
+                     litofs += 32;
+                     litlen -= 32;
+                   }
+               }
+             litofs = 0;
+           }
+
+         /* fprintf(stderr, "ref: %d @ %d\n", mlen, mofs); */
+
+         if (mlen >= 2 && mlen <= 9 && mofs < 1024)
+           {
+             if (oo + 2 >= out_len)
+               return 0;
+             out[oo++] = 0xa0 | ((mofs & 0x300) >> 5) | (mlen - 2);
+             out[oo++] = mofs & 0xff;
+           }
+         else if (mlen >= 10 && mlen <= 41 && mofs < 256)
+           {
+             if (oo + 2 >= out_len)
+               return 0;
+             out[oo++] = 0xc0 | (mlen - 10);
+             out[oo++] = mofs;
+           }
+         else if (mofs >= 65536)
+           {
+             assert(mlen >= 5 && mlen < 2048 + 5);
+             if (oo + 5 >= out_len)
+               return 0;
+             out[oo++] = 0xf8 | ((mlen - 5) >> 8);
+             out[oo++] = (mlen - 5) & 0xff;
+             out[oo++] = mofs & 0xff;
+             out[oo++] = (mofs >> 8) & 0xff;
+             out[oo++] = mofs >> 16;
+           }
+         else if (mlen >= 3 && mlen <= 18)
+           {
+             assert(mofs < 65536);
+             if (oo + 3 >= out_len)
+               return 0;
+             out[oo++] = 0xe0 | (mlen - 3);
+             out[oo++] = mofs & 0xff;
+             out[oo++] = mofs >> 8;
+           }
+         else
+           {
+             assert(mlen >= 19 && mlen <= 4095 + 19 && mofs < 65536);
+             if (oo + 4 >= out_len)
+               return 0;
+             out[oo++] = 0xf0 | ((mlen - 19) >> 8);
+             out[oo++] = (mlen - 19) & 0xff;
+             out[oo++] = mofs & 0xff;
+             out[oo++] = mofs >> 8;
+           }
+         /* Insert the hashes for the compressed run [io..io+mlen-1].
+            For [io] we have it already done at the start of the loop.
+            So it's from [io+1..io+mlen-1], and we need three chars per
+            hash, so the accessed characters will be [io+1..io+mlen-1+2],
+            ergo io+mlen+1 < in_len.  */
+         mlen--;
+         io++;
+         while (mlen--)
+           {
+             if (io + 2 < in_len)
+               {
+                 unsigned int hval =
+                   in[io] | in[io + 1] << 8 | in[io + 2] << 16;
+                 hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
+                 hval = hval & (HS - 1);
+                 hnext[io] = htab[hval];
+                 htab[hval] = io;
+               }
+             io++;
+           };
+       }
+    }
+  /* We might have some characters left.  */
+  if (io < in_len && !litofs)
+    litofs = io + 1;
+  io = in_len;
+  if (litofs)
+    {
+      unsigned litlen;
+      litofs--;
+      litlen = io - litofs;
+      /* fprintf(stderr, "lit: %d\n", litlen); */
+      while (litlen)
+       {
+         unsigned int easy_sz;
+         /* Emit everything we can as self-describers.  As soon as we hit a
+            byte we can't emit as such we're going to emit a length
+            descriptor anyway, so we can as well include bytes < 0x80 which
+            might follow afterwards in that run.  */
+         for (easy_sz = 0; easy_sz < litlen && in[litofs + easy_sz] < 0x80;
+              easy_sz++)
+           ;
+         if (easy_sz)
+           {
+             if (oo + easy_sz >= out_len)
+               return 0;
+             memcpy(out + oo, in + litofs, easy_sz);
+             litofs += easy_sz;
+             oo += easy_sz;
+             litlen -= easy_sz;
+             if (!litlen)
+               break;
+           }
+         if (litlen <= 32)
+           {
+             if (oo + 1 + litlen >= out_len)
+               return 0;
+             out[oo++] = 0x80 | (litlen - 1);
+             while (litlen--)
+               out[oo++] = in[litofs++];
+             break;
+           }
+         else
+           {
+             /* Literal length > 32, so chunk it.  */
+             if (oo + 1 + 32 >= out_len)
+               return 0;
+             out[oo++] = 0x80 | 31;
+             memcpy(out + oo, in + litofs, 32);
+             oo += 32;
+             litofs += 32;
+             litlen -= 32;
+           }
+       }
+      litofs = 0;
+    }
+  return oo;
+}
+
+static unsigned int
+unchecked_decompress_buf(const unsigned char *in, unsigned int in_len,
+                         unsigned char *out,
+                         unsigned int out_len __attribute__((unused)))
+{
+  unsigned char *orig_out = out;
+  const unsigned char *in_end = in + in_len;
+  while (in < in_end)
+    {
+      unsigned int first = *in++;
+      int o;
+      switch (first >> 4)
+       {
+       default:
+         /* This default case can't happen, but GCCs VRP is not strong
+            enough to see this, so make this explicitely not fall to
+            the end of the switch, so that we don't have to initialize
+            o above.  */
+         continue;
+       case 0: case 1:
+       case 2: case 3:
+       case 4: case 5:
+       case 6: case 7:
+         /* a 0LLLLLLL */
+         /* fprintf (stderr, "lit: 1\n"); */
+         *out++ = first;
+         continue;
+       case 8: case 9:
+         /* b 100lllll <l+1 bytes> */
+         {
+           unsigned int l = first & 31;
+           /* fprintf (stderr, "lit: %d\n", l); */
+           do
+             *out++ = *in++;
+           while (l--);
+           continue;
+         }
+       case 10: case 11:
+         /* c 101oolll <8o> */
+         {
+           o = first & (3 << 3);
+           o = (o << 5) | *in++;
+           first = (first & 7) + 2;
+           break;
+         }
+       case 12: case 13:
+         /* d 110lllll <8o> */
+         {
+           o = *in++;
+           first = (first & 31) + 10;
+           break;
+         }
+       case 14:
+         /* e 1110llll <8o> <8o> */
+         {
+           o = in[0] | (in[1] << 8);
+           in += 2;
+           first = first & 31;
+           first += 3;
+           break;
+         }
+       case 15:
+         /* f1 1111llll <8o> <8o> <8l> */
+         /* f2 11110lll <8o> <8o> <8l> */
+         /* g 11111lll <8o> <8o> <8o> <8l> */
+         {
+           first = first & 15;
+           if (first >= 8)
+             {
+               first = (((first - 8) << 8) | in[0]) + 5;
+               o = in[1] | (in[2] << 8) | (in[3] << 16);
+               in += 4;
+             }
+           else
+             {
+               first = ((first << 8) | in[0]) + 19;
+               o = in[1] | (in[2] << 8);
+               in += 3;
+             }
+           break;
+         }
+       }
+      /* fprintf(stderr, "ref: %d @ %d\n", first, o); */
+      o++;
+      o = -o;
+#if 0
+      /* We know that first will not be zero, and this loop structure is
+         better optimizable.  */
+      do
+       {
+         *out = *(out - o);
+         out++;
+       }
+      while (--first);
+#else
+      switch (first)
+        {
+         case 18: *out = *(out + o); out++;
+         case 17: *out = *(out + o); out++;
+         case 16: *out = *(out + o); out++;
+         case 15: *out = *(out + o); out++;
+         case 14: *out = *(out + o); out++;
+         case 13: *out = *(out + o); out++;
+         case 12: *out = *(out + o); out++;
+         case 11: *out = *(out + o); out++;
+         case 10: *out = *(out + o); out++;
+         case  9: *out = *(out + o); out++;
+         case  8: *out = *(out + o); out++;
+         case  7: *out = *(out + o); out++;
+         case  6: *out = *(out + o); out++;
+         case  5: *out = *(out + o); out++;
+         case  4: *out = *(out + o); out++;
+         case  3: *out = *(out + o); out++;
+         case  2: *out = *(out + o); out++;
+         case  1: *out = *(out + o); out++;
+         case  0: break;
+         default:
+           /* Duff duff :-) */
+           switch (first & 15)
+             {
+               do
+                 {
+                   case  0: *out = *(out + o); out++;
+                   case 15: *out = *(out + o); out++;
+                   case 14: *out = *(out + o); out++;
+                   case 13: *out = *(out + o); out++;
+                   case 12: *out = *(out + o); out++;
+                   case 11: *out = *(out + o); out++;
+                   case 10: *out = *(out + o); out++;
+                   case  9: *out = *(out + o); out++;
+                   case  8: *out = *(out + o); out++;
+                   case  7: *out = *(out + o); out++;
+                   case  6: *out = *(out + o); out++;
+                   case  5: *out = *(out + o); out++;
+                   case  4: *out = *(out + o); out++;
+                   case  3: *out = *(out + o); out++;
+                   case  2: *out = *(out + o); out++;
+                   case  1: *out = *(out + o); out++;
+                 }
+               while ((int)(first -= 16) > 0);
+             }
+           break;
+       }
+#endif
+    }
+  return out - orig_out;
+}
+
+/**********************************************************************/
+
+void repopagestore_init(Repopagestore *store)
+{
+  memset(store, 0, sizeof(*store));
+  store->pagefd = -1;
+}
+
+void repopagestore_free(Repopagestore *store)
+{
+  store->blob_store = solv_free(store->blob_store);
+  store->file_pages = solv_free(store->file_pages);
+  store->mapped_at = solv_free(store->mapped_at);
+  store->mapped = solv_free(store->mapped);
+  if (store->pagefd != -1)
+    close(store->pagefd);
+  store->pagefd = -1;
+}
+
+
+/**********************************************************************/
+
+unsigned char *
+repopagestore_load_page_range(Repopagestore *store, unsigned int pstart, unsigned int pend)
+{
+/* Make sure all pages from PSTART to PEND (inclusive) are loaded,
+   and are consecutive.  Return a pointer to the mapping of PSTART.  */
+  unsigned char buf[REPOPAGE_BLOBSIZE];
+  unsigned int i, best, pnum;
+
+  if (pstart == pend)
+    {
+      /* Quick check in case the requested page is already mapped */
+      if (store->mapped_at[pstart] != -1)
+       return store->blob_store + store->mapped_at[pstart];
+    }
+  else
+    {
+      /* Quick check in case all pages are already mapped and consecutive.  */
+      for (pnum = pstart; pnum <= pend; pnum++)
+       if (store->mapped_at[pnum] == -1
+           || (pnum > pstart
+               && store->mapped_at[pnum]
+                  != store->mapped_at[pnum-1] + REPOPAGE_BLOBSIZE))
+         break;
+      if (pnum > pend)
+       return store->blob_store + store->mapped_at[pstart];
+    }
+
+  if (store->pagefd == -1 || !store->file_pages)
+    return 0;  /* no backing file */
+
+#ifdef DEBUG_PAGING
+  fprintf(stderr, "PAGE: want %d pages starting at %d\n", pend - pstart + 1, pstart);
+#endif
+
+  /* Ensure that we can map the numbers of pages we need at all.  */
+  if (pend - pstart + 1 > store->nmapped)
+    {
+      unsigned int oldcan = store->nmapped;
+      store->nmapped = pend - pstart + 1;
+      if (store->nmapped < 4)
+        store->nmapped = 4;
+      store->mapped = solv_realloc2(store->mapped, store->nmapped, sizeof(store->mapped[0]));
+      for (i = oldcan; i < store->nmapped; i++)
+       store->mapped[i] = -1;
+      store->blob_store = solv_realloc2(store->blob_store, store->nmapped, REPOPAGE_BLOBSIZE);
+#ifdef DEBUG_PAGING
+      fprintf(stderr, "PAGE: can map %d pages\n", store->nmapped);
+#endif
+    }
+
+  if (store->mapped_at[pstart] != -1)
+    {
+      /* assume forward search */
+      best = store->mapped_at[pstart] / REPOPAGE_BLOBSIZE;
+      if (best + (pend - pstart) >= store->nmapped)
+       best = 0;
+    }
+  else if (store->mapped_at[pend] != -1)
+    {
+      /* assume backward search */
+      best = store->mapped_at[pend] / REPOPAGE_BLOBSIZE;
+      if (best < pend - pstart)
+       best = store->nmapped - 1;
+      best -= pend - pstart;
+    }
+  else
+    {
+      /* choose some "random" location to avoid thrashing */
+      best = (pstart + store->rr_counter++) % (store->nmapped - pend + pstart);
+    }
+
+  /* So we want to map our pages from [best] to [best+pend-pstart].
+     Use a very simple strategy, which doesn't make the best use of
+     our resources, but works.  Throw away all pages in that range
+     (even ours) then copy around ours or read them in.  */
+  for (i = best, pnum = pstart; pnum <= pend; i++, pnum++)
+    {
+      unsigned int pnum_mapped_at;
+      unsigned int oldpnum = store->mapped[i];
+      if (oldpnum != -1)
+       {
+         if (oldpnum == pnum)
+           continue;   /* already have the correct page */
+         /* Evict this page.  */
+#ifdef DEBUG_PAGING
+         fprintf(stderr, "PAGE: evict page %d from %d\n", oldpnum, i);
+#endif
+         store->mapped[i] = -1;
+         store->mapped_at[oldpnum] = -1;
+       }
+      /* check if we can copy the correct content (before it gets evicted) */
+      pnum_mapped_at = store->mapped_at[pnum];
+      if (pnum_mapped_at != -1 && pnum_mapped_at != i * REPOPAGE_BLOBSIZE)
+       {
+         void *dest = store->blob_store + i * REPOPAGE_BLOBSIZE;
+#ifdef DEBUG_PAGING
+         fprintf(stderr, "PAGECOPY: %d from %d to %d\n", pnum, pnum_mapped_at / REPOPAGE_BLOBSIZE, i);
+#endif
+         memcpy(dest, store->blob_store + pnum_mapped_at, REPOPAGE_BLOBSIZE);
+         store->mapped[pnum_mapped_at / REPOPAGE_BLOBSIZE] = -1;
+         store->mapped[i] = pnum;
+         store->mapped_at[pnum] = i * REPOPAGE_BLOBSIZE;
+       }
+    }
+
+  /* Everything is free now.  Read in or copy the pages we want.  */
+  for (i = best, pnum = pstart; pnum <= pend; i++, pnum++)
+    {
+      void *dest = store->blob_store + i * REPOPAGE_BLOBSIZE;
+      if (store->mapped_at[pnum] != -1)
+        {
+          unsigned int pnum_mapped_at = store->mapped_at[pnum];
+         if (pnum_mapped_at != i * REPOPAGE_BLOBSIZE)
+           {
+#ifdef DEBUG_PAGING
+             fprintf(stderr, "PAGECOPY: %d from %d to %d\n", pnum, pnum_mapped_at / REPOPAGE_BLOBSIZE, i);
+#endif
+             /* Still mapped somewhere else, so just copy it from there.  */
+             memcpy(dest, store->blob_store + pnum_mapped_at, REPOPAGE_BLOBSIZE);
+             store->mapped[pnum_mapped_at / REPOPAGE_BLOBSIZE] = -1;
+           }
+       }
+      else
+        {
+         Attrblobpage *p = store->file_pages + pnum;
+         unsigned int in_len = p->page_size;
+         unsigned int compressed = in_len & 1;
+         in_len >>= 1;
+#ifdef DEBUG_PAGING
+         fprintf(stderr, "PAGEIN: %d to %d", pnum, i);
+#endif
+          if (pread(store->pagefd, compressed ? buf : dest, in_len, store->file_offset + p->page_offset) != in_len)
+           {
+             perror("mapping pread");
+             return 0;
+           }
+         if (compressed)
+           {
+             unsigned int out_len;
+             out_len = unchecked_decompress_buf(buf, in_len, dest, REPOPAGE_BLOBSIZE);
+             if (out_len != REPOPAGE_BLOBSIZE && pnum < store->num_pages - 1)
+               {
+#ifdef DEBUG_PAGING
+                 fprintf(stderr, "can't decompress\n");
+#endif
+                 return 0;
+               }
+#ifdef DEBUG_PAGING
+             fprintf(stderr, " (expand %d to %d)", in_len, out_len);
+#endif
+           }
+#ifdef DEBUG_PAGING
+         fprintf(stderr, "\n");
+#endif
+       }
+      store->mapped_at[pnum] = i * REPOPAGE_BLOBSIZE;
+      store->mapped[i] = pnum;
+    }
+  return store->blob_store + best * REPOPAGE_BLOBSIZE;
+}
+
+unsigned int
+repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
+{
+  return compress_buf(page, len, cpage, max);
+}
+
+#define SOLV_ERROR_EOF         3
+#define SOLV_ERROR_CORRUPT     6
+
+static inline unsigned int
+read_u32(FILE *fp)
+{
+  int c, i;
+  unsigned int x = 0;
+
+  for (i = 0; i < 4; i++)
+    {
+      c = getc(fp);
+      if (c == EOF)
+        return 0;
+      x = (x << 8) | c;
+    }
+  return x;
+}
+
+/* Try to either setup on-demand paging (using FP as backing
+   file), or in case that doesn't work (FP not seekable) slurps in
+   all pages and deactivates paging.  */
+int
+repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int pagesz, unsigned int blobsz)
+{
+  unsigned int npages;
+  unsigned int i;
+  unsigned int can_seek;
+  unsigned int cur_page_ofs;
+  unsigned char buf[REPOPAGE_BLOBSIZE];
+
+  if (pagesz != REPOPAGE_BLOBSIZE)
+    {
+      /* We could handle this by slurping in everything.  */
+      return SOLV_ERROR_CORRUPT;
+    }
+  can_seek = 1;
+  if ((store->file_offset = ftell(fp)) < 0)
+    can_seek = 0;
+  clearerr(fp);
+  if (can_seek)
+    store->pagefd = dup(fileno(fp));
+  if (store->pagefd == -1)
+    can_seek = 0;
+  else
+    fcntl(store->pagefd, F_SETFD, FD_CLOEXEC);
+
+#ifdef DEBUG_PAGING
+  fprintf(stderr, "can %sseek\n", can_seek ? "" : "NOT ");
+#endif
+  npages = (blobsz + REPOPAGE_BLOBSIZE - 1) / REPOPAGE_BLOBSIZE;
+
+  store->num_pages = npages;
+  store->mapped_at = solv_malloc2(npages, sizeof(*store->mapped_at));
+
+  /* If we can't seek on our input we have to slurp in everything.
+   * Otherwise set up file_pages containing offest/length of the
+   * pages */
+  if (can_seek)
+    store->file_pages = solv_malloc2(npages, sizeof(*store->file_pages));
+  else
+    store->blob_store = solv_malloc2(npages, REPOPAGE_BLOBSIZE);
+  cur_page_ofs = 0;
+  for (i = 0; i < npages; i++)
+    {
+      unsigned int in_len = read_u32(fp);
+      unsigned int compressed = in_len & 1;
+      in_len >>= 1;
+#ifdef DEBUG_PAGING
+      fprintf(stderr, "page %d: len %d (%scompressed)\n",
+              i, in_len, compressed ? "" : "not ");
+#endif
+      if (can_seek)
+        {
+         Attrblobpage *p = store->file_pages + i;
+          cur_page_ofs += 4;
+          store->mapped_at[i] = -1;    /* not mapped yet */
+         p->page_offset = cur_page_ofs;
+         p->page_size = in_len * 2 + compressed;
+         if (fseek(fp, in_len, SEEK_CUR) < 0)
+           {
+             /* We can't fall back to non-seeking behaviour as we already
+                read over some data pages without storing them away.  */
+             close(store->pagefd);
+             store->pagefd = -1;
+             return SOLV_ERROR_EOF;
+           }
+         cur_page_ofs += in_len;
+       }
+      else
+        {
+         unsigned int out_len;
+         void *dest = store->blob_store + i * REPOPAGE_BLOBSIZE;
+          store->mapped_at[i] = i * REPOPAGE_BLOBSIZE;
+         /* We can't seek, so suck everything in.  */
+         if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
+           {
+             perror("fread");
+             return SOLV_ERROR_EOF;
+           }
+         if (compressed)
+           {
+             out_len = unchecked_decompress_buf(buf, in_len, dest, REPOPAGE_BLOBSIZE);
+             if (out_len != REPOPAGE_BLOBSIZE && i < npages - 1)
+               {
+                 return SOLV_ERROR_CORRUPT;
+               }
+           }
+       }
+    }
+  return 0;
+}
+
+void
+repopagestore_disable_paging(Repopagestore *store)
+{
+  if (store->num_pages)
+    repopagestore_load_page_range(store, 0, store->num_pages - 1);
+}
+
+#ifdef STANDALONE
+
+static void
+transfer_file(FILE * from, FILE * to, int compress)
+{
+  unsigned char inb[BLOCK_SIZE];
+  unsigned char outb[BLOCK_SIZE];
+  while (!feof (from) && !ferror (from))
+    {
+      unsigned int in_len, out_len;
+      if (compress)
+       {
+         in_len = fread(inb, 1, BLOCK_SIZE, from);
+         if (in_len)
+           {
+             unsigned char *b = outb;
+             out_len = compress_buf(inb, in_len, outb, sizeof (outb));
+             if (!out_len)
+               b = inb, out_len = in_len;
+             if (fwrite(&out_len, sizeof (out_len), 1, to) != 1)
+               {
+                 perror("write size");
+                 exit (1);
+               }
+             if (fwrite(b, out_len, 1, to) != 1)
+               {
+                 perror("write data");
+                 exit (1);
+               }
+           }
+       }
+      else
+       {
+         if (fread(&in_len, sizeof(in_len), 1, from) != 1)
+           {
+             if (feof(from))
+               return;
+             perror("can't read size");
+             exit(1);
+           }
+         if (fread(inb, in_len, 1, from) != 1)
+           {
+             perror("can't read data");
+             exit(1);
+           }
+         out_len =
+           unchecked_decompress_buf(inb, in_len, outb, sizeof(outb));
+         if (fwrite(outb, out_len, 1, to) != 1)
+           {
+             perror("can't write output");
+             exit(1);
+           }
+       }
+    }
+}
+
+/* Just for benchmarking purposes.  */
+static void
+dumb_memcpy(void *dest, const void *src, unsigned int len)
+{
+  char *d = dest;
+  const char *s = src;
+  while (len--)
+    *d++ = *s++;
+}
+
+static void
+benchmark(FILE * from)
+{
+  unsigned char inb[BLOCK_SIZE];
+  unsigned char outb[BLOCK_SIZE];
+  unsigned int in_len = fread(inb, 1, BLOCK_SIZE, from);
+  unsigned int out_len;
+  if (!in_len)
+    {
+      perror("can't read from input");
+      exit(1);
+    }
+
+  unsigned int calib_loop;
+  unsigned int per_loop;
+  unsigned int i, j;
+  clock_t start, end;
+  float seconds;
+
+#if 0
+  calib_loop = 1;
+  per_loop = 0;
+  start = clock();
+  while ((clock() - start) < CLOCKS_PER_SEC / 4)
+    {
+      calib_loop *= 2;
+      for (i = 0; i < calib_loop; i++)
+       dumb_memcpy(outb, inb, in_len);
+      per_loop += calib_loop;
+    }
+
+  fprintf(stderr, "memcpy:\nCalibrated to %d iterations per loop\n",
+          per_loop);
+
+  start = clock();
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < per_loop; j++)
+      dumb_memcpy(outb, inb, in_len);
+  end = clock();
+  seconds = (end - start) / (float) CLOCKS_PER_SEC;
+  fprintf(stderr, "%.2f seconds == %.2f MB/s\n", seconds,
+          ((long long) in_len * per_loop * 10) / (1024 * 1024 * seconds));
+#endif
+
+  calib_loop = 1;
+  per_loop = 0;
+  start = clock();
+  while ((clock() - start) < CLOCKS_PER_SEC / 4)
+    {
+      calib_loop *= 2;
+      for (i = 0; i < calib_loop; i++)
+       compress_buf(inb, in_len, outb, sizeof(outb));
+      per_loop += calib_loop;
+    }
+
+  fprintf(stderr, "compression:\nCalibrated to %d iterations per loop\n",
+          per_loop);
+
+  start = clock();
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < per_loop; j++)
+      compress_buf(inb, in_len, outb, sizeof(outb));
+  end = clock();
+  seconds = (end - start) / (float) CLOCKS_PER_SEC;
+  fprintf(stderr, "%.2f seconds == %.2f MB/s\n", seconds,
+          ((long long) in_len * per_loop * 10) / (1024 * 1024 * seconds));
+
+  out_len = compress_buf(inb, in_len, outb, sizeof(outb));
+
+  calib_loop = 1;
+  per_loop = 0;
+  start = clock();
+  while ((clock() - start) < CLOCKS_PER_SEC / 4)
+    {
+      calib_loop *= 2;
+      for (i = 0; i < calib_loop; i++)
+       unchecked_decompress_buf(outb, out_len, inb, sizeof(inb));
+      per_loop += calib_loop;
+    }
+
+  fprintf(stderr, "decompression:\nCalibrated to %d iterations per loop\n",
+          per_loop);
+
+  start = clock();
+  for (i = 0; i < 10; i++)
+    for (j = 0; j < per_loop; j++)
+      unchecked_decompress_buf(outb, out_len, inb, sizeof(inb));
+  end = clock();
+  seconds = (end - start) / (float) CLOCKS_PER_SEC;
+  fprintf(stderr, "%.2f seconds == %.2f MB/s\n", seconds,
+          ((long long) in_len * per_loop * 10) / (1024 * 1024 * seconds));
+}
+
+int
+main(int argc, char *argv[])
+{
+  int compress = 1;
+  if (argc > 1 && !strcmp(argv[1], "-d"))
+    compress = 0;
+  if (argc > 1 && !strcmp(argv[1], "-b"))
+    benchmark(stdin);
+  else
+    transfer_file(stdin, stdout, compress);
+  return 0;
+}
+
+#endif
+
diff --git a/libsolv-0.7.2/src/repopage.h b/libsolv-0.7.2/src/repopage.h
new file mode 100644 (file)
index 0000000..b5f2eee
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007-2011, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef LIBSOLV_REPOPAGE_H
+#define LIBSOLV_REPOPAGE_H
+
+#define REPOPAGE_BLOBBITS 15
+#define REPOPAGE_BLOBSIZE (1 << REPOPAGE_BLOBBITS)
+
+typedef struct s_Attrblobpage
+{
+  /* page_size == 0 means the page is not backed by some file storage.
+     Otherwise it is L*2+(compressed ? 1 : 0), with L being the data
+     length.  */
+  unsigned int page_offset;
+  unsigned int page_size;
+} Attrblobpage;
+
+typedef struct s_Repopagestore {
+  int pagefd;          /* file descriptor we're paging from */
+  long file_offset;    /* pages in file start here */
+
+  unsigned char *blob_store;
+  unsigned int num_pages;
+
+  /* mapped_at[page] == -1  --> not loaded, otherwise offset into
+     store->blob_store.  The size of the mapping is REPOPAGE_BLOBSIZE
+     except for the last page.  */
+  unsigned int *mapped_at;
+
+  Attrblobpage *file_pages;
+
+  /* mapped[i] is -1 if nothing is mapped at logical page I,
+   otherwise it contains the page number (of the mapped page).  */
+  unsigned int *mapped;
+  unsigned int nmapped;
+  unsigned int rr_counter;
+} Repopagestore;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void repopagestore_init(Repopagestore *store);
+void repopagestore_free(Repopagestore *store);
+
+/* load pages pstart..pend into consecutive memory, return address */
+unsigned char *repopagestore_load_page_range(Repopagestore *store, unsigned int pstart, unsigned int pend);
+
+/* compress a page, return compressed len */
+unsigned int repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max);
+
+/* setup page data for repodata_load_page_range */
+int repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int pagesz, unsigned int blobsz);
+
+void repopagestore_disable_paging(Repopagestore *store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_REPOPAGE_H */
diff --git a/libsolv-0.7.2/src/rules.c b/libsolv-0.7.2/src/rules.c
new file mode 100644 (file)
index 0000000..df32341
--- /dev/null
@@ -0,0 +1,3727 @@
+/*
+ * Copyright (c) 2007-2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * rules.c
+ *
+ * SAT based dependency solver
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "util.h"
+#include "evr.h"
+#include "policy.h"
+#include "solverdebug.h"
+#include "linkedpkg.h"
+#include "cplxdeps.h"
+
+#define RULES_BLOCK 63
+
+static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep);
+
+static inline int
+is_otherproviders_dep(Pool *pool, Id dep)
+{
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
+       return 1;
+    }
+  return 0;
+}
+
+/********************************************************************
+ *
+ * Rule handling
+ *
+ * - unify rules, remove duplicates
+ */
+
+/*-------------------------------------------------------------------
+ *
+ * compare rules for unification sort
+ *
+ */
+
+static int
+unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  Rule *a = (Rule *)ap;
+  Rule *b = (Rule *)bp;
+  Id *ad, *bd;
+  int x;
+
+  x = a->p - b->p;
+  if (x)
+    return x;                          /* p differs */
+
+  /* identical p */
+  if (a->d == 0 && b->d == 0)          /* both assertions or binary */
+    return a->w2 - b->w2;
+
+  if (a->d == 0)                       /* a is assertion or binary, b not */
+    {
+      x = a->w2 - pool->whatprovidesdata[b->d];
+      return x ? x : -1;
+    }
+
+  if (b->d == 0)                       /* b is assertion or binary, a not */
+    {
+      x = pool->whatprovidesdata[a->d] - b->w2;
+      return x ? x : 1;
+    }
+
+  if (a->d == b->d)
+    return 0;
+
+  /* compare whatprovidesdata */
+  ad = pool->whatprovidesdata + a->d;
+  bd = pool->whatprovidesdata + b->d;
+  while (*bd)
+    if ((x = *ad++ - *bd++) != 0)
+      return x;
+  return *ad;
+}
+
+int
+solver_rulecmp(Solver *solv, Rule *r1, Rule *r2)
+{
+  return unifyrules_sortcmp(r1, r2, solv->pool);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * unify rules
+ * go over all rules and remove duplicates
+ */
+
+void
+solver_unifyrules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  Rule *ir, *jr;
+
+  if (solv->nrules <= 2)               /* nothing to unify */
+    return;
+
+  if (solv->recommendsruleq)
+    {
+      /* mis-use n2 as recommends rule marker */
+      for (i = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
+       ir->n2 = 0;
+      for (i = 0; i < solv->recommendsruleq->count; i++)
+       solv->rules[solv->recommendsruleq->elements[i]].n2 = 1;
+    }
+
+  /* sort rules first */
+  solv_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
+
+  /* prune rules */
+  jr = 0;
+  for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
+    {
+      if (jr && !unifyrules_sortcmp(ir, jr, pool))
+       {
+         jr->n2 &= ir->n2;             /* bitwise-and recommends marker */
+         continue;                     /* prune! */
+       }
+      jr = solv->rules + j++;          /* keep! */
+      if (ir != jr)
+        *jr = *ir;
+    }
+
+  /* reduced count from nrules to j rules */
+  POOL_DEBUG(SOLV_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
+
+  /* adapt rule buffer */
+  solver_shrinkrules(solv, j);
+
+  if (solv->recommendsruleq)
+    {
+      /* rebuild recommendsruleq */
+      queue_empty(solv->recommendsruleq);
+      for (i = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
+       if (ir->n2)
+         {
+           ir->n2 = 0;
+           queue_push(solv->recommendsruleq, i);
+         }
+    }
+
+  /*
+   * debug: log rule statistics
+   */
+  IF_POOLDEBUG (SOLV_DEBUG_STATS)
+    {
+      int binr = 0;
+      int lits = 0;
+      Id *dp;
+      Rule *r;
+
+      for (i = 1; i < solv->nrules; i++)
+       {
+         r = solv->rules + i;
+         if (r->d == 0)
+           binr++;
+         else
+           {
+             dp = solv->pool->whatprovidesdata + r->d;
+             while (*dp++)
+               lits++;
+           }
+       }
+      POOL_DEBUG(SOLV_DEBUG_STATS, "  binary: %d\n", binr);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
+    }
+}
+
+#if 0
+
+/*
+ * hash rule
+ */
+
+static Hashval
+hashrule(Solver *solv, Id p, Id d, int n)
+{
+  unsigned int x = (unsigned int)p;
+  int *dp;
+
+  if (n <= 1)
+    return (x * 37) ^ (unsigned int)d;
+  dp = solv->pool->whatprovidesdata + d;
+  while (*dp)
+    x = (x * 37) ^ (unsigned int)*dp++;
+  return x;
+}
+#endif
+
+
+/*-------------------------------------------------------------------
+ *
+ */
+
+/*
+ * add rule
+ *
+ * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
+ *
+ * p < 0  : pkg id of A
+ * d > 0  : Offset in whatprovidesdata (list of providers of b)
+ *
+ * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
+ * p < 0  : pkg id of A
+ * p2 < 0 : Id of solvable (e.g. B1)
+ *
+ * d == 0, p2 == 0: unary rule, assertion => (A) or (-A)
+ *
+ *   Install:    p > 0, d = 0   (A)             user requested install
+ *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
+ *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
+ *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
+ *   Conflicts:  p < 0, p2 < 0  (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
+ *                                              also used for obsoletes
+ *   No-op ?:    p = 0, d = 0   (null)          (used as placeholder in update/feature rules)
+ *
+ *   resulting watches:
+ *   ------------------
+ *   Direct assertion (no watch needed) --> d = 0, w1 = p, w2 = 0
+ *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
+ *   every other : w1 = p, w2 = whatprovidesdata[d];
+ *
+ *   always returns a rule for non-pkg rules
+ */
+
+Rule *
+solver_addrule(Solver *solv, Id p, Id p2, Id d)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+
+  if (d)
+    {
+      assert(!p2 && d > 0);
+      if (!pool->whatprovidesdata[d])
+       d = 0;
+      else if (!pool->whatprovidesdata[d + 1])
+       {
+         p2 = pool->whatprovidesdata[d];
+         d = 0;
+       }
+    }
+
+  /* now we have two cases:
+   * 1 or 2 literals:    d = 0, p, p2 contain the literals
+   * 3 or more literals: d > 0, p2 == 0, d is offset into whatprovidesdata
+   */
+
+  /* it often happenes that requires lead to adding the same pkg rule
+   * multiple times, so we prune those duplicates right away to make
+   * the work for unifyrules a bit easier */
+  if (!solv->pkgrules_end)             /* we add pkg rules */
+    {
+      r = solv->rules + solv->lastpkgrule;
+      if (d)
+       {
+         Id *dp;
+         /* check if rule is identical */
+         if (r->p == p)
+           {
+             Id *dp2;
+             if (r->d == d)
+               return r;
+             dp2 = pool->whatprovidesdata + r->d;
+             for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
+               if (*dp != *dp2)
+                 break;
+             if (*dp == *dp2)
+               return r;
+           }
+         /* check if rule is self-fulfilling */
+         for (dp = pool->whatprovidesdata + d; *dp; dp++)
+           if (*dp == -p)
+             return 0;                 /* rule is self-fulfilling */
+       }
+      else
+       {
+         if (p2 && p > p2)
+           {
+             Id o = p;                 /* switch p1 and p2 */
+             p = p2;
+             p2 = o;
+           }
+         if (r->p == p && !r->d && r->w2 == p2)
+           return r;
+         if (p == -p2)
+           return 0;                   /* rule is self-fulfilling */
+       }
+      solv->lastpkgrule = solv->nrules;
+    }
+
+  solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
+  r = solv->rules + solv->nrules++;    /* point to rule space */
+  r->p = p;
+  r->d = d;
+  r->w1 = p;
+  r->w2 = d ? pool->whatprovidesdata[d] : p2;
+  r->n1 = 0;
+  r->n2 = 0;
+  IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
+    {
+      POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "  Add rule: ");
+      solver_printrule(solv, SOLV_DEBUG_RULE_CREATION, r);
+    }
+  return r;
+}
+
+
+void
+solver_shrinkrules(Solver *solv, int nrules)
+{
+  solv->nrules = nrules;
+  solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
+  solv->lastpkgrule = 0;
+}
+
+/******************************************************************************
+ ***
+ *** pkg rule part: create rules representing the package dependencies
+ ***
+ ***/
+
+/*
+ *  special multiversion patch conflict handling:
+ *  a patch conflict is also satisfied if some other
+ *  version with the same name/arch that doesn't conflict
+ *  gets installed. The generated rule is thus:
+ *  -patch|-cpack|opack1|opack2|...
+ */
+static Id
+makemultiversionconflict(Solver *solv, Id n, Id con)
+{
+  Pool *pool = solv->pool;
+  Solvable *s, *sn;
+  Queue q;
+  Id p, pp, qbuf[64];
+
+  sn = pool->solvables + n;
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  queue_push(&q, -n);
+  FOR_PROVIDES(p, pp, sn->name)
+    {
+      s = pool->solvables + p;
+      if (s->name != sn->name || s->arch != sn->arch)
+       continue;
+      if (!MAPTST(&solv->multiversion, p))
+       continue;
+      if (pool_match_nevr(pool, pool->solvables + p, con))
+       continue;
+      /* here we have a multiversion solvable that doesn't conflict */
+      /* thus we're not in conflict if it is installed */
+      queue_push(&q, p);
+    }
+  if (q.count == 1)
+    n = 0;     /* no other package found, normal conflict handling */
+  else
+    n = pool_queuetowhatprovides(pool, &q);
+  queue_free(&q);
+  return n;
+}
+
+static inline void
+addpkgrule(Solver *solv, Id p, Id p2, Id d, int type, Id dep)
+{
+  if (!solv->ruleinfoq)
+    solver_addrule(solv, p, p2, d);
+  else
+    addpkgruleinfo(solv, p, p2, d, type, dep);
+}
+
+#ifdef ENABLE_LINKED_PKGS
+
+static int
+addlinks_cmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  Id a = *(Id *)ap;
+  Id b = *(Id *)bp;
+  Solvable *sa = pool->solvables + a;
+  Solvable *sb = pool->solvables + b;
+  if (sa->name != sb->name)
+    return sa->name - sb->name;
+  return sa - sb;
+}
+
+static void
+addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m, Queue *workq)
+{
+  Pool *pool = solv->pool;
+  int i;
+  if (!qr->count)
+    return;
+  if (qp->count > 1)
+    solv_sort(qp->elements, qp->count, sizeof(Id), addlinks_cmp, pool);
+#if 0
+  printf("ADDLINKS %s\n -> %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
+  for (i = 0; i < qr->count; i++)
+    printf("    - %s\n", pool_solvid2str(pool, qr->elements[i]));
+  printf(" <- %s\n", pool_dep2str(pool, prv));
+  for (i = 0; i < qp->count; i++)
+    printf("    - %s\n", pool_solvid2str(pool, qp->elements[i]));
+#endif
+
+  if (qr->count == 1)
+    addpkgrule(solv, -(s - pool->solvables), qr->elements[0], 0, SOLVER_RULE_PKG_REQUIRES, req);
+  else
+    addpkgrule(solv, -(s - pool->solvables), 0, pool_queuetowhatprovides(pool, qr), SOLVER_RULE_PKG_REQUIRES, req);
+  if (qp->count > 1)
+    {
+      int j;
+      for (i = j = 0; i < qp->count; i = j)
+       {
+         Id d = pool->solvables[qp->elements[i]].name;
+         for (j = i + 1; j < qp->count; j++)
+           if (d != pool->solvables[qp->elements[j]].name)
+             break;
+         d = pool_ids2whatprovides(pool, qp->elements + i, j - i);
+         for (i = 0; i < qr->count; i++)
+           addpkgrule(solv, -qr->elements[i], 0, d, SOLVER_RULE_PKG_REQUIRES, prv);
+       }
+    }
+  else if (qp->count)
+    {
+      for (i = 0; i < qr->count; i++)
+       addpkgrule(solv, -qr->elements[i], qp->elements[0], 0, SOLVER_RULE_PKG_REQUIRES, prv);
+    }
+  if (!m)
+    return;    /* nothing more to do if called from getpkgruleinfos() */
+  for (i = 0; i < qr->count; i++)
+    if (!MAPTST(m, qr->elements[i]))
+      queue_push(workq, qr->elements[i]);
+  for (i = 0; i < qp->count; i++)
+    if (!MAPTST(m, qp->elements[i]))
+      queue_push(workq, qp->elements[i]);
+  if (solv->installed && s->repo == solv->installed)
+    {
+      Repo *installed = solv->installed;
+      /* record installed buddies */
+      if (!solv->instbuddy)
+        solv->instbuddy = solv_calloc(installed->end - installed->start, sizeof(Id));
+      if (qr->count == 1)
+        solv->instbuddy[s - pool->solvables - installed->start] = qr->elements[0];
+      for (i = 0; i < qr->count; i++)
+       {
+         Id p = qr->elements[i];
+         if (pool->solvables[p].repo != installed)
+           continue;   /* huh? */
+         if (qp->count > 1 || (solv->instbuddy[p - installed->start] != 0 && solv->instbuddy[p - installed->start] != s - pool->solvables))
+           solv->instbuddy[p - installed->start] = 1;  /* 1: ambiguous buddy */
+         else
+           solv->instbuddy[p - installed->start] = s - pool->solvables;
+       }
+    }
+}
+
+static void
+add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq)
+{
+  Queue qr, qp;
+  Id req = 0, prv = 0;
+  queue_init(&qr);
+  queue_init(&qp);
+  find_package_link(solv->pool, s, &req, &qr, &prv, &qp);
+  if (qr.count)
+    addlinks(solv, s, req, &qr, prv, &qp, m, workq);
+  queue_free(&qr);
+  queue_free(&qp);
+}
+
+#endif
+
+#ifdef ENABLE_COMPLEX_DEPS
+
+static void
+add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int i, j, flags;
+  Queue bq;
+
+  queue_init(&bq);
+  flags = dontfix ? CPLXDEPS_DONTFIX : 0;
+  /* CNF expansion for requires, DNF + INVERT expansion for conflicts */
+  if (type == SOLVER_RULE_PKG_CONFLICTS)
+    flags |= CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT;
+
+  i = pool_normalize_complex_dep(pool, dep, &bq, flags);
+  /* handle special cases */
+  if (i == 0)
+    {
+      if (dontfix)
+       {
+         POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken dependency %s of installed package %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, p));
+       }
+      else
+       {
+         POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep));
+         addpkgrule(solv, -p, 0, 0, type == SOLVER_RULE_PKG_REQUIRES ? SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP : type, dep);
+       }
+      queue_free(&bq);
+      return;
+    }
+  if (i == 1)
+    {
+      queue_free(&bq);
+      return;
+    }
+
+  /* go through all blocks and add a rule for each block */
+  for (i = 0; i < bq.count; i++)
+    {
+      if (!bq.elements[i])
+       continue;       /* huh? */
+      if (bq.elements[i] == pool->nsolvables)
+       {
+         /* conventional requires (cannot be a conflicts as they have been expanded) */
+         Id *dp = pool->whatprovidesdata + bq.elements[i + 1];
+         i += 2;
+         if (dontfix)
+           {
+             for (j = 0; dp[j] != 0; j++)
+               if (pool->solvables[dp[j]].repo == installed)
+                 break;                /* provider was installed */
+             if (!dp[j])
+               continue;
+           }
+         if (type == SOLVER_RULE_PKG_RECOMMENDS && !*dp)
+           continue;
+         /* check if the rule contains both p and -p */
+         for (j = 0; dp[j] != 0; j++)
+           if (dp[j] == p)
+             break;
+         if (dp[j])
+           continue;
+         addpkgrule(solv, -p, 0, dp - pool->whatprovidesdata, type, dep);
+         /* push all non-visited providers on the work queue */
+         if (m)
+           for (; *dp; dp++)
+             if (!MAPTST(m, *dp))
+               queue_push(workq, *dp);
+         continue;
+       }
+      if (!bq.elements[i + 1])
+       {
+         Id p2 = bq.elements[i++];
+         /* simple rule with just two literals, we'll add a (-p, p2) rule */
+         if (dontfix)
+           {
+             if (p2 < 0 && pool->solvables[-p2].repo == installed)
+               continue;
+             if (p2 > 0 && pool->solvables[p2].repo != installed)
+               continue;
+           }
+         if (-p == p2)
+           {
+             if (type == SOLVER_RULE_PKG_CONFLICTS)
+               {
+                 if (pool->forbidselfconflicts && !is_otherproviders_dep(pool, dep))
+                   addpkgrule(solv, -p, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, dep);
+                 continue;
+               }
+             addpkgrule(solv, -p, 0, 0, type, dep);
+             continue;
+           }
+         /* check if the rule contains both p and -p */
+         if (p == p2)
+           continue;
+         addpkgrule(solv, -p, p2, 0, type, dep);
+         if (m && p2 > 0 && !MAPTST(m, p2))
+           queue_push(workq, p2);
+       }
+      else
+       {
+         Id *qele;
+         int qcnt;
+
+         qele = bq.elements + i;
+         qcnt = i;
+         while (bq.elements[i])
+            i++;
+         qcnt = i - qcnt;
+         if (dontfix)
+           {
+             for (j = 0; j < qcnt; j++)
+               {
+                 if (qele[j] > 0 && pool->solvables[qele[j]].repo == installed)
+                   break;
+                 if (qele[j] < 0 && pool->solvables[-qele[j]].repo != installed)
+                   break;
+               }
+             if (j == qcnt)
+               continue;
+           }
+         /* add -p to (ordered) rule (overwriting the trailing zero) */
+         for (j = 0; ; j++)
+           {
+             if (j == qcnt || qele[j] > -p)
+               {
+                 if (j < qcnt)
+                   memmove(qele + j + 1, qele + j, (qcnt - j) * sizeof(Id));
+                 qele[j] = -p;
+                 qcnt++;
+                 break;
+               }
+             if (qele[j] == -p)
+               break;
+           }
+         /* check if the rule contains both p and -p */
+         for (j = 0; j < qcnt; j++)
+           if (qele[j] == p)
+             break;
+         if (j < qcnt)
+           continue;
+         addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep);
+         if (m)
+           for (j = 0; j < qcnt; j++)
+             if (qele[j] > 0 && !MAPTST(m, qele[j]))
+               queue_push(workq, qele[j]);
+       }
+    }
+  queue_free(&bq);
+}
+
+#endif
+
+/*-------------------------------------------------------------------
+ *
+ * add dependency rules for solvable
+ *
+ * s: Solvable for which to add rules
+ * m: m[s] = 1 for solvables which have rules, prevent rule duplication
+ *
+ * Algorithm: 'visit all nodes of a graph'. The graph nodes are
+ *  solvables, the edges their dependencies.
+ *  Starting from an installed solvable, this will create all rules
+ *  representing the graph created by the solvables dependencies.
+ *
+ * for unfulfilled requirements, conflicts, obsoletes,....
+ * add a negative assertion for solvables that are not installable
+ *
+ * It will also create rules for all solvables referenced by 's'
+ *  i.e. descend to all providers of requirements of 's'
+ *
+ */
+
+void
+solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+
+  Queue workq; /* list of solvables we still have to work on */
+  Id workqbuf[64];
+  Queue prereqq;       /* list of pre-req ids to ignore */
+  Id prereqbuf[16];
+
+  int i;
+  int dontfix;         /* ignore dependency errors for installed solvables */
+  Id req, *reqp;
+  Id con, *conp;
+  Id obs, *obsp;
+  Id rec, *recp;
+  Id sug, *sugp;
+  Id p, pp;            /* whatprovides loops */
+  Id *dp;              /* ptr to 'whatprovides' */
+  Id n;                        /* Id for current solvable 's' */
+
+  queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
+  queue_push(&workq, s - pool->solvables);     /* push solvable Id to work queue */
+
+  queue_init_buffer(&prereqq, prereqbuf, sizeof(prereqbuf)/sizeof(*prereqbuf));
+
+  /* loop until there's no more work left */
+  while (workq.count)
+    {
+      /*
+       * n: Id of solvable
+       * s: Pointer to solvable
+       */
+
+      n = queue_shift(&workq);         /* 'pop' next solvable to work on from queue */
+      if (m)
+       {
+         if (MAPTST(m, n))             /* continue if already visited */
+           continue;
+         MAPSET(m, n);                 /* mark as visited */
+       }
+
+      s = pool->solvables + n;
+
+      dontfix = 0;
+      if (installed                    /* Installed system available */
+         && s->repo == installed       /* solvable is installed */
+         && !solv->fixmap_all          /* NOT repair errors in dependency graph */
+         && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
+        {
+         dontfix = 1;                  /* dont care about broken deps */
+        }
+
+      if (!dontfix)
+       {
+         if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC
+               ? pool_disabled_solvable(pool, s)
+               : !pool_installable(pool, s))
+           {
+             POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", pool_solvid2str(pool, n), n);
+             addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0);
+           }
+       }
+
+#ifdef ENABLE_LINKED_PKGS
+      /* add pseudo-package <-> real-package links */
+      if (has_package_link(pool, s))
+        add_package_link(solv, s, m, &workq);
+#endif
+
+      /*-----------------------------------------
+       * check requires of s
+       */
+
+      if (s->requires)
+       {
+         int filterpre = 0;
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)            /* go through all requires */
+           {
+             if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
+               {
+                 if (installed && s->repo == installed)
+                   {
+                     if (prereqq.count)
+                       queue_empty(&prereqq);
+                     solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &prereqq);
+                     filterpre = prereqq.count;
+                   }
+                 continue;
+               }
+             if (filterpre)
+               {
+                 /* check if this id is filtered. assumes that prereqq.count is small */
+                 for (i = 0; i < prereqq.count; i++)
+                   if (req == prereqq.elements[i])
+                     break;
+                 if (i < prereqq.count)
+                   {
+                     POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
+                     continue;
+                   }
+               }
+
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, req))
+               {
+                 /* we have AND/COND deps, normalize */
+                 add_complex_deprules(solv, n, req, SOLVER_RULE_PKG_REQUIRES, dontfix, &workq, m);
+                 continue;
+               }
+#endif
+
+             /* find list of solvables providing 'req' */
+             dp = pool_whatprovides_ptr(pool, req);
+
+             if (*dp == SYSTEMSOLVABLE)          /* always installed */
+               continue;
+
+             if (dontfix)
+               {
+                 /* the strategy here is to not insist on dependencies
+                   * that are already broken. so if we find one provider
+                   * that was already installed, we know that the
+                   * dependency was not broken before so we enforce it */
+                 for (i = 0; (p = dp[i]) != 0; i++)
+                   if (pool->solvables[p].repo == installed)
+                     break;            /* found installed provider */
+                 if (!p)
+                   {
+                     /* didn't find an installed provider: previously broken dependency */
+                     POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s));
+                     continue;
+                   }
+               }
+
+             if (!*dp)
+               {
+                 POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, n), n, pool_dep2str(pool, req));
+                 addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req);
+                 continue;
+               }
+
+             for (i = 0; dp[i] != 0; i++)
+               if (n == dp[i])
+                 break;
+             if (dp[i])
+               continue;               /* provided by itself, no need to add rule */
+
+             IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
+               {
+                 POOL_DEBUG(SOLV_DEBUG_RULE_CREATION,"  %s requires %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
+                 for (i = 0; dp[i]; i++)
+                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "   provided by %s\n", pool_solvid2str(pool, dp[i]));
+               }
+
+             /* add 'requires' dependency */
+              /* rule: (-requestor|provider1|provider2|...|providerN) */
+             addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req);
+
+             /* push all non-visited providers on the work queue */
+             if (m)
+               for (; *dp; dp++)
+                 if (!MAPTST(m, *dp))
+                   queue_push(&workq, *dp);
+           }
+       }
+
+      if (s->recommends && solv->strongrecommends)
+       {
+         int start = solv->nrules;
+         solv->lastpkgrule = 0;
+         reqp = s->repo->idarraydata + s->recommends;
+         while ((req = *reqp++) != 0)            /* go through all recommends */
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, req))
+               {
+                 /* we have AND/COND deps, normalize */
+                 add_complex_deprules(solv, n, req, SOLVER_RULE_PKG_RECOMMENDS, dontfix, &workq, m);
+                 continue;
+               }
+#endif
+             dp = pool_whatprovides_ptr(pool, req);
+             if (*dp == SYSTEMSOLVABLE || !*dp)          /* always installed or not installable */
+               continue;
+             for (i = 0; dp[i] != 0; i++)
+               if (n == dp[i])
+                 break;
+             if (dp[i])
+               continue;               /* provided by itself, no need to add rule */
+             addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_RECOMMENDS, req);
+             if (m)
+               for (; *dp; dp++)
+                 if (!MAPTST(m, *dp))
+                   queue_push(&workq, *dp);
+           }
+         if (!solv->ruleinfoq && start < solv->nrules)
+           {
+             if (!solv->recommendsruleq)
+               {
+                 solv->recommendsruleq = solv_calloc(1, sizeof(Queue));
+                 queue_init(solv->recommendsruleq);
+               }
+             for (i = start; i < solv->nrules; i++)
+               queue_push(solv->recommendsruleq, i);
+             solv->lastpkgrule = 0;
+           }
+       }
+
+      /* that's all we check for src packages */
+      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+       continue;
+
+      /*-----------------------------------------
+       * check conflicts of s
+       */
+
+      if (s->conflicts)
+       {
+         int ispatch = 0;
+
+         /* we treat conflicts in patches a bit differen:
+          * - nevr matching
+          * - multiversion handling
+          * XXX: we should really handle this different, looking
+          * at the name is a bad hack
+          */
+         if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
+           ispatch = 1;
+         conp = s->repo->idarraydata + s->conflicts;
+         /* foreach conflicts of 's' */
+         while ((con = *conp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (!ispatch && pool_is_complex_dep(pool, con))
+               {
+                 /* we have AND/COND deps, normalize */
+                 add_complex_deprules(solv, n, con, SOLVER_RULE_PKG_CONFLICTS, dontfix, &workq, m);
+                 continue;
+               }
+#endif
+             /* foreach providers of a conflict of 's' */
+             FOR_PROVIDES(p, pp, con)
+               {
+                 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
+                   continue;
+                 /* dontfix: dont care about conflicts with already installed packs */
+                 if (dontfix && pool->solvables[p].repo == installed)
+                   continue;
+                 if (p == n)           /* p == n: self conflict */
+                   {
+                     if (!pool->forbidselfconflicts || is_otherproviders_dep(pool, con))
+                       continue;
+                     addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con);
+                     continue;
+                   }
+                 if (ispatch && solv->multiversion.size && MAPTST(&solv->multiversion, p) && ISRELDEP(con))
+                   {
+                     /* our patch conflicts with a multiversion package */
+                     Id d = makemultiversionconflict(solv, p, con);
+                     if (d)
+                       {
+                         addpkgrule(solv, -n, 0, d, SOLVER_RULE_PKG_CONFLICTS, con);
+                         continue;
+                       }
+                   }
+                 if (p == SYSTEMSOLVABLE)
+                   p = 0;
+                  /* rule: -n|-p: either solvable _or_ provider of conflict */
+                 addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONFLICTS, con);
+               }
+           }
+       }
+
+      /*-----------------------------------------
+       * check obsoletes and implicit obsoletes of a package
+       * if ignoreinstalledsobsoletes is not set, we're also checking
+       * obsoletes of installed packages (like newer rpm versions)
+       */
+      if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
+       {
+         int multi = solv->multiversion.size && MAPTST(&solv->multiversion, n);
+         int isinstalled = (installed && s->repo == installed);
+         if (s->obsoletes && (!multi || solv->keepexplicitobsoletes))
+           {
+             obsp = s->repo->idarraydata + s->obsoletes;
+             /* foreach obsoletes */
+             while ((obs = *obsp++) != 0)
+               {
+                 /* foreach provider of an obsoletes of 's' */
+                 FOR_PROVIDES(p, pp, obs)
+                   {
+                     Solvable *ps = pool->solvables + p;
+                     if (p == n)
+                       continue;
+                     if (isinstalled && dontfix && ps->repo == installed)
+                       continue;       /* don't repair installed/installed problems */
+                     if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
+                         && !pool_match_nevr(pool, ps, obs))
+                       continue;
+                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+                       continue;
+                     if (p == SYSTEMSOLVABLE)
+                       p = 0;
+                     if (!isinstalled)
+                       addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_OBSOLETES, obs);
+                     else
+                       addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs);
+                   }
+               }
+           }
+         /* check implicit obsoletes
+           * for installed packages we only need to check installed/installed problems (and
+           * only when dontfix is not set), as the others are picked up when looking at the
+           * uninstalled package.
+           */
+         if (!isinstalled || !dontfix)
+           {
+             FOR_PROVIDES(p, pp, s->name)
+               {
+                 Solvable *ps = pool->solvables + p;
+                 if (p == n)
+                   continue;
+                 if (isinstalled && ps->repo != installed)
+                   continue;
+                 /* we still obsolete packages with same nevra, like rpm does */
+                 /* (actually, rpm mixes those packages. yuck...) */
+                 if (multi && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
+                   {
+                     if (isinstalled || ps->repo != installed)
+                       continue;
+                     /* also check the installed package for multi-ness */
+                     if (MAPTST(&solv->multiversion, p))
+                       continue;
+                   }
+                 if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+                   continue;
+                 if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+                   continue;
+                 if (p == SYSTEMSOLVABLE)
+                   p = 0;
+                 if (s->name == ps->name)
+                   {
+                     /* optimization: do not add the same-name conflict rule if it was
+                      * already added when we looked at the other package.
+                      * (this assumes pool_colormatch is symmetric) */
+                     if (p && m && ps->repo != installed && MAPTST(m, p) &&
+                         (ps->arch != ARCH_SRC && ps->arch != ARCH_NOSRC) &&
+                         !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
+                       continue;
+                     addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_SAME_NAME, 0);
+                   }
+                 else
+                   addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name);
+               }
+           }
+       }
+
+      if (m && pool->implicitobsoleteusescolors && pool_arch2score(pool, s->arch) > 1)
+       {
+         unsigned int pa, a = pool_arch2score(pool, s->arch);
+         /* check lock-step candidates */
+         FOR_PROVIDES(p, pp, s->name)
+           {
+             Solvable *ps = pool->solvables + p;
+             if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p))
+               continue;
+             pa = pool_arch2score(pool, ps->arch);
+             if (!pa || pa == 1 || pa >= a)
+               continue;
+             queue_push(&workq, p);
+           }
+       }
+
+      /*-----------------------------------------
+       * add recommends/suggests to the work queue
+       */
+      if (s->recommends && m)
+       {
+         recp = s->repo->idarraydata + s->recommends;
+         while ((rec = *recp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, rec))
+               {
+                 pool_add_pos_literals_complex_dep(pool, rec, &workq, m, 0);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, rec)
+               if (!MAPTST(m, p))
+                 queue_push(&workq, p);
+           }
+       }
+      if (s->suggests && m)
+       {
+         sugp = s->repo->idarraydata + s->suggests;
+         while ((sug = *sugp++) != 0)
+           {
+#ifdef ENABLE_COMPLEX_DEPS
+             if (pool_is_complex_dep(pool, sug))
+               {
+                 pool_add_pos_literals_complex_dep(pool, sug, &workq, m, 0);
+                 continue;
+               }
+#endif
+             FOR_PROVIDES(p, pp, sug)
+               if (!MAPTST(m, p))
+                 queue_push(&workq, p);
+           }
+       }
+    }
+  queue_free(&prereqq);
+  queue_free(&workq);
+}
+
+#ifdef ENABLE_LINKED_PKGS
+void
+solver_addpkgrulesforlinked(Solver *solv, Map *m)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  int i, j;
+  Queue qr;
+
+  queue_init(&qr);
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      if (MAPTST(m, i))
+       continue;
+      s = pool->solvables + i;
+      if (!s->repo || s->repo == solv->installed)
+       continue;
+      if (!strchr(pool_id2str(pool, s->name), ':'))
+       continue;
+      if (!pool_installable(pool, s))
+       continue;
+      find_package_link(pool, s, 0, &qr, 0, 0);
+      if (qr.count)
+       {
+         for (j = 0; j < qr.count; j++)
+           if (MAPTST(m, qr.elements[j]))
+             {
+               solver_addpkgrulesforsolvable(solv, s, m);
+               break;
+             }
+         queue_empty(&qr);
+       }
+    }
+  queue_free(&qr);
+}
+#endif
+
+/*-------------------------------------------------------------------
+ *
+ * Add rules for packages possibly selected in by weak dependencies
+ *
+ * m: already added solvables
+ */
+
+void
+solver_addpkgrulesforweak(Solver *solv, Map *m)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  Id sup, *supp;
+  int i, n;
+
+  /* foreach solvable in pool */
+  for (i = n = 1; n < pool->nsolvables; i++, n++)
+    {
+      if (i == pool->nsolvables)               /* wrap i */
+       i = 1;
+      if (MAPTST(m, i))                                /* already added that one */
+       continue;
+
+      s = pool->solvables + i;
+      if (!s->repo)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;       /* only look at installable ones */
+
+      sup = 0;
+      if (s->supplements)
+       {
+         /* find possible supplements */
+         supp = s->repo->idarraydata + s->supplements;
+         while ((sup = *supp++) != 0)
+           if (solver_dep_possible(solv, sup, m))
+             break;
+       }
+
+      /* if nothing found, check for enhances */
+      if (!sup && s->enhances)
+       {
+         supp = s->repo->idarraydata + s->enhances;
+         while ((sup = *supp++) != 0)
+           if (solver_dep_possible(solv, sup, m))
+             break;
+       }
+      /* if nothing found, goto next solvables */
+      if (!sup)
+       continue;
+      solver_addpkgrulesforsolvable(solv, s, m);
+      n = 0;                   /* check all solvables again because we added solvables to m */
+    }
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * add package rules for possible updates
+ *
+ * s: solvable
+ * m: map of already visited solvables
+ * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
+ */
+
+void
+solver_addpkgrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
+{
+  Pool *pool = solv->pool;
+  int i;
+    /* queue and buffer for it */
+  Queue qs;
+  Id qsbuf[64];
+
+  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
+    /* find update candidates for 's' */
+  policy_findupdatepackages(solv, s, &qs, allow_all);
+    /* add rule for 's' if not already done */
+  if (!MAPTST(m, s - pool->solvables))
+    solver_addpkgrulesforsolvable(solv, s, m);
+    /* foreach update candidate, add rule if not already done */
+  for (i = 0; i < qs.count; i++)
+    if (!MAPTST(m, qs.elements[i]))
+      solver_addpkgrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
+  queue_free(&qs);
+}
+
+
+/***********************************************************************
+ ***
+ ***  Update/Feature rule part
+ ***
+ ***  Those rules make sure an installed package isn't silently deleted
+ ***
+ ***/
+
+static int
+dup_maykeepinstalled(Solver *solv, Solvable *s)
+{
+  Pool *pool = solv->pool;
+  Id ip, pp;
+
+  if (solv->dupmap.size && MAPTST(&solv->dupmap,  s - pool->solvables))
+    return 1;
+  /* is installed identical to a good one? */
+  FOR_PROVIDES(ip, pp, s->name)
+    {
+      Solvable *is = pool->solvables + ip;
+      if (is->evr != s->evr)
+       continue;
+      if (solv->dupmap.size)
+       {
+         if (!MAPTST(&solv->dupmap, ip))
+           continue;
+       }
+      else if (is->repo == pool->installed)
+       continue;
+      if (solvable_identical(s, is))
+       return 1;
+    }
+  return 0;
+}
+
+
+/* stash away the original updaters for multiversion packages. We do this so that
+ * we can update the package later */
+static inline void
+set_specialupdaters(Solver *solv, Solvable *s, Id d)
+{
+  Repo *installed = solv->installed;
+  if (!solv->specialupdaters)
+    solv->specialupdaters = solv_calloc(installed->end - installed->start, sizeof(Id));
+  solv->specialupdaters[s - solv->pool->solvables - installed->start] = d;
+}
+
+#ifdef ENABLE_LINKED_PKGS
+/* Check if this is a linked pseudo package. As it is linked, we do not need an update/feature rule */
+static inline int
+is_linked_pseudo_package(Solver *solv, Solvable *s)
+{
+  Pool *pool = solv->pool;
+  if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start])
+    {
+      const char *name = pool_id2str(pool, s->name);
+      if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
+       return 1;
+    }
+  return 0;
+}
+#endif
+
+void
+solver_addfeaturerule(Solver *solv, Solvable *s)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id p;
+  Queue qs;
+  Id qsbuf[64];
+
+#ifdef ENABLE_LINKED_PKGS
+  if (is_linked_pseudo_package(solv, s))
+    {
+      solver_addrule(solv, 0, 0, 0);   /* no feature rules for those */
+      return;
+    }
+#endif
+  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
+  p = s - pool->solvables;
+  policy_findupdatepackages(solv, s, &qs, 1);
+  if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
+    {
+      if (!dup_maykeepinstalled(solv, s))
+       {
+         for (i = 0; i < qs.count; i++)
+           {
+             Solvable *ns = pool->solvables + qs.elements[i];
+             if (ns->repo != pool->installed || dup_maykeepinstalled(solv, ns))
+               break;
+           }
+         if (i == qs.count)
+           {
+             solver_addrule(solv, 0, 0, 0);    /* this is an orphan */
+             queue_free(&qs);
+             return;
+           }
+       }
+    }
+  if (qs.count > 1)
+    {
+      Id d = pool_queuetowhatprovides(pool, &qs);
+      queue_free(&qs);
+      solver_addrule(solv, p, 0, d);   /* allow update of s */
+    }
+  else
+    {
+      Id d = qs.count ? qs.elements[0] : 0;
+      queue_free(&qs);
+      solver_addrule(solv, p, d, 0);   /* allow update of s */
+    }
+}
+
+/*-------------------------------------------------------------------
+ *
+ * add rule for update
+ *   (A|A1|A2|A3...)  An = update candidates for A
+ *
+ * s = (installed) solvable
+ */
+
+void
+solver_addupdaterule(Solver *solv, Solvable *s)
+{
+  /* installed packages get a special upgrade allowed rule */
+  Pool *pool = solv->pool;
+  Id p, d;
+  Queue qs;
+  Id qsbuf[64];
+  Rule *r;
+  int dupinvolved = 0;
+
+  p = s - pool->solvables;
+  /* Orphan detection. We cheat by looking at the feature rule, which
+   * we already calculated */
+  r = solv->rules + solv->featurerules + (p - solv->installed->start);
+  if (!r->p)
+    {
+#ifdef ENABLE_LINKED_PKGS
+      if (is_linked_pseudo_package(solv, s))
+       {
+         solver_addrule(solv, 0, 0, 0);
+         return;
+       }
+#endif
+      p = 0;
+      queue_push(&solv->orphaned, s - pool->solvables);                /* an orphaned package */
+      if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
+       p = s - pool->solvables;        /* keep this orphaned package installed */
+      solver_addrule(solv, p, 0, 0);
+      return;
+    }
+
+  /* find update candidates for 's' */
+  queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
+  dupinvolved = solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p));
+  policy_findupdatepackages(solv, s, &qs, dupinvolved ? 2 : 0);
+
+  if (qs.count && solv->multiversion.size)
+    {
+      int i, j;
+
+      for (i = 0; i < qs.count; i++)
+       if (MAPTST(&solv->multiversion, qs.elements[i]))
+         break;
+      if (i < qs.count)
+       {
+         /* filter out all multiversion packages as they don't update */
+         d = pool_queuetowhatprovides(pool, &qs);      /* save qs away */
+         for (j = i; i < qs.count; i++)
+            {
+             if (MAPTST(&solv->multiversion, qs.elements[i]))
+               {
+                 Solvable *ps = pool->solvables + qs.elements[i];
+                 /* if keepexplicitobsoletes is set and the name is different,
+                  * we assume that there is an obsoletes. XXX: not 100% correct */
+                 if (solv->keepexplicitobsoletes && ps->name != s->name)
+                   {
+                     qs.elements[j++] = qs.elements[i];
+                     continue;
+                   }
+                 /* it's ok if they have same nevra */
+                 if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
+                   continue;
+               }
+             qs.elements[j++] = qs.elements[i];
+           }
+
+         if (j == 0 && dupinvolved && !dup_maykeepinstalled(solv, s))
+           {
+             /* this is a multiversion orphan */
+             queue_push(&solv->orphaned, p);
+             set_specialupdaters(solv, s, d);
+             if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+               {
+                 /* we need to keep the orphan */
+                 queue_free(&qs);
+                 solver_addrule(solv, p, 0, 0);
+                 return;
+               }
+             /* we can drop it as long as we update */
+             j = qs.count;
+           }
+
+         if (j < qs.count)             /* filtered at least one package? */
+           {
+             if (d && (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start))))
+               {
+                 /* non-orphan multiversion package, set special updaters if we want an update */
+                 set_specialupdaters(solv, s, d);
+               }
+             qs.count = j;
+           }
+         else
+           {
+             /* could fallthrough, but then we would do pool_queuetowhatprovides twice */
+             queue_free(&qs);
+             solver_addrule(solv, p, 0, d);    /* allow update of s */
+             return;
+           }
+       }
+    }
+  if (qs.count > 1)
+    {
+      d = pool_queuetowhatprovides(pool, &qs);
+      queue_free(&qs);
+      solver_addrule(solv, p, 0, d);   /* allow update of s */
+    }
+  else
+    {
+      d = qs.count ? qs.elements[0] : 0;
+      queue_free(&qs);
+      solver_addrule(solv, p, d, 0);   /* allow update of s */
+    }
+}
+
+static inline void
+disableupdaterule(Solver *solv, Id p)
+{
+  Rule *r;
+
+  MAPSET(&solv->noupdate, p - solv->installed->start);
+  r = solv->rules + solv->updaterules + (p - solv->installed->start);
+  if (r->p && r->d >= 0)
+    solver_disablerule(solv, r);
+  r = solv->rules + solv->featurerules + (p - solv->installed->start);
+  if (r->p && r->d >= 0)
+    solver_disablerule(solv, r);
+  if (solv->bestrules_pkg)
+    {
+      int i, ni;
+      ni = solv->bestrules_end - solv->bestrules;
+      for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
+       if (solv->bestrules_pkg[i] == p)
+         solver_disablerule(solv, solv->rules + solv->bestrules + i);
+    }
+}
+
+static inline void
+reenableupdaterule(Solver *solv, Id p)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+
+  MAPCLR(&solv->noupdate, p - solv->installed->start);
+  r = solv->rules + solv->updaterules + (p - solv->installed->start);
+  if (r->p)
+    {
+      if (r->d < 0)
+       {
+         solver_enablerule(solv, r);
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
+       }
+    }
+  else
+    {
+      r = solv->rules + solv->featurerules + (p - solv->installed->start);
+      if (r->p && r->d < 0)
+       {
+         solver_enablerule(solv, r);
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
+       }
+    }
+  if (solv->bestrules_pkg)
+    {
+      int i, ni;
+      ni = solv->bestrules_end - solv->bestrules;
+      for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
+       if (solv->bestrules_pkg[i] == p)
+         solver_enablerule(solv, solv->rules + solv->bestrules + i);
+    }
+}
+
+
+/***********************************************************************
+ ***
+ ***  Infarch rule part
+ ***
+ ***  Infarch rules make sure the solver uses the best architecture of
+ ***  a package if multiple archetectures are available
+ ***
+ ***/
+
+void
+solver_addinfarchrules(Solver *solv, Map *addedmap)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = pool->installed;
+  int first, i, j;
+  Id p, pp, aa;
+  unsigned int a, bestscore;
+  Solvable *s, *ps, *bests;
+  Queue badq, allowedarchs;
+  Queue lsq;
+
+  queue_init(&badq);
+  queue_init(&allowedarchs);
+  queue_init(&lsq);
+  solv->infarchrules = solv->nrules;
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
+       continue;
+      s = pool->solvables + i;
+      first = i;
+      bestscore = 0;
+      bests = 0;
+      queue_empty(&allowedarchs);
+      FOR_PROVIDES(p, pp, s->name)
+       {
+         ps = pool->solvables + p;
+         if (ps->name != s->name || !MAPTST(addedmap, p))
+           continue;
+         if (p == i)
+           first = 0;
+         if (first)
+           break;
+         a = pool_arch2score(pool, ps->arch);
+         if (a != 1 && installed && ps->repo == installed)
+           {
+             if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
+               continue;
+             queue_pushunique(&allowedarchs, ps->arch);        /* also ok to keep this architecture */
+             continue;         /* but ignore installed solvables when calculating the best arch */
+           }
+         if (a && a != 1 && (!bestscore || a < bestscore))
+           {
+             bestscore = a;
+             bests = ps;
+           }
+       }
+      if (first)
+       continue;
+
+      /* speed up common case where installed package already has best arch */
+      if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
+       allowedarchs.count--;   /* installed arch is best */
+
+      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestscore)
+       {
+         /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
+          * if the corresponding installed package is not lock-stepped */
+         queue_empty(&allowedarchs);
+         FOR_PROVIDES(p, pp, s->name)
+           {
+             Id p2, pp2;
+             ps = pool->solvables + p;
+             if (ps->name != s->name || ps->repo != installed || !MAPTST(addedmap, p))
+               continue;
+             if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
+               continue;
+             a = pool_arch2score(pool, ps->arch);
+             if (!a)
+               {
+                 queue_pushunique(&allowedarchs, ps->arch);    /* strange arch, allow */
+                 continue;
+               }
+             if (a == 1 || ((a ^ bestscore) & 0xffff0000) == 0)
+               continue;
+             /* have installed package with inferior arch, check if lock-stepped */
+             FOR_PROVIDES(p2, pp2, s->name)
+               {
+                 Solvable *s2 = pool->solvables + p2;
+                 unsigned int a2;
+                 if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
+                   continue;
+                 a2 = pool_arch2score(pool, s2->arch);
+                 if (a2 && (a2 == 1 || ((a2 ^ bestscore) & 0xffff0000) == 0))
+                   break;
+               }
+             if (!p2)
+               queue_pushunique(&allowedarchs, ps->arch);
+           }
+       }
+
+      /* find all bad packages */
+      queue_empty(&badq);
+      FOR_PROVIDES(p, pp, s->name)
+       {
+         ps = pool->solvables + p;
+         if (ps->name != s->name || !MAPTST(addedmap, p))
+           continue;
+         a = pool_arch2score(pool, ps->arch);
+         if (a != 1 && bestscore && ((a ^ bestscore) & 0xffff0000) != 0)
+           {
+             if (installed && ps->repo == installed)
+               {
+                 if (pool->implicitobsoleteusescolors)
+                   queue_push(&badq, p);               /* special lock-step handling, see below */
+                 continue;     /* always ok to keep an installed package */
+               }
+             for (j = 0; j < allowedarchs.count; j++)
+               {
+                 unsigned int aas;
+                 aa = allowedarchs.elements[j];
+                 if (ps->arch == aa)
+                   break;
+                 aas = pool_arch2score(pool, aa);
+                 if (aas && ((a ^ aas) & 0xffff0000) == 0)
+                   break;      /* compatible */
+               }
+             if (j == allowedarchs.count)
+               queue_push(&badq, p);
+           }
+       }
+
+      /* block all solvables in the badq! */
+      for (j = 0; j < badq.count; j++)
+       {
+         p = badq.elements[j];
+         /* special lock-step handling */
+         if (pool->implicitobsoleteusescolors)
+           {
+             Id p2;
+             int haveinstalled = 0;
+             queue_empty(&lsq);
+             FOR_PROVIDES(p2, pp, s->name)
+               {
+                 Solvable *s2 = pool->solvables + p2;
+                 if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
+                   continue;
+                 a = pool_arch2score(pool, s2->arch);
+                 if (a && (a == 1 || ((a ^ bestscore) & 0xffff000) == 0))
+                   {
+                     queue_push(&lsq, p2);
+                     if (installed && s2->repo == installed)
+                       haveinstalled = 1;
+                   }
+               }
+             if (installed && pool->solvables[p].repo == installed && !haveinstalled)
+               continue;       /* installed package not in lock-step */
+           }
+         if (lsq.count < 2)
+           solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0);
+         else
+           solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq));
+       }
+    }
+  queue_free(&lsq);
+  queue_free(&badq);
+  queue_free(&allowedarchs);
+  solv->infarchrules_end = solv->nrules;
+}
+
+static inline void
+disableinfarchrule(Solver *solv, Id name)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
+    {
+      if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
+        solver_disablerule(solv, r);
+    }
+}
+
+static inline void
+reenableinfarchrule(Solver *solv, Id name)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
+    {
+      if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
+        {
+          solver_enablerule(solv, r);
+          IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+            {
+              POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+              solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+            }
+        }
+    }
+}
+
+
+/***********************************************************************
+ ***
+ ***  Dup rule part
+ ***
+ ***  Dup rules make sure a package is selected from the specified dup
+ ***  repositories if an update candidate is included in one of them.
+ ***
+ ***/
+
+static inline void
+add_cleandeps_updatepkg(Solver *solv, Id p)
+{
+  if (!solv->cleandeps_updatepkgs)
+    {
+      solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
+      queue_init(solv->cleandeps_updatepkgs);
+    }
+  queue_pushunique(solv->cleandeps_updatepkgs, p);
+}
+
+static void
+solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted)
+{
+  Pool *pool = solv->pool;
+  Solvable *ps, *s = pool->solvables + p;
+  Repo *installed = solv->installed;
+  Id pi, pip, obs, *obsp;
+
+  if (!solv->dupinvolvedmap.size)
+    map_grow(&solv->dupinvolvedmap, pool->nsolvables);
+
+  MAPSET(&solv->dupinvolvedmap, p);
+  if (targeted)
+    MAPSET(&solv->dupmap, p);
+  FOR_PROVIDES(pi, pip, s->name)
+    {
+      ps = pool->solvables + pi;
+      if (ps->name != s->name)
+       continue;
+      MAPSET(&solv->dupinvolvedmap, pi);
+      if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
+       {
+         Id *opp, pi2;
+         for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
+           if (pool->solvables[pi2].repo != installed)
+             MAPSET(&solv->dupinvolvedmap, pi2);
+       }
+      if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0 && !solv->bestupdatemap_all)
+       {
+         if (!solv->bestupdatemap.size)
+           map_grow(&solv->bestupdatemap, installed->end - installed->start);
+         MAPSET(&solv->bestupdatemap, pi - installed->start);
+       }
+      if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
+       add_cleandeps_updatepkg(solv, pi);
+      if (!targeted && ps->repo != installed)
+       MAPSET(&solv->dupmap, pi);
+    }
+  if (s->repo == installed && solv->obsoletes && solv->obsoletes[p - installed->start])
+    {
+      Id *opp;
+      for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (pi = *opp++) != 0;)
+       {
+         ps = pool->solvables + pi;
+         if (ps->repo == installed)
+           continue;
+         MAPSET(&solv->dupinvolvedmap, pi);
+         if (!targeted)
+           MAPSET(&solv->dupmap, pi);
+       }
+    }
+  if (targeted && s->repo != installed && s->obsoletes)
+    {
+      /* XXX: check obsoletes/provides combination */
+      obsp = s->repo->idarraydata + s->obsoletes;
+      while ((obs = *obsp++) != 0)
+       {
+         FOR_PROVIDES(pi, pip, obs)
+           {
+             Solvable *ps = pool->solvables + pi;
+             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             MAPSET(&solv->dupinvolvedmap, pi);
+             if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
+               {
+                 Id *opp, pi2;
+                 for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
+                   if (pool->solvables[pi2].repo != installed)
+                     MAPSET(&solv->dupinvolvedmap, pi2);
+               }
+             if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0 && !solv->bestupdatemap_all)
+               {
+                 if (!solv->bestupdatemap.size)
+                   map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                 MAPSET(&solv->bestupdatemap, pi - installed->start);
+               }
+             if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
+               add_cleandeps_updatepkg(solv, pi);
+           }
+       }
+    }
+}
+
+/* create the two dupmaps:
+ * - dupmap: packages in that map are good to install/keep
+ * - dupinvolvedmap: packages are subject to dup mode
+ */
+void
+solver_createdupmaps(Solver *solv)
+{
+  Queue *job = &solv->job;
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id select, how, what, p, pp;
+  Solvable *s;
+  int i, targeted;
+
+  map_init(&solv->dupmap, pool->nsolvables);
+  solv->dupinvolvedmap_all = 0;
+  map_init(&solv->dupinvolvedmap, 0);
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      select = job->elements[i] & SOLVER_SELECTMASK;
+      what = job->elements[i + 1];
+      switch (how & SOLVER_JOBMASK)
+       {
+       case SOLVER_DISTUPGRADE:
+         if (select == SOLVER_SOLVABLE_REPO)
+           {
+             Repo *repo;
+             if (what <= 0 || what > pool->nrepos)
+               break;
+             repo = pool_id2repo(pool, what);
+             if (!repo)
+               break;
+             if (repo != installed && !(how & SOLVER_TARGETED) && solv->noautotarget)
+               break;
+             targeted = repo != installed || (how & SOLVER_TARGETED) != 0;
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 if (repo != installed && !pool_installable(pool, s))
+                   continue;
+                 solver_addtodupmaps(solv, p, how, targeted);
+               }
+           }
+         else if (select == SOLVER_SOLVABLE_ALL)
+           {
+             solv->dupinvolvedmap_all = 1;
+             FOR_POOL_SOLVABLES(p)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (!s->repo || s->repo == installed)
+                   continue;
+                 if (!pool_installable(pool, s))
+                   continue;
+                 MAPSET(&solv->dupmap, p);
+               }
+             if ((how & SOLVER_FORCEBEST) != 0)
+               solv->bestupdatemap_all = 1;
+             if ((how & SOLVER_CLEANDEPS) != 0 && installed)
+               {
+                 FOR_REPO_SOLVABLES(installed, p, s)
+                   add_cleandeps_updatepkg(solv, p);
+               }
+           }
+         else
+           {
+             targeted = how & SOLVER_TARGETED ? 1 : 0;
+             if (installed && !targeted && !solv->noautotarget)
+               {
+                 FOR_JOB_SELECT(p, pp, select, what)
+                   if (pool->solvables[p].repo == installed)
+                     break;
+                 targeted = p == 0;
+               }
+             else if (!installed && !solv->noautotarget)
+               targeted = 1;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 Solvable *s = pool->solvables + p;
+                 if (!s->repo)
+                   continue;
+                 if (s->repo != installed && !targeted)
+                   continue;
+                 if (s->repo != installed && !pool_installable(pool, s))
+                   continue;
+                 solver_addtodupmaps(solv, p, how, targeted);
+               }
+           }
+         break;
+       default:
+         break;
+       }
+    }
+  if (solv->dupinvolvedmap.size)
+    MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
+  /* set update for all involved installed packages. We need to do
+   * this before creating the update rules */
+  if (solv->dupinvolvedmap_all)
+    solv->updatemap_all = 1;
+  else if (installed && !solv->updatemap_all && solv->dupinvolvedmap.size)
+    {
+      FOR_REPO_SOLVABLES(installed, p, s)
+       {
+         if (!MAPTST(&solv->dupinvolvedmap, p))
+           continue;
+         if (!solv->updatemap.size)
+           map_grow(&solv->updatemap, installed->end - installed->start);
+         MAPSET(&solv->updatemap, p - installed->start);
+       }
+    }
+}
+
+void
+solver_freedupmaps(Solver *solv)
+{
+  map_free(&solv->dupmap);
+  /* we no longer free solv->dupinvolvedmap as we need it in
+   * policy's priority pruning code. sigh. */
+}
+
+void
+solver_addduprules(Solver *solv, Map *addedmap)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id p, pp;
+  Solvable *s, *ps;
+  int first, i;
+  Rule *r;
+
+  solv->duprules = solv->nrules;
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
+       continue;
+      s = pool->solvables + i;
+      first = i;
+      FOR_PROVIDES(p, pp, s->name)
+       {
+         ps = pool->solvables + p;
+         if (ps->name != s->name || !MAPTST(addedmap, p))
+           continue;
+         if (p == i)
+           first = 0;
+         if (first)
+           break;
+         if (!solv->dupinvolvedmap_all && !MAPTST(&solv->dupinvolvedmap, p))
+           continue;
+         if (installed && ps->repo == installed)
+           {
+             if (!MAPTST(&solv->dupmap, p))
+               {
+                 Id ip, ipp;
+                 /* is installed identical to a good one? */
+                 FOR_PROVIDES(ip, ipp, ps->name)
+                   {
+                     Solvable *is = pool->solvables + ip;
+                     if (!MAPTST(&solv->dupmap, ip))
+                       continue;
+                     if (is->evr == ps->evr && solvable_identical(ps, is))
+                       break;
+                   }
+                 if (ip)
+                   {
+                     /* ok, identical to a good one. we may keep this package. */
+                     MAPSET(&solv->dupmap, p);         /* for best rules processing */
+                     continue;
+                   }
+                 /* check if it's orphaned. If yes, we may keep it */
+                 r = solv->rules + solv->updaterules + (p - installed->start);
+                 if (!r->p)
+                   r = solv->rules + solv->featurerules + (p - installed->start);
+                 if (!r->p)
+                   {
+                     /* no update/feature rule, this is an orphan */
+                     MAPSET(&solv->dupmap, p);         /* for best rules processing */
+                     continue;
+                   }
+                 if (solv->specialupdaters && solv->specialupdaters[p - installed->start])
+                   {
+                     /* this is a multiversion orphan, we're good if an update is installed */
+                     solver_addrule(solv, -p, 0, solv->specialupdaters[p - installed->start]);
+                     continue;
+                   }
+                 if (r->p == p && !r->d && !r->w2)
+                   {
+                     r = solv->rules + solv->featurerules + (p - installed->start);
+                     if (!r->p || (!r->d && !r->w2))
+                       {
+                         /* this is an orphan */
+                         MAPSET(&solv->dupmap, p);             /* for best rules processing */
+                         continue;
+                       }
+                   }
+                 solver_addrule(solv, -p, 0, 0);       /* no match, sorry */
+               }
+           }
+         else if (!MAPTST(&solv->dupmap, p))
+           solver_addrule(solv, -p, 0, 0);
+       }
+    }
+  solv->duprules_end = solv->nrules;
+}
+
+
+static inline void
+disableduprule(Solver *solv, Id name)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
+    {
+      if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
+       solver_disablerule(solv, r);
+    }
+}
+
+static inline void
+reenableduprule(Solver *solv, Id name)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
+    {
+      if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
+       {
+         solver_enablerule(solv, r);
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
+       }
+    }
+}
+
+
+/***********************************************************************
+ ***
+ ***  Policy rule disabling/reenabling
+ ***
+ ***  Disable all policy rules that conflict with our jobs. If a job
+ ***  gets disabled later on, reenable the involved policy rules again.
+ ***
+ ***/
+
+#define DISABLE_UPDATE 1
+#define DISABLE_INFARCH        2
+#define DISABLE_DUP    3
+
+static void
+jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Id select, p, pp;
+  Repo *installed;
+  Solvable *s;
+  int i, j, set, qstart;
+  Map omap;
+
+  installed = solv->installed;
+  select = how & SOLVER_SELECTMASK;
+  switch (how & SOLVER_JOBMASK)
+    {
+    case SOLVER_INSTALL:
+      set = how & SOLVER_SETMASK;
+      if (!(set & SOLVER_NOAUTOSET))
+       {
+         /* automatically add set bits by analysing the job */
+         if (select == SOLVER_SOLVABLE_NAME)
+           set |= SOLVER_SETNAME;
+         if (select == SOLVER_SOLVABLE)
+           set |= SOLVER_SETNAME | SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
+         else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
+           {
+             Reldep *rd = GETRELDEP(pool, what);
+             if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
+               {
+                 if (pool->disttype != DISTTYPE_DEB)
+                   {
+                     const char *rel = strrchr(pool_id2str(pool, rd->evr), '-');
+                     set |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
+                   }
+                 else
+                   set |= SOLVER_SETEVR;
+               }
+             if (rd->flags <= 7 && ISRELDEP(rd->name))
+               rd = GETRELDEP(pool, rd->name);
+             if (rd->flags == REL_ARCH)
+               set |= SOLVER_SETARCH;
+           }
+       }
+      else
+       set &= ~SOLVER_NOAUTOSET;
+      if (!set)
+       return;
+      if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
+       {
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
+         else
+           {
+             int qcnt = q->count;
+             /* does not work for SOLVER_SOLVABLE_ALL and SOLVER_SOLVABLE_REPO, but
+                they are not useful for SOLVER_INSTALL jobs anyway */
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 /* unify names */
+                 for (i = qcnt; i < q->count; i += 2)
+                   if (q->elements[i + 1] == s->name)
+                     break;
+                 if (i < q->count)
+                   continue;
+                 queue_push2(q, DISABLE_INFARCH, s->name);
+               }
+           }
+       }
+      if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
+       {
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
+         else
+           {
+             int qcnt = q->count;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 /* unify names */
+                 for (i = qcnt; i < q->count; i += 2)
+                   if (q->elements[i + 1] == s->name)
+                     break;
+                 if (i < q->count)
+                   continue;
+                 queue_push2(q, DISABLE_DUP, s->name);
+               }
+           }
+       }
+      if (!installed || installed->end == installed->start)
+       return;
+      /* now the hard part: disable some update rules */
+
+      /* first check if we have installed or multiversion packages in the job */
+      FOR_JOB_SELECT(p, pp, select, what)
+       {
+         if (pool->solvables[p].repo == installed)
+           return;
+         if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes)
+           return;
+       }
+      omap.size = 0;
+      qstart = q->count;
+      FOR_JOB_SELECT(p, pp, select, what)
+       {
+         solver_intersect_obsoleted(solv, p, q, qstart, &omap);
+         if (q->count == qstart)
+           break;
+       }
+      if (omap.size)
+        map_free(&omap);
+
+      if (qstart == q->count)
+       return;         /* nothing to prune */
+
+      /* convert result to (DISABLE_UPDATE, p) pairs */
+      i = q->count;
+      for (j = qstart; j < i; j++)
+       queue_push(q, q->elements[j]);
+      for (j = qstart; j < q->count; j += 2)
+       {
+         q->elements[j] = DISABLE_UPDATE;
+         q->elements[j + 1] = q->elements[i++];
+       }
+
+      /* now that we know which installed packages are obsoleted check each of them */
+      if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
+       return;         /* all is set, nothing to do */
+
+      for (i = j = qstart; i < q->count; i += 2)
+       {
+         Solvable *is = pool->solvables + q->elements[i + 1];
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             int illegal = 0;
+             s = pool->solvables + p;
+             if ((set & SOLVER_SETEVR) != 0)
+               illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
+             if ((set & SOLVER_SETNAME) != 0)
+               illegal |= POLICY_ILLEGAL_NAMECHANGE;   /* ignore */
+             if ((set & SOLVER_SETARCH) != 0)
+               illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
+             if ((set & SOLVER_SETVENDOR) != 0)
+               illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
+             illegal = policy_is_illegal(solv, is, s, illegal);
+             if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
+               {
+                 /* it's ok if the EV is different */
+                 if (pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
+                   illegal = 0;
+               }
+             if (illegal)
+               break;
+           }
+         if (!p)
+           {   
+             /* no package conflicts with the update rule */
+             /* thus keep the DISABLE_UPDATE */
+             q->elements[j + 1] = q->elements[i + 1];
+             j += 2;
+           }
+       }
+      queue_truncate(q, j);
+      return;
+
+    case SOLVER_ERASE:
+      if (!installed)
+       break;
+      if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+       {
+         FOR_REPO_SOLVABLES(installed, p, s)
+           queue_push2(q, DISABLE_UPDATE, p);
+       }
+      FOR_JOB_SELECT(p, pp, select, what)
+       if (pool->solvables[p].repo == installed)
+         {
+           queue_push2(q, DISABLE_UPDATE, p);
+#ifdef ENABLE_LINKED_PKGS
+           if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
+             queue_push2(q, DISABLE_UPDATE, solv->instbuddy[p - installed->start]);
+#endif
+         }
+      return;
+    default:
+      return;
+    }
+}
+
+/* disable all policy rules that are in conflict with our job list */
+void
+solver_disablepolicyrules(Solver *solv)
+{
+  Queue *job = &solv->job;
+  int i, j;
+  Queue allq;
+  Rule *r;
+  Id lastjob = -1;
+  Id allqbuf[128];
+
+  queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
+
+  for (i = solv->jobrules; i < solv->jobrules_end; i++)
+    {
+      r = solv->rules + i;
+      if (r->d < 0)    /* disabled? */
+       continue;
+      j = solv->ruletojob.elements[i - solv->jobrules];
+      if (j == lastjob)
+       continue;
+      lastjob = j;
+      jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
+    }
+  if (solv->cleandepsmap.size)
+    {
+      solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
+      for (i = solv->installed->start; i < solv->installed->end; i++)
+       if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+         queue_push2(&allq, DISABLE_UPDATE, i);
+    }
+  MAPZERO(&solv->noupdate);
+  for (i = 0; i < allq.count; i += 2)
+    {
+      Id type = allq.elements[i], arg = allq.elements[i + 1];
+      switch(type)
+       {
+       case DISABLE_UPDATE:
+         disableupdaterule(solv, arg);
+         break;
+       case DISABLE_INFARCH:
+         disableinfarchrule(solv, arg);
+         break;
+       case DISABLE_DUP:
+         disableduprule(solv, arg);
+         break;
+       default:
+         break;
+       }
+    }
+  queue_free(&allq);
+}
+
+/* we just disabled job #jobidx, now reenable all policy rules that were
+ * disabled because of this job */
+void
+solver_reenablepolicyrules(Solver *solv, int jobidx)
+{
+  Queue *job = &solv->job;
+  int i, j, k, ai;
+  Queue q, allq;
+  Rule *r;
+  Id lastjob = -1;
+  Id qbuf[32], allqbuf[32];
+
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  jobtodisablelist(solv, job->elements[jobidx - 1], job->elements[jobidx], &q);
+  if (!q.count)
+    {
+      queue_free(&q);
+      return;
+    }
+  /* now remove everything from q that is disabled by other jobs */
+
+  /* first remove cleandeps packages, they count as DISABLE_UPDATE */
+  if (solv->cleandepsmap.size)
+    {
+      solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
+      for (j = k = 0; j < q.count; j += 2)
+       {
+         if (q.elements[j] == DISABLE_UPDATE)
+           {
+             Id p = q.elements[j + 1];
+             if (p >= solv->installed->start && p < solv->installed->end && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
+               continue;       /* remove element from q */
+           }
+         q.elements[k++] = q.elements[j];
+         q.elements[k++] = q.elements[j + 1];
+       }
+      q.count = k;
+      if (!q.count)
+       {
+         queue_free(&q);
+         return;
+       }
+    }
+
+  /* now go through the disable list of all other jobs */
+  queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
+  for (i = solv->jobrules; i < solv->jobrules_end; i++)
+    {
+      r = solv->rules + i;
+      if (r->d < 0)    /* disabled? */
+       continue;
+      j = solv->ruletojob.elements[i - solv->jobrules];
+      if (j == lastjob)
+       continue;
+      lastjob = j;
+      jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
+      if (!allq.count)
+       continue;
+      /* remove all elements in allq from q */
+      for (j = k = 0; j < q.count; j += 2)
+       {
+         Id type = q.elements[j], arg = q.elements[j + 1];
+         for (ai = 0; ai < allq.count; ai += 2)
+           if (allq.elements[ai] == type && allq.elements[ai + 1] == arg)
+             break;
+         if (ai < allq.count)
+           continue;   /* found it in allq, remove element from q */
+         q.elements[k++] = q.elements[j];
+         q.elements[k++] = q.elements[j + 1];
+       }
+      q.count = k;
+      if (!q.count)
+       {
+         queue_free(&q);
+         queue_free(&allq);
+         return;
+       }
+      queue_empty(&allq);
+    }
+  queue_free(&allq);
+
+  /* now re-enable anything that's left in q */
+  for (j = 0; j < q.count; j += 2)
+    {
+      Id type = q.elements[j], arg = q.elements[j + 1];
+      switch(type)
+       {
+       case DISABLE_UPDATE:
+         reenableupdaterule(solv, arg);
+         break;
+       case DISABLE_INFARCH:
+         reenableinfarchrule(solv, arg);
+         break;
+       case DISABLE_DUP:
+         reenableduprule(solv, arg);
+         break;
+       }
+    }
+  queue_free(&q);
+}
+
+/* we just removed a package from the cleandeps map, now reenable all policy rules that were
+ * disabled because of this */
+void
+solver_reenablepolicyrules_cleandeps(Solver *solv, Id pkg)
+{
+  Queue *job = &solv->job;
+  int i, j;
+  Queue allq;
+  Rule *r;
+  Id lastjob = -1;
+  Id allqbuf[128];
+
+  queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
+  for (i = solv->jobrules; i < solv->jobrules_end; i++)
+    {
+      r = solv->rules + i;
+      if (r->d < 0)    /* disabled? */
+       continue;
+      j = solv->ruletojob.elements[i - solv->jobrules];
+      if (j == lastjob)
+       continue;
+      lastjob = j;
+      jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
+    }
+  for (i = 0; i < allq.count; i += 2)
+    if (allq.elements[i] == DISABLE_UPDATE && allq.elements[i + 1] == pkg)
+      break;
+  if (i == allq.count)
+    reenableupdaterule(solv, pkg);
+  queue_free(&allq);
+}
+
+
+/***********************************************************************
+ ***
+ ***  Rule info part, tell the user what the rule is about.
+ ***
+ ***/
+
+static void
+addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+
+  if (d)
+    {
+      assert(!p2 && d > 0);
+      if (!pool->whatprovidesdata[d])
+       d = 0;
+      else if (!pool->whatprovidesdata[d + 1])
+       {
+         p2 = pool->whatprovidesdata[d];
+         d = 0;
+       }
+    }
+
+  /* check if this creates the rule we're searching for */
+  r = solv->rules + solv->ruleinfoq->elements[0];
+  if (d)
+    {
+      /* three or more literals */
+      Id od = r->d < 0 ? -r->d - 1 : r->d;
+      if (p != r->p && !od)
+       return;
+      if (d != od)
+       {
+         Id *dp = pool->whatprovidesdata + d;
+         Id *odp = pool->whatprovidesdata + od;
+         while (*dp)
+           if (*dp++ != *odp++)
+             return;
+         if (*odp)
+           return;
+       }
+      if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS)
+       p2 = pool->whatprovidesdata[d];
+    }
+  else
+    {
+      /* one or two literals */
+      Id op = p, op2 = p2;
+      if (op2 && op > op2)     /* normalize */
+       {
+         Id o = op;
+         op = op2;
+         op2 = o;
+       }
+      if (r->p != op || r->w2 != op2 || (r->d && r->d != -1))
+       return;
+      if (type == SOLVER_RULE_PKG_CONFLICTS && !p2)
+       p2 = -SYSTEMSOLVABLE;
+      if (type == SOLVER_RULE_PKG_SAME_NAME)
+       {
+         p = op;       /* we normalize same name order */
+         p2 = op2;
+       }
+    }
+  /* yep, rule matches. record info */
+  queue_push(solv->ruleinfoq, type);
+  queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
+  queue_push(solv->ruleinfoq, p2 < 0 ? -p2 : 0);
+  queue_push(solv->ruleinfoq, dep);
+}
+
+static int
+solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap, *b = bp;
+  int r;
+
+  r = a[0] - b[0];
+  if (r)
+    return r;
+  r = a[1] - b[1];
+  if (r)
+    return r;
+  r = a[2] - b[2];
+  if (r)
+    return r;
+  r = a[3] - b[3];
+  if (r)
+    return r;
+  return 0;
+}
+
+static void
+getpkgruleinfos(Solver *solv, Rule *r, Queue *rq)
+{
+  Pool *pool = solv->pool;
+  Id l, pp;
+  if (r->p >= 0)
+    return;
+  queue_push(rq, r - solv->rules);     /* push the rule we're interested in */
+  solv->ruleinfoq = rq;
+  FOR_RULELITERALS(l, pp, r)
+    {
+      if (l >= 0)
+       break;
+      solver_addpkgrulesforsolvable(solv, pool->solvables - l, 0);
+    }
+#ifdef ENABLE_LINKED_PKGS
+  FOR_RULELITERALS(l, pp, r)
+    {
+      if (l < 0)
+       {
+         if (l == r->p)
+           continue;
+         break;
+       }
+      if (!strchr(pool_id2str(pool, pool->solvables[l].name), ':') || !has_package_link(pool, pool->solvables + l))
+       break;
+      add_package_link(solv, pool->solvables + l, 0, 0);
+    }
+#endif
+  solv->ruleinfoq = 0;
+  queue_shift(rq);
+}
+
+int
+solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
+{
+  Rule *r = solv->rules + rid;
+  int i, j;
+
+  queue_empty(rq);
+  if (rid <= 0 || rid >= solv->pkgrules_end)
+    {
+      Id type, from, to, dep;
+      type = solver_ruleinfo(solv, rid, &from, &to, &dep);
+      queue_push(rq, type);
+      queue_push(rq, from);
+      queue_push(rq, to);
+      queue_push(rq, dep);
+      return 1;
+    }
+  getpkgruleinfos(solv, r, rq);
+  /* now sort & unify em */
+  if (!rq->count)
+    return 0;
+  solv_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
+  /* throw out identical entries */
+  for (i = j = 0; i < rq->count; i += 4)
+    {
+      if (j)
+       {
+         if (rq->elements[i] == rq->elements[j - 4] &&
+             rq->elements[i + 1] == rq->elements[j - 3] &&
+             rq->elements[i + 2] == rq->elements[j - 2] &&
+             rq->elements[i + 3] == rq->elements[j - 1])
+           continue;
+       }
+      rq->elements[j++] = rq->elements[i];
+      rq->elements[j++] = rq->elements[i + 1];
+      rq->elements[j++] = rq->elements[i + 2];
+      rq->elements[j++] = rq->elements[i + 3];
+    }
+  rq->count = j;
+  return j / 4;
+}
+
+SolverRuleinfo
+solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
+{
+  Pool *pool = solv->pool;
+  Rule *r = solv->rules + rid;
+  SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
+
+  if (fromp)
+    *fromp = 0;
+  if (top)
+    *top = 0;
+  if (depp)
+    *depp = 0;
+  if (rid > 0 && rid < solv->pkgrules_end)
+    {
+      Queue rq;
+      int i;
+
+      if (r->p >= 0)
+       return SOLVER_RULE_PKG;
+      if (fromp)
+       *fromp = -r->p;
+      queue_init(&rq);
+      getpkgruleinfos(solv, r, &rq);
+      type = SOLVER_RULE_PKG;
+      for (i = 0; i < rq.count; i += 4)
+       {
+         Id qt, qo, qp, qd;
+         qt = rq.elements[i];
+         qp = rq.elements[i + 1];
+         qo = rq.elements[i + 2];
+         qd = rq.elements[i + 3];
+         if (type == SOLVER_RULE_PKG || type > qt)
+           {
+             type = qt;
+             if (fromp)
+               *fromp = qp;
+             if (top)
+               *top = qo;
+             if (depp)
+               *depp = qd;
+           }
+       }
+      queue_free(&rq);
+      return type;
+    }
+  if (rid >= solv->jobrules && rid < solv->jobrules_end)
+    {
+      Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
+      if (fromp)
+       *fromp = jidx;
+      if (top)
+       *top = solv->job.elements[jidx];
+      if (depp)
+       *depp = solv->job.elements[jidx + 1];
+      if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
+       {
+         Id how = solv->job.elements[jidx];
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME))
+           return SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES))
+           return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME))
+           return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
+         if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES))
+           return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
+         return SOLVER_RULE_JOB_UNSUPPORTED;
+       }
+      return SOLVER_RULE_JOB;
+    }
+  if (rid >= solv->updaterules && rid < solv->updaterules_end)
+    {
+      if (fromp)
+       *fromp = solv->installed->start + (rid - solv->updaterules);
+      return SOLVER_RULE_UPDATE;
+    }
+  if (rid >= solv->featurerules && rid < solv->featurerules_end)
+    {
+      if (fromp)
+       *fromp = solv->installed->start + (rid - solv->featurerules);
+      return SOLVER_RULE_FEATURE;
+    }
+  if (rid >= solv->duprules && rid < solv->duprules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      if (depp)
+       *depp = pool->solvables[-r->p].name;
+      return SOLVER_RULE_DISTUPGRADE;
+    }
+  if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      if (depp)
+       *depp = pool->solvables[-r->p].name;
+      return SOLVER_RULE_INFARCH;
+    }
+  if (rid >= solv->bestrules && rid < solv->bestrules_end)
+    {
+      if (fromp && solv->bestrules_pkg[rid - solv->bestrules] > 0)
+       *fromp = solv->bestrules_pkg[rid - solv->bestrules];
+      return SOLVER_RULE_BEST;
+    }
+  if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      if (top)
+       {
+         /* first solvable is enough, we just need it for the name */
+         if (!r->d || r->d == -1)
+           *top = r->w2;
+         else
+           *top = pool->whatprovidesdata[r->d < 0 ? -r->d : r->d];
+       }
+      if (depp)
+       *depp = solv->yumobsrules_info[rid - solv->yumobsrules];
+      return SOLVER_RULE_YUMOBS;
+    }
+  if (rid >= solv->choicerules && rid < solv->choicerules_end)
+    {
+      return SOLVER_RULE_CHOICE;
+    }
+  if (rid >= solv->learntrules)
+    {
+      return SOLVER_RULE_LEARNT;
+    }
+  return SOLVER_RULE_UNKNOWN;
+}
+
+SolverRuleinfo
+solver_ruleclass(Solver *solv, Id rid)
+{
+  if (rid <= 0)
+    return SOLVER_RULE_UNKNOWN;
+  if (rid > 0 && rid < solv->pkgrules_end)
+    return SOLVER_RULE_PKG;
+  if (rid >= solv->jobrules && rid < solv->jobrules_end)
+    return SOLVER_RULE_JOB;
+  if (rid >= solv->updaterules && rid < solv->updaterules_end)
+    return SOLVER_RULE_UPDATE;
+  if (rid >= solv->featurerules && rid < solv->featurerules_end)
+    return SOLVER_RULE_FEATURE;
+  if (rid >= solv->duprules && rid < solv->duprules_end)
+    return SOLVER_RULE_DISTUPGRADE;
+  if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
+    return SOLVER_RULE_INFARCH;
+  if (rid >= solv->bestrules && rid < solv->bestrules_end)
+    return SOLVER_RULE_BEST;
+  if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
+    return SOLVER_RULE_YUMOBS;
+  if (rid >= solv->choicerules && rid < solv->choicerules_end)
+    return SOLVER_RULE_CHOICE;
+  if (rid >= solv->learntrules && rid < solv->nrules)
+    return SOLVER_RULE_LEARNT;
+  return SOLVER_RULE_UNKNOWN;
+}
+
+void
+solver_ruleliterals(Solver *solv, Id rid, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  Rule *r;
+
+  queue_empty(q);
+  r = solv->rules + rid;
+  FOR_RULELITERALS(p, pp, r)
+    if (p != -SYSTEMSOLVABLE)
+      queue_push(q, p);
+  if (!q->count)
+    queue_push(q, -SYSTEMSOLVABLE);    /* hmm, better to return an empty result? */
+}
+
+int
+solver_rule2jobidx(Solver *solv, Id rid)
+{
+  if (rid < solv->jobrules || rid >= solv->jobrules_end)
+    return 0;
+  return solv->ruletojob.elements[rid - solv->jobrules] + 1;
+}
+
+/* job rule introspection */
+Id
+solver_rule2job(Solver *solv, Id rid, Id *whatp)
+{
+  int idx;
+  if (rid < solv->jobrules || rid >= solv->jobrules_end)
+    {
+      if (whatp)
+       *whatp = 0;
+      return 0;
+    }
+  idx = solv->ruletojob.elements[rid - solv->jobrules];
+  if (whatp)
+    *whatp = solv->job.elements[idx + 1];
+  return solv->job.elements[idx];
+}
+
+/* update/feature rule introspection */
+Id
+solver_rule2solvable(Solver *solv, Id rid)
+{
+  if (rid >= solv->updaterules && rid < solv->updaterules_end)
+    return rid - solv->updaterules;
+  if (rid >= solv->featurerules && rid < solv->featurerules_end)
+    return rid - solv->featurerules;
+  return 0;
+}
+
+Id
+solver_rule2pkgrule(Solver *solv, Id rid)
+{
+  if (rid >= solv->choicerules && rid < solv->choicerules_end)
+    return solv->choicerules_ref[rid - solv->choicerules];
+  return 0;
+}
+
+static void
+solver_rule2rules_rec(Solver *solv, Id rid, Queue *q, Map *seen)
+{
+  int i;
+  Id rid2;
+
+  if (seen)
+    MAPSET(seen, rid);
+  for (i = solv->learnt_why.elements[rid - solv->learntrules]; (rid2 = solv->learnt_pool.elements[i]) != 0; i++)
+    {
+      if (seen)
+       {
+         if (MAPTST(seen, rid2))
+           continue;
+         if (rid2 >= solv->learntrules)
+           solver_rule2rules_rec(solv, rid2, q, seen);
+         continue;
+       }
+      queue_push(q, rid2);
+    }
+}
+
+/* learnt rule introspection */
+void
+solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive)
+{
+  queue_empty(q);
+  if (rid < solv->learntrules || rid >= solv->nrules)
+    return;
+  if (recursive)
+    {
+      Map seen;
+      map_init(&seen, solv->nrules);
+      solver_rule2rules_rec(solv, rid, q, &seen);
+      map_free(&seen);
+    }
+  else
+    solver_rule2rules_rec(solv, rid, q, 0);
+}
+
+
+/* check if the newest versions of pi still provides the dependency we're looking for */
+static int
+solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Rule *ur;
+  Id p, pp;
+  int i;
+
+  if (!q->count || q->elements[0] != pi)
+    {
+      if (q->count)
+        queue_empty(q);
+      ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
+      if (!ur->p)
+        ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
+      if (!ur->p)
+       return 0;
+      queue_push2(q, pi, 0);
+      FOR_RULELITERALS(p, pp, ur)
+       if (p > 0)
+         queue_push(q, p);
+    }
+  if (q->count == 2)
+    return 1;
+  if (q->count == 3)
+    {
+      p = q->elements[2];
+      return MAPTST(m, p) ? 0 : 1;
+    }
+  if (!q->elements[1])
+    {
+      for (i = 2; i < q->count; i++)
+       if (!MAPTST(m, q->elements[i]))
+         break;
+      if (i == q->count)
+       return 0;       /* all provide it, no need to filter */
+      /* some don't provide it, have to filter */
+      queue_deleten(q, 0, 2);
+      policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
+      queue_unshift(q, 1);     /* filter mark */
+      queue_unshift(q, pi);
+    }
+  for (i = 2; i < q->count; i++)
+    if (MAPTST(m, q->elements[i]))
+      return 0;                /* at least one provides it */
+  return 1;    /* none of the new packages provided it */
+}
+
+static inline void
+queue_removeelement(Queue *q, Id el)
+{
+  int i, j;
+  for (i = 0; i < q->count; i++)
+    if (q->elements[i] == el)
+      break;
+  if (i < q->count)
+    {
+      for (j = i++; i < q->count; i++)
+       if (q->elements[i] != el)
+         q->elements[j++] = q->elements[i];
+      queue_truncate(q, j);
+    }
+}
+
+void
+solver_addchoicerules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Map m, mneg;
+  Rule *r;
+  Queue q, qi, qcheck;
+  int i, j, rid, havechoice;
+  Id p, d, pp;
+  Id p2, pp2;
+  Solvable *s, *s2;
+  Id lastaddedp, lastaddedd;
+  int lastaddedcnt;
+  unsigned int now;
+
+  solv->choicerules = solv->nrules;
+  if (!pool->installed)
+    {
+      solv->choicerules_end = solv->nrules;
+      return;
+    }
+  now = solv_timems(0);
+  solv->choicerules_ref = solv_calloc(solv->pkgrules_end, sizeof(Id));
+  queue_init(&q);
+  queue_init(&qi);
+  queue_init(&qcheck);
+  map_init(&m, pool->nsolvables);
+  map_init(&mneg, pool->nsolvables);
+  /* set up negative assertion map from infarch and dup rules */
+  for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
+    if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
+      MAPSET(&mneg, -r->p);
+  for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
+    if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
+      MAPSET(&mneg, -r->p);
+  lastaddedp = 0;
+  lastaddedd = 0;
+  lastaddedcnt = 0;
+  for (rid = 1; rid < solv->pkgrules_end ; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 <= 0))
+       continue;       /* only look at requires rules */
+      /* solver_printrule(solv, SOLV_DEBUG_RESULT, r); */
+      queue_empty(&q);
+      queue_empty(&qi);
+      havechoice = 0;
+      FOR_RULELITERALS(p, pp, r)
+       {
+         if (p < 0)
+           continue;
+         s = pool->solvables + p;
+         if (!s->repo)
+           continue;
+         if (s->repo == pool->installed)
+           {
+             queue_push(&q, p);
+             continue;
+           }
+         /* check if this package is "blocked" by a installed package */
+         s2 = 0;
+         FOR_PROVIDES(p2, pp2, s->name)
+           {
+             s2 = pool->solvables + p2;
+             if (s2->repo != pool->installed)
+               continue;
+             if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
+               continue;
+             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
+               continue;
+             break;
+           }
+         if (p2)
+           {
+             /* found installed package p2 that we can update to p */
+             if (MAPTST(&mneg, p))
+               continue;
+             if (policy_is_illegal(solv, s2, s, 0))
+               continue;
+#if 0
+             if (solver_choicerulecheck(solv, p2, r, &m))
+               continue;
+             queue_push(&qi, p2);
+#else
+             queue_push2(&qi, p2, p);
+#endif
+             queue_push(&q, p);
+             continue;
+           }
+         if (s->obsoletes)
+           {
+             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+             s2 = 0;
+             while ((obs = *obsp++) != 0)
+               {
+                 FOR_PROVIDES(p2, pp2, obs)
+                   {
+                     s2 = pool->solvables + p2;
+                     if (s2->repo != pool->installed)
+                       continue;
+                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+                       continue;
+                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+                       continue;
+                     break;
+                   }
+                 if (p2)
+                   break;
+               }
+             if (obs)
+               {
+                 /* found installed package p2 that we can update to p */
+                 if (MAPTST(&mneg, p))
+                   continue;
+                 if (policy_is_illegal(solv, s2, s, 0))
+                   continue;
+#if 0
+                 if (solver_choicerulecheck(solv, p2, r, &m))
+                   continue;
+                 queue_push(&qi, p2);
+#else
+                 queue_push2(&qi, p2, p);
+#endif
+                 queue_push(&q, p);
+                 continue;
+               }
+           }
+         /* package p is independent of the installed ones */
+         havechoice = 1;
+       }
+      if (!havechoice || !q.count || !qi.count)
+       continue;       /* no choice */
+
+      FOR_RULELITERALS(p, pp, r)
+        if (p > 0)
+         MAPSET(&m, p);
+
+      /* do extra checking */
+      for (i = j = 0; i < qi.count; i += 2)
+       {
+         p2 = qi.elements[i];
+         if (!p2)
+           continue;
+         if (solver_choicerulecheck(solv, p2, r, &m, &qcheck))
+           {
+             /* oops, remove element p from q */
+             queue_removeelement(&q, qi.elements[i + 1]);
+             continue;
+           }
+         qi.elements[j++] = p2;
+       }
+      queue_truncate(&qi, j);
+
+      if (!q.count || !qi.count)
+       {
+         FOR_RULELITERALS(p, pp, r)
+           if (p > 0)
+             MAPCLR(&m, p);
+         continue;
+       }
+
+
+      /* now check the update rules of the installed package.
+       * if all packages of the update rules are contained in
+       * the dependency rules, there's no need to set up the choice rule */
+      for (i = 0; i < qi.count; i++)
+       {
+         Rule *ur;
+         if (!qi.elements[i])
+           continue;
+         ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
+         if (!ur->p)
+           ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
+         if (!ur->p)
+           continue;
+         FOR_RULELITERALS(p, pp, ur)
+           if (!MAPTST(&m, p))
+             break;
+         if (p)
+           break;
+         for (j = i + 1; j < qi.count; j++)
+           if (qi.elements[i] == qi.elements[j])
+             qi.elements[j] = 0;
+       }
+      /* empty map again */
+      FOR_RULELITERALS(p, pp, r)
+        if (p > 0)
+         MAPCLR(&m, p);
+      if (i == qi.count)
+       {
+#if 0
+         printf("skipping choice ");
+         solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
+#endif
+         continue;
+       }
+
+      /* don't add identical rules */
+      if (lastaddedp == r->p && lastaddedcnt == q.count)
+       {
+         for (i = 0; i < q.count; i++)
+           if (q.elements[i] != pool->whatprovidesdata[lastaddedd + i])
+             break;
+         if (i == q.count)
+           continue;   /* already added that one */
+       }
+      d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
+
+      lastaddedp = r->p;
+      lastaddedd = d;
+      lastaddedcnt = q.count;
+
+      solver_addrule(solv, r->p, 0, d);
+      queue_push(&solv->weakruleq, solv->nrules - 1);
+      solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
+#if 0
+      printf("OLD ");
+      solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
+      printf("WEAK CHOICE ");
+      solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + solv->nrules - 1);
+#endif
+    }
+  queue_free(&q);
+  queue_free(&qi);
+  queue_free(&qcheck);
+  map_free(&m);
+  map_free(&mneg);
+  solv->choicerules_end = solv->nrules;
+  /* shrink choicerules_ref */
+  solv->choicerules_ref = solv_realloc2(solv->choicerules_ref, solv->choicerules_end - solv->choicerules, sizeof(Id));
+  POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now));
+}
+
+/* called when a choice rule is disabled by analyze_unsolvable. We also
+ * have to disable all other choice rules so that the best packages get
+ * picked */
+void
+solver_disablechoicerules(Solver *solv, Rule *r)
+{
+  Id rid, p, pp;
+  Pool *pool = solv->pool;
+  Map m;
+  Rule *or;
+
+  or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
+  map_init(&m, pool->nsolvables);
+  FOR_RULELITERALS(p, pp, or)
+    if (p > 0)
+      MAPSET(&m, p);
+  FOR_RULELITERALS(p, pp, r)
+    if (p > 0)
+      MAPCLR(&m, p);
+  for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->d < 0)
+       continue;
+      or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
+      FOR_RULELITERALS(p, pp, or)
+        if (p > 0 && MAPTST(&m, p))
+         break;
+      if (p)
+       solver_disablerule(solv, r);
+    }
+}
+
+static void
+prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
+{
+  int i, j;
+  Id p, *cp2;
+  for (i = j = 0; i < q->count; i++)
+    {
+      p = q->elements[i];
+      for (cp2 = cp; *cp2; cp2++)
+        if (*cp2 == p)
+          {
+            q->elements[j++] = p;
+            break;
+          }
+    }
+  queue_truncate(q, j);
+}
+
+static void
+prune_to_dup_packages(Solver *solv, Id p, Queue *q)
+{
+  int i, j;
+  for (i = j = 0; i < q->count; i++)
+    {
+      Id p = q->elements[i];
+      if (MAPTST(&solv->dupmap, p))
+       q->elements[j++] = p;
+    }
+  queue_truncate(q, j);
+}
+
+void
+solver_addbestrules(Solver *solv, int havebestinstalljobs)
+{
+  Pool *pool = solv->pool;
+  Id p;
+  Solvable *s;
+  Repo *installed = solv->installed;
+  Queue q, q2;
+  Rule *r;
+  Queue r2pkg;
+  int i, oldcnt;
+
+  solv->bestrules = solv->nrules;
+  queue_init(&q);
+  queue_init(&q2);
+  queue_init(&r2pkg);
+
+  if (havebestinstalljobs)
+    {
+      for (i = 0; i < solv->job.count; i += 2)
+       {
+         Id how = solv->job.elements[i];
+         if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
+           {
+             int j;
+             Id p2, pp2;
+             for (j = 0; j < solv->ruletojob.count; j++)
+               {
+                 if (solv->ruletojob.elements[j] != i)
+                   continue;
+                 r = solv->rules + solv->jobrules + j;
+                 queue_empty(&q);
+                 queue_empty(&q2);
+                 FOR_RULELITERALS(p2, pp2, r)
+                   {
+                     if (p2 > 0)
+                       queue_push(&q, p2);
+                     else if (p2 < 0)
+                       queue_push(&q2, p2);
+                   }
+                 if (!q.count)
+                   continue;   /* orphaned */
+                 /* select best packages, just look at prio and version */
+                 oldcnt = q.count;
+                 policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+                 if (q.count == oldcnt)
+                   continue;   /* nothing filtered */
+                 if (q2.count)
+                   queue_insertn(&q, 0, q2.count, q2.elements);
+                 p2 = queue_shift(&q);
+                 if (q.count < 2)
+                   solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
+                 else
+                   solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
+                 if ((how & SOLVER_WEAK) != 0)
+                   queue_push(&solv->weakruleq, solv->nrules - 1);
+                 queue_push(&r2pkg, -(solv->jobrules + j));
+               }
+           }
+       }
+    }
+  solv->bestrules_up = solv->nrules;
+
+  if (installed && (solv->bestupdatemap_all || solv->bestupdatemap.size))
+    {
+      Map m;
+
+      if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
+       map_init(&m, pool->nsolvables);
+      else
+       map_init(&m, 0);
+      FOR_REPO_SOLVABLES(installed, p, s)
+       {
+         Id d, p2, pp2;
+         if (!solv->updatemap_all && (!solv->updatemap.size || !MAPTST(&solv->updatemap, p - installed->start)))
+           continue;
+         if (!solv->bestupdatemap_all && (!solv->bestupdatemap.size || !MAPTST(&solv->bestupdatemap, p - installed->start)))
+           continue;
+         queue_empty(&q);
+         if (solv->bestobeypolicy)
+           r = solv->rules + solv->updaterules + (p - installed->start);
+         else
+           {
+             r = solv->rules + solv->featurerules + (p - installed->start);
+             if (!r->p)        /* identical to update rule? */
+               r = solv->rules + solv->updaterules + (p - installed->start);
+           }
+         if (solv->specialupdaters && (d = solv->specialupdaters[p - installed->start]) != 0 && r == solv->rules + solv->updaterules + (p - installed->start))
+           {
+             /* need to check specialupdaters */
+             if (r->p == p)    /* be careful with the dup case */
+               queue_push(&q, p);
+             while ((p2 = pool->whatprovidesdata[d++]) != 0)
+               queue_push(&q, p2);
+           }
+         else
+           {
+             FOR_RULELITERALS(p2, pp2, r)
+               if (p2 > 0)
+                 queue_push(&q, p2);
+           }
+         if (solv->update_targets && solv->update_targets->elements[p - installed->start])
+           prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
+         if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+           prune_to_dup_packages(solv, p, &q);
+         /* select best packages, just look at prio and version */
+         policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+         if (!q.count)
+           continue;   /* orphaned */
+         if (solv->bestobeypolicy)
+           {
+             /* also filter the best of the feature rule packages and add them */
+             r = solv->rules + solv->featurerules + (p - installed->start);
+             if (r->p)
+               {
+                 int j;
+                 queue_empty(&q2);
+                 FOR_RULELITERALS(p2, pp2, r)
+                   if (p2 > 0)
+                     queue_push(&q2, p2);
+                 if (solv->update_targets && solv->update_targets->elements[p - installed->start])
+                   prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q2);
+                 if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+                   prune_to_dup_packages(solv, p, &q2);
+                 policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
+                 for (j = 0; j < q2.count; j++)
+                   queue_pushunique(&q, q2.elements[j]);
+               }
+           }
+         if (solv->allowuninstall || solv->allowuninstall_all || (solv->allowuninstallmap.size && MAPTST(&solv->allowuninstallmap, p - installed->start)))
+           {
+             /* package is flagged both for allowuninstall and best, add negative rules */
+             d = q.count == 1 ? q.elements[0] : -pool_queuetowhatprovides(pool, &q);
+             for (i = 0; i < q.count; i++)
+               MAPSET(&m, q.elements[i]);
+             r = solv->rules + solv->featurerules + (p - installed->start);
+             if (!r->p)        /* identical to update rule? */
+               r = solv->rules + solv->updaterules + (p - installed->start);
+             FOR_RULELITERALS(p2, pp2, r)
+               {
+                 if (MAPTST(&m, p2))
+                   continue;
+                 if (d >= 0)
+                   solver_addrule(solv, -p2, d, 0);
+                 else
+                   solver_addrule(solv, -p2, 0, -d);
+                 queue_push(&r2pkg, p);
+               }
+             for (i = 0; i < q.count; i++)
+               MAPCLR(&m, q.elements[i]);
+             continue;
+           }
+         p2 = queue_shift(&q);
+         if (q.count < 2)
+           solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
+         else
+           solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
+         queue_push(&r2pkg, p);
+       }
+      map_free(&m);
+    }
+  if (r2pkg.count)
+    solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id));
+  solv->bestrules_end = solv->nrules;
+  queue_free(&q);
+  queue_free(&q2);
+  queue_free(&r2pkg);
+}
+
+
+
+
+/* yumobs rule handling */
+/* note that we use pool->obsoleteusescolors || pool->implicitobsoleteusescolors
+ * like in policy_findupdatepackages */
+
+static void
+find_obsolete_group(Solver *solv, Id obs, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Queue qn;
+  Id p2, pp2, op, *opp, opp2;
+  int i, j, qnc, ncnt;
+
+  queue_empty(q);
+  FOR_PROVIDES(p2, pp2, obs)
+    {
+      Solvable *s2 = pool->solvables + p2;
+      if (s2->repo != pool->installed)
+       continue;
+      if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+       continue;
+      /* we obsolete installed package s2 with obs. now find all other packages that have the same dep  */
+      for (opp = solv->obsoletes_data + solv->obsoletes[p2 - solv->installed->start]; (op = *opp++) != 0;)
+       {
+         Solvable *os = pool->solvables + op;
+         Id obs2, *obsp2;
+         if (!os->obsoletes)
+           continue;
+         if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
+           continue;
+         obsp2 = os->repo->idarraydata + os->obsoletes; 
+         while ((obs2 = *obsp2++) != 0)
+           if (obs2 == obs)
+             break;
+         if (obs2)
+           queue_pushunique(q, op);
+       }
+      /* also search packages with the same name */
+      FOR_PROVIDES(op, opp2, s2->name)
+       {
+         Solvable *os = pool->solvables + op;
+         Id obs2, *obsp2;
+         if (os->name != s2->name)
+           continue;
+         if (!os->obsoletes)
+           continue;
+         if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
+           continue;
+         obsp2 = os->repo->idarraydata + os->obsoletes; 
+         while ((obs2 = *obsp2++) != 0)
+           if (obs2 == obs)
+             break;
+         if (obs2)
+           queue_pushunique(q, op);
+       }
+    }
+  /* find names so that we can build groups */
+  queue_init_clone(&qn, q);
+  prune_to_best_version(solv->pool, &qn);
+#if 0
+{
+  for (i = 0; i < qn.count; i++)
+    printf(" + %s\n", pool_solvid2str(pool, qn.elements[i]));
+}
+#endif
+  /* filter into name groups */
+  qnc = qn.count;
+  if (qnc == 1)
+    {
+      queue_free(&qn);
+      queue_empty(q);
+      return;
+    }
+  ncnt = 0;
+  for (i = 0; i < qnc; i++)
+    {
+      Id n = pool->solvables[qn.elements[i]].name;
+      int got = 0;
+      for (j = 0; j < q->count; j++)
+       {
+         Id p = q->elements[j];
+         if (pool->solvables[p].name == n)
+           {
+             queue_push(&qn, p);
+             got = 1;
+           }
+       }
+      if (got)
+       {
+         queue_push(&qn, 0);
+         ncnt++;
+       }
+    }
+  if (ncnt <= 1)
+    {
+      queue_empty(q);
+    }
+  else
+    {
+      queue_empty(q);
+      queue_insertn(q, 0, qn.count - qnc, qn.elements + qnc);
+    }
+  queue_free(&qn);
+}
+
+void
+solver_addyumobsrules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id p, op, *opp;
+  Solvable *s;
+  Queue qo, qq, yumobsinfoq;
+  int i, j, k;
+  unsigned int now;
+
+  solv->yumobsrules = solv->nrules;
+  if (!installed || !solv->obsoletes)
+    {
+      solv->yumobsrules_end = solv->nrules;
+      return;
+    }
+  now = solv_timems(0);
+  queue_init(&qo);
+  FOR_REPO_SOLVABLES(installed, p, s)
+    {
+      if (!solv->obsoletes[p - installed->start])
+       continue;
+#if 0
+printf("checking yumobs for %s\n", pool_solvable2str(pool, s));
+#endif
+      for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (op = *opp++) != 0;)
+       {
+         Solvable *os = pool->solvables + op;
+          Id obs, *obsp = os->repo->idarraydata + os->obsoletes;
+         Id p2, pp2;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p2, pp2, obs)
+               {
+                 Solvable *s2 = pool->solvables + p2;
+                 if (s2->repo != installed)
+                   continue;
+                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+                   continue;
+                 if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, s2))
+                   continue;
+                 queue_pushunique(&qo, obs);
+                 break;
+               }
+           }
+       }
+    }
+  if (!qo.count)
+    {
+      queue_free(&qo);
+      return;
+    }
+  queue_init(&yumobsinfoq);
+  queue_init(&qq);
+  for (i = 0; i < qo.count; i++)
+    {
+      int group, groupk, groupstart;
+      queue_empty(&qq);
+#if 0
+printf("investigating %s\n", pool_dep2str(pool, qo.elements[i]));
+#endif
+      find_obsolete_group(solv, qo.elements[i], &qq);
+#if 0
+printf("result:\n");
+for (j = 0; j < qq.count; j++)
+  if (qq.elements[j] == 0)
+    printf("---\n");
+  else
+    printf("%s\n", pool_solvid2str(pool, qq.elements[j]));
+#endif
+  
+      if (!qq.count)
+       continue;
+      /* at least two goups, build rules */
+      group = 0;
+      for (j = 0; j < qq.count; j++)
+       {
+         p = qq.elements[j];
+         if (!p)
+           {
+             group++;
+             continue;
+           }
+         if (pool->solvables[p].repo == installed)
+           continue;
+         groupk = 0;
+         groupstart = 0;
+         for (k = 0; k < qq.count; k++)
+           {
+             Id pk = qq.elements[k];
+             if (pk)
+               continue;
+             if (group != groupk && k > groupstart)
+               {
+                 /* add the rule */
+                 if (k - groupstart == 1)
+                   solver_addrule(solv, -p, qq.elements[groupstart], 0);
+                 else
+                   solver_addrule(solv, -p, 0, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart));
+                 queue_push(&yumobsinfoq, qo.elements[i]);
+               }
+             groupstart = k + 1;
+             groupk++;
+           }
+       }
+    }
+  if (yumobsinfoq.count)
+    solv->yumobsrules_info = solv_memdup2(yumobsinfoq.elements, yumobsinfoq.count, sizeof(Id));
+  queue_free(&yumobsinfoq);
+  queue_free(&qq);
+  queue_free(&qo);
+  solv->yumobsrules_end = solv->nrules;
+  POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now));
+}
+
+void
+solver_breakorphans(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int i, rid;
+  Map m;
+
+  if (!installed || solv->droporphanedmap_all)
+    return;
+  solv->brokenorphanrules = solv_calloc(1, sizeof(Queue));
+  queue_init(solv->brokenorphanrules);
+  map_init(&m, installed->end - installed->start);
+  for (i = 0; i < solv->orphaned.count; i++)
+    {
+      Id p = solv->orphaned.elements[i];
+      if (pool->solvables[p].repo != installed)
+       continue;
+      if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - installed->start))
+       continue;
+      MAPSET(&m, p - installed->start);
+    }
+  for (rid = 1; rid < solv->pkgrules_end ; rid++)
+    {
+      Id p, *dp;
+      Rule *r = solv->rules + rid;
+      /* ignore non-deps and simple conflicts */
+      if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
+       continue;
+      p = -r->p;
+      if (p < installed->start || p >= installed->end || !MAPTST(&m, p - installed->start))
+       {
+         /* need to check other literals */
+         if (r->d == 0 || r->d == -1)
+           continue;
+         for (dp = pool->whatprovidesdata + (r->d < 0 ? -r->d - 1 : r->d); *dp < 0; dp++)
+           {
+             p = -*dp;
+             if (p >= installed->start && p < installed->end && MAPTST(&m, p - installed->start))
+               break;
+           }
+         if (*dp >= 0)
+           continue;
+       }
+      /* ok, disable this rule */
+      queue_push(solv->brokenorphanrules, rid);
+      if (r->d >= 0)
+       solver_disablerule(solv, r);
+    }
+  map_free(&m);
+  if (!solv->brokenorphanrules->count)
+    {
+      queue_free(solv->brokenorphanrules);
+      solv->brokenorphanrules = solv_free(solv->brokenorphanrules);
+    }
+}
+
+void
+solver_check_brokenorphanrules(Solver *solv, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id l, pp;
+  
+  queue_empty(dq);
+  if (!solv->brokenorphanrules)
+    return;
+  for (i = 0; i < solv->brokenorphanrules->count; i++)
+    {
+      int rid = solv->brokenorphanrules->elements[i];
+      Rule *r = solv->rules + rid;
+      FOR_RULELITERALS(l, pp, r)
+       {
+         if (l < 0)
+           {
+             if (solv->decisionmap[-l] <= 0)
+               break;
+           }
+         else
+           {
+             if (solv->decisionmap[l] > 0 && pool->solvables[l].repo != solv->installed)
+               break;
+           }
+       }
+      if (l)
+       continue;
+      FOR_RULELITERALS(l, pp, r)
+        if (l > 0 && solv->decisionmap[l] == 0 && pool->solvables[l].repo != solv->installed)
+         queue_pushunique(dq, l);
+    }
+}
+
diff --git a/libsolv-0.7.2/src/rules.h b/libsolv-0.7.2/src/rules.h
new file mode 100644 (file)
index 0000000..a3c0135
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * rules.h
+ *
+ */
+
+#ifndef LIBSOLV_RULES_H
+#define LIBSOLV_RULES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ----------------------------------------------
+ * Rule
+ *
+ *   providerN(B) == Package Id of package providing tag B
+ *   N = 1, 2, 3, in case of multiple providers
+ *
+ * A requires B : !A | provider1(B) | provider2(B)
+ *
+ * A conflicts B : (!A | !provider1(B)) & (!A | !provider2(B)) ...
+ *
+ * 'not' is encoded as a negative Id
+ *
+ * Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
+ *
+ * There are a lot of rules, so the struct is kept as small as
+ * possible. Do not add new members unless there is no other way.
+ */
+
+typedef struct s_Rule {
+  Id p;                /* first literal in rule */
+  Id d;                /* Id offset into 'list of providers terminated by 0' as used by whatprovides; pool->whatprovides + d */
+               /* in case of binary rules, d == 0, w1 == p, w2 == other literal */
+               /* in case of disabled rules: ~d, aka -d - 1 */
+  Id w1, w2;   /* watches, literals not-yet-decided */
+               /* if !w2, assertion, not rule */
+  Id n1, n2;   /* next rules in linked list, corresponding to w1, w2 */
+} Rule;
+
+
+typedef enum {
+  SOLVER_RULE_UNKNOWN = 0,
+  SOLVER_RULE_PKG = 0x100,
+  SOLVER_RULE_PKG_NOT_INSTALLABLE,
+  SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP,
+  SOLVER_RULE_PKG_REQUIRES,
+  SOLVER_RULE_PKG_SELF_CONFLICT,
+  SOLVER_RULE_PKG_CONFLICTS,
+  SOLVER_RULE_PKG_SAME_NAME,
+  SOLVER_RULE_PKG_OBSOLETES,
+  SOLVER_RULE_PKG_IMPLICIT_OBSOLETES,
+  SOLVER_RULE_PKG_INSTALLED_OBSOLETES,
+  SOLVER_RULE_PKG_RECOMMENDS,
+  SOLVER_RULE_UPDATE = 0x200,
+  SOLVER_RULE_FEATURE = 0x300,
+  SOLVER_RULE_JOB = 0x400,
+  SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP,
+  SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM,
+  SOLVER_RULE_JOB_UNKNOWN_PACKAGE,
+  SOLVER_RULE_JOB_UNSUPPORTED,
+  SOLVER_RULE_DISTUPGRADE = 0x500,
+  SOLVER_RULE_INFARCH = 0x600,
+  SOLVER_RULE_CHOICE = 0x700,
+  SOLVER_RULE_LEARNT = 0x800,
+  SOLVER_RULE_BEST = 0x900,
+  SOLVER_RULE_YUMOBS = 0xa00
+} SolverRuleinfo;
+
+#define SOLVER_RULE_TYPEMASK    0xff00
+
+struct s_Solver;
+
+/*-------------------------------------------------------------------
+ * disable rule
+ */
+
+static inline void
+solver_disablerule(struct s_Solver *solv, Rule *r)
+{
+  if (r->d >= 0)
+    r->d = -r->d - 1;
+}
+
+/*-------------------------------------------------------------------
+ * enable rule
+ */
+
+static inline void
+solver_enablerule(struct s_Solver *solv, Rule *r)
+{
+  if (r->d < 0)
+    r->d = -r->d - 1;
+}
+
+extern Rule *solver_addrule(struct s_Solver *solv, Id p, Id p2, Id d);
+extern void solver_unifyrules(struct s_Solver *solv);
+extern int solver_rulecmp(struct s_Solver *solv, Rule *r1, Rule *r2);
+extern void solver_shrinkrules(struct s_Solver *solv, int nrules);
+
+/* pkg rules */
+extern void solver_addpkgrulesforsolvable(struct s_Solver *solv, Solvable *s, Map *m);
+extern void solver_addpkgrulesforweak(struct s_Solver *solv, Map *m);
+extern void solver_addpkgrulesforlinked(struct s_Solver *solv, Map *m);
+extern void solver_addpkgrulesforupdaters(struct s_Solver *solv, Solvable *s, Map *m, int allow_all);
+
+/* update/feature rules */
+extern void solver_addfeaturerule(struct s_Solver *solv, Solvable *s);
+extern void solver_addupdaterule(struct s_Solver *solv, Solvable *s);
+
+/* infarch rules */
+extern void solver_addinfarchrules(struct s_Solver *solv, Map *addedmap);
+
+/* dup rules */
+extern void solver_createdupmaps(struct s_Solver *solv);
+extern void solver_freedupmaps(struct s_Solver *solv);
+extern void solver_addduprules(struct s_Solver *solv, Map *addedmap);
+
+/* choice rules */
+extern void solver_addchoicerules(struct s_Solver *solv);
+extern void solver_disablechoicerules(struct s_Solver *solv, Rule *r);
+
+/* best rules */
+extern void solver_addbestrules(struct s_Solver *solv, int havebestinstalljobs);
+
+/* yumobs rules */
+extern void solver_addyumobsrules(struct s_Solver *solv);
+
+/* policy rule disabling/reenabling */
+extern void solver_disablepolicyrules(struct s_Solver *solv);
+extern void solver_reenablepolicyrules(struct s_Solver *solv, int jobidx);
+extern void solver_reenablepolicyrules_cleandeps(struct s_Solver *solv, Id pkg);
+
+/* rule info */
+extern int solver_allruleinfos(struct s_Solver *solv, Id rid, Queue *rq);
+extern SolverRuleinfo solver_ruleinfo(struct s_Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
+extern SolverRuleinfo solver_ruleclass(struct s_Solver *solv, Id rid);
+extern void solver_ruleliterals(struct s_Solver *solv, Id rid, Queue *q);
+extern int  solver_rule2jobidx(struct s_Solver *solv, Id rid);
+extern Id   solver_rule2job(struct s_Solver *solv, Id rid, Id *whatp);
+extern Id   solver_rule2solvable(struct s_Solver *solv, Id rid);
+extern void solver_rule2rules(struct s_Solver *solv, Id rid, Queue *q, int recursive);
+extern Id   solver_rule2pkgrule(struct s_Solver *solv, Id rid);
+
+/* orphan handling */
+extern void solver_breakorphans(struct s_Solver *solv);
+extern void solver_check_brokenorphanrules(struct s_Solver *solv, Queue *dq);
+
+
+/* legacy */
+#define SOLVER_RULE_RPM SOLVER_RULE_PKG
+#define SOLVER_RULE_RPM_NOT_INSTALLABLE SOLVER_RULE_PKG_NOT_INSTALLABLE
+#define SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP
+#define SOLVER_RULE_RPM_PACKAGE_REQUIRES SOLVER_RULE_PKG_REQUIRES
+#define SOLVER_RULE_RPM_SELF_CONFLICT SOLVER_RULE_PKG_SELF_CONFLICT
+#define SOLVER_RULE_RPM_PACKAGE_CONFLICT SOLVER_RULE_PKG_CONFLICTS
+#define SOLVER_RULE_RPM_SAME_NAME SOLVER_RULE_PKG_SAME_NAME
+#define SOLVER_RULE_RPM_PACKAGE_OBSOLETES SOLVER_RULE_PKG_OBSOLETES
+#define SOLVER_RULE_RPM_IMPLICIT_OBSOLETES SOLVER_RULE_PKG_IMPLICIT_OBSOLETES
+#define SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES SOLVER_RULE_PKG_INSTALLED_OBSOLETES
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libsolv-0.7.2/src/selection.c b/libsolv-0.7.2/src/selection.c
new file mode 100644 (file)
index 0000000..a160122
--- /dev/null
@@ -0,0 +1,2081 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * selection.c
+ *
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "selection.h"
+#include "solver.h"
+#include "evr.h"
+
+
+static int
+str2archid(Pool *pool, const char *arch)
+{
+  Id id;
+  if (!*arch)
+    return 0;
+  id = pool_str2id(pool, arch, 0);
+  if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
+    return id;
+  if (pool->id2arch && pool_arch2score(pool, id) == 0)
+    return 0;
+  return id;
+}
+
+/* remove empty jobs from the selection */
+static void
+selection_prune(Pool *pool, Queue *selection)
+{
+  int i, j;
+  Id p, pp;
+  for (i = j = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      p = 0;
+      if (select == SOLVER_SOLVABLE_ALL)
+       p = 1;
+      else if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
+         if (repo)
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               break;
+           }
+       }
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
+           break;
+       }
+      if (!p)
+       continue;
+      selection->elements[j] = selection->elements[i];
+      selection->elements[j + 1] = selection->elements[i + 1];
+      j += 2;
+    }
+  queue_truncate(selection, j);
+}
+
+
+static int
+selection_solvables_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  return *(const Id *)ap - *(const Id *)bp;
+}
+
+void
+selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
+{
+  int i, j;
+  Id p, pp, lastid;
+  queue_empty(pkgs);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      Id id = selection->elements[i + 1];
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         FOR_POOL_SOLVABLES(p)
+           queue_push(pkgs, p);
+       }
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, id);
+         if (repo)
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               queue_push(pkgs, p);
+           }
+       }
+      else if (select == SOLVER_SOLVABLE)
+       queue_push(pkgs, id);
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, id)
+           queue_push(pkgs, p);
+       }
+    }
+  if (pkgs->count < 2)
+    return;
+  /* sort and unify */
+  solv_sort(pkgs->elements, pkgs->count, sizeof(Id), selection_solvables_sortcmp, NULL);
+  lastid = pkgs->elements[0];
+  for (i = j = 1; i < pkgs->count; i++)
+    if (pkgs->elements[i] != lastid)
+      pkgs->elements[j++] = lastid = pkgs->elements[i];
+  queue_truncate(pkgs, j);
+}
+
+static void
+selection_flatten(Pool *pool, Queue *selection)
+{
+  Queue q;
+  int i;
+  if (selection->count <= 2)
+    return;
+  for (i = 0; i < selection->count; i += 2)
+    if ((selection->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+      {
+       selection->elements[0] = selection->elements[i];
+       selection->elements[1] = selection->elements[i + 1];
+       queue_truncate(selection, 2);
+       return;
+      }
+  queue_init(&q);
+  selection_solvables(pool, selection, &q);
+  if (!q.count)
+    {
+      queue_empty(selection);
+      return;
+    }
+  queue_truncate(selection, 2);
+  if (q.count > 1)
+    {
+      selection->elements[0] = SOLVER_SOLVABLE_ONE_OF;
+      selection->elements[1] = pool_queuetowhatprovides(pool, &q);
+    }
+  else
+    {
+      selection->elements[0] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+      selection->elements[1] = q.elements[0];
+    }
+}
+
+/* only supports simple rels plus REL_ARCH */
+static int
+match_nevr_rel(Pool *pool, Solvable *s, Id rflags, Id revr)
+{
+  if (rflags == REL_ARCH)
+    {
+      if (s->arch != revr) 
+       {
+         if (revr != ARCH_SRC || s->arch != ARCH_NOSRC)
+           return 0;
+       }
+      return 1;
+    }
+  if (rflags > 7)
+    return 0;
+  return pool_intersect_evrs(pool, REL_EQ, s->evr, rflags, revr);
+}
+
+/* only supports simple rels plus REL_ARCH */
+static void
+selection_filter_rel_noprune(Pool *pool, Queue *selection, Id relflags, Id relevr)
+{
+  int i;
+
+  if (!selection->count)
+    return;
+
+  for (i = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      Id id = selection->elements[i + 1];
+      if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
+       {
+         /* done by selection_addextra, currently implies SELECTION_NAME */
+         Queue q;
+         Id p, pp;
+         int miss = 0;
+
+         queue_init(&q);
+         FOR_JOB_SELECT(p, pp, select, id)
+           {
+             Solvable *s = pool->solvables + p;
+             if (match_nevr_rel(pool, s, relflags, relevr))
+               queue_push(&q, p);
+             else
+               miss = 1;
+           }
+         if (miss)
+           {
+             if (q.count == 1)
+               {
+                 selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+                 selection->elements[i + 1] = q.elements[0];
+               }
+             else
+               {
+                 selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
+                 selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
+               }
+           }
+         queue_free(&q);
+       }
+      else if (select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES)
+       {
+         /* don't stack src reldeps */
+         if (relflags == REL_ARCH && (relevr == ARCH_SRC || relevr == ARCH_NOSRC) && ISRELDEP(id))
+           {
+             Reldep *rd = GETRELDEP(pool, id);
+             if (rd->flags == REL_ARCH && rd->evr == ARCH_SRC)
+               id = rd->name;
+           }
+         selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
+       }
+      else
+       continue;       /* actually cannot happen */
+
+      /* now add the setflags we gained */
+      if (relflags == REL_ARCH)
+       selection->elements[i] |= SOLVER_SETARCH;
+      if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES)
+       {
+         if (pool->disttype == DISTTYPE_DEB)
+           selection->elements[i] |= SOLVER_SETEVR;    /* debian can't match version only like rpm */
+         else
+           {
+             const char *rel =  strrchr(pool_id2str(pool, relevr), '-');
+             selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
+           }
+       }
+    }
+}
+
+/* only supports simple rels plus REL_ARCH */
+/* prunes empty jobs */
+static void
+selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
+{
+  selection_filter_rel_noprune(pool, selection, relflags, relevr);
+  selection_prune(pool, selection);
+}
+
+/* limit a selection to to repository */
+/* prunes empty jobs */
+static void
+selection_filter_repo(Pool *pool, Queue *selection, Repo *repo, int setflags)
+{
+  Queue q;
+  int i, j;
+
+  if (!selection->count)
+    return;
+  if (!repo)
+    {
+      queue_empty(selection);
+      return;
+    }
+  queue_init(&q);
+  for (i = j = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      Id id = selection->elements[i + 1];
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         select = SOLVER_SOLVABLE_REPO;
+         id = repo->repoid;
+       }
+      else if (select == SOLVER_SOLVABLE_REPO)
+       {
+         if (id != repo->repoid)
+           continue;
+       }
+      else if (select == SOLVER_SOLVABLE)
+       {
+         if (pool->solvables[id].repo != repo)
+           continue;
+       }
+      else
+       {
+         int bad = 0;
+         Id p, pp;
+         queue_empty(&q);
+         FOR_JOB_SELECT(p, pp, select, id)
+           {
+             if (pool->solvables[p].repo != repo)
+               bad = 1;
+             else
+               queue_push(&q, p);
+           }
+         if (!q.count)
+           continue;
+         if (bad)
+           {
+             if (q.count == 1)
+               {
+                 select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+                 id = q.elements[0];
+               }
+             else
+               {
+                 select = SOLVER_SOLVABLE_ONE_OF;
+                 id = pool_queuetowhatprovides(pool, &q);
+               }
+           }
+       }
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Id p;
+         Solvable *s;
+         FOR_REPO_SOLVABLES(repo, p, s)
+           break;
+         if (!p)
+           continue;   /* repo is empty */
+       }
+      selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | setflags;
+      selection->elements[j++] = id;
+    }
+  queue_truncate(selection, j);
+  queue_free(&q);
+}
+
+
+static int
+matchprovides(Pool *pool, Solvable *s, Id dep)
+{
+  Id id, *idp;
+  idp = s->repo->idarraydata + s->provides;
+  while ((id = *idp++) != 0)
+    if (pool_match_dep(pool, id, dep))
+      return 1;
+  return 0;
+}
+
+/* change a SOLVER_SOLVABLE_NAME/PROVIDES selection to something that also includes
+ * extra packages.
+ * extra packages are: src, badarch, disabled
+ */
+static void
+selection_addextra(Pool *pool, Queue *selection, int flags)
+{
+  Queue q;
+  Id p, pp, dep;
+  int i, isextra, haveextra, doprovides;
+
+  if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+    flags &= ~SELECTION_WITH_SOURCE;
+
+  if (!(flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)))
+    return;    /* nothing to add */
+
+  queue_init(&q);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      if (selection->elements[i] == SOLVER_SOLVABLE_NAME)
+       doprovides = 0;
+      else if (selection->elements[i] == SOLVER_SOLVABLE_PROVIDES)
+       doprovides = 1;
+      else
+       continue;
+      dep = selection->elements[i + 1];
+      haveextra = 0;
+      queue_empty(&q);
+      if (doprovides)
+       {
+         /* first put all non-extra packages on the queue */
+         FOR_PROVIDES(p, pp, dep)
+           {
+             if ((flags & SELECTION_INSTALLED_ONLY) != 0 && pool->solvables[p].repo != pool->installed)
+               continue;
+             queue_push(&q, p);
+           }
+       }
+      FOR_POOL_SOLVABLES(p)
+       {
+         Solvable *s = pool->solvables + p;
+         if (!doprovides && !pool_match_nevr(pool, s, dep))
+           continue;
+         if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+           continue;
+         isextra = 0;
+         if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+           {
+             if (!(flags & SELECTION_WITH_SOURCE) && !(flags & SELECTION_SOURCE_ONLY))
+               continue;
+             if (!(flags & SELECTION_SOURCE_ONLY))
+               isextra = 1;
+             if (pool_disabled_solvable(pool, s))
+               {
+                 if (!(flags & SELECTION_WITH_DISABLED))
+                   continue;
+                 isextra = 1;
+               }
+           }
+         else
+           {
+             if ((flags & SELECTION_SOURCE_ONLY) != 0)
+               continue;
+             if (s->repo != pool->installed)
+               {
+                 if (pool_disabled_solvable(pool, s))
+                   {
+                     if (!(flags & SELECTION_WITH_DISABLED))
+                       continue;
+                     isextra = 1;
+                   }
+                 if (pool_badarch_solvable(pool, s))
+                   {
+                     if (!(flags & SELECTION_WITH_BADARCH))
+                       continue;
+                     isextra = 1;
+                   }
+               }
+           }
+         if (doprovides)
+           {
+             if (!isextra)
+               continue;       /* already done above in FOR_PROVIDES */
+             if (!s->provides || !matchprovides(pool, s, dep))
+               continue;
+           }
+         haveextra |= isextra;
+         queue_push(&q, p);
+       }
+      if (!haveextra || !q.count)
+       continue;
+      if (q.count == 1)
+       {
+         selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+         selection->elements[i + 1] = q.elements[0];
+       }
+      else
+       {
+         if (doprovides)
+           solv_sort(q.elements, q.count, sizeof(Id), selection_solvables_sortcmp, NULL);
+         selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
+         selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
+       }
+    }
+  queue_free(&q);
+}
+
+static inline const char *
+skipkind(const char *n)
+{
+  const char *s;
+  for (s = n; *s >= 'a' && *s <= 'z'; s++)
+    ;
+  if (*s == ':' && s != n)
+     return s + 1;
+  return n;
+}
+
+static inline void
+queue_pushunique2(Queue *q, Id id1, Id id2)
+{
+  int i;
+  for (i = 0; i < q->count; i += 2)
+    if (q->elements[i] == id1 && q->elements[i + 1] == id2)
+      return;
+  queue_push2(q, id1, id2);
+}
+
+
+/*****  provides matching  *****/
+
+static int
+selection_addextra_provides(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  Id p, id, *idp;
+  int match = 0;
+  int doglob, nocase, globflags;
+
+  if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+    return 0;  /* neither disabled nor badarch nor src */
+
+  nocase = flags & SELECTION_NOCASE;
+  doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+  globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+
+  FOR_POOL_SOLVABLES(p)
+    {
+      const char *n;
+      Solvable *s = pool->solvables + p;
+      if (!s->provides)
+       continue;
+      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)        /* no provides */
+       continue;
+      if (s->repo == pool->installed)
+       continue;
+      if (pool_disabled_solvable(pool, s))
+       {
+         if (!(flags & SELECTION_WITH_DISABLED))
+           continue;
+         if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+           continue;
+       }
+      else if (pool_badarch_solvable(pool, s))
+       {
+         if (!(flags & SELECTION_WITH_BADARCH))
+           continue;
+       }
+      else
+       continue;
+      /* here is an extra solvable we need to consider */
+      idp = s->repo->idarraydata + s->provides;
+      while ((id = *idp++) != 0)
+       {
+         while (ISRELDEP(id))
+           {
+             Reldep *rd = GETRELDEP(pool, id);
+             id = rd->name;
+           }
+         if (pool->whatprovides[id] > 1)
+           continue;   /* we already did that one in the normal code path */
+         n = pool_id2str(pool, id);
+         if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+           {
+             queue_pushunique2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+             match = 1;
+           }
+       }
+    }
+  return match;
+}
+
+/* this is the fast path of selection_provides: the id for the name
+ * is known and thus we can use the whatprovides data to quickly
+ * check the existance of a package with that provides */
+static int
+selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
+{
+  Id p, pp;
+
+  FOR_PROVIDES(p, pp, id)
+    {
+      Solvable *s = pool->solvables + p;
+      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+       continue;
+      queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+      return SELECTION_PROVIDES;
+    }
+
+  if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+    {
+      /* misuse selection_addextra to test if there is an extra package
+       * that provides the id */
+      queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+      selection_addextra(pool, selection, flags);
+      if (selection->elements[0] == SOLVER_SOLVABLE_PROVIDES)
+       queue_empty(selection);         /* no extra package found */
+      else
+       {
+          selection->elements[0] = SOLVER_SOLVABLE_PROVIDES;
+          selection->elements[1] = id;
+       }
+      return selection->count ? SELECTION_PROVIDES : 0;
+    }
+
+  return 0;
+}
+
+/* match the provides of a package */
+/* note that we only return raw SOLVER_SOLVABLE_PROVIDES jobs
+ * so that the selection can be modified later. */
+static int
+selection_provides(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  Id id, p, pp;
+  int match;
+  int doglob;
+  int nocase;
+  int globflags;
+  const char *n;
+
+  if ((flags & SELECTION_SOURCE_ONLY) != 0)
+    return 0;  /* sources do not have provides */
+
+  nocase = flags & SELECTION_NOCASE;
+  if (!nocase)
+    {
+      /* try the fast path first */
+      id = pool_str2id(pool, name, 0);
+      if (id)
+       {
+         /* the id is known, do the fast id matching */
+         int ret = selection_provides_id(pool, selection, id, flags);
+         if (ret)
+           return ret;
+       }
+    }
+
+  doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+  if (!nocase && !doglob)
+    {
+      /* all done above in selection_provides_id */
+      return 0;
+    }
+
+  /* looks like a glob or nocase match. really hard work. */
+  match = 0;
+  globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+  for (id = 1; id < pool->ss.nstrings; id++)
+    {
+      /* do we habe packages providing this id? */
+      if ((!pool->whatprovides[id] && pool->addedfileprovides == 2) || pool->whatprovides[id] == 1)
+       continue;
+      n = pool_id2str(pool, id);
+      if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+       {
+         if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+           {
+             FOR_PROVIDES(p, pp, id)
+               if (pool->solvables[p].repo == pool->installed)
+                 break;
+             if (!p)
+               continue;
+           }
+         else if (!pool->whatprovides[id])
+           {
+             FOR_PROVIDES(p, pp, id)
+               break;
+             if (!p)
+               continue;
+           }
+         queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+         match = 1;
+       }
+    }
+
+  if (flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED))
+    match |= selection_addextra_provides(pool, selection, name, flags);
+
+  return match ? SELECTION_PROVIDES : 0;
+}
+
+/*****  name matching  *****/
+
+/* this is the fast path of selection_name: the id for the name
+ * is known and thus we can quickly check the existance of a
+ * package with that name */
+static int
+selection_name_id(Pool *pool, Queue *selection, Id id, int flags)
+{
+  Id p, pp, matchid;
+
+  matchid = id;
+  if ((flags & SELECTION_SOURCE_ONLY) != 0)
+    {
+      /* sources cannot be installed */
+      if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+       return 0;
+      /* add ARCH_SRC to match only sources */
+      matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+      flags &= ~SELECTION_WITH_SOURCE;
+    }
+
+  FOR_PROVIDES(p, pp, matchid)
+    {
+      Solvable *s = pool->solvables + p;
+      if (s->name != id)
+       continue;
+      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+       continue;
+      /* one match is all we need */
+      queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+      /* add the requested extra packages */
+      if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+       selection_addextra(pool, selection, flags);
+      return SELECTION_NAME;
+    }
+
+  if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+    {
+      queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+      selection_addextra(pool, selection, flags);
+      if (selection->elements[0] == SOLVER_SOLVABLE_NAME)
+       queue_empty(selection);
+      return selection->count ? SELECTION_NAME : 0;
+    }
+
+  if ((flags & SELECTION_WITH_SOURCE) != 0 && (flags & SELECTION_INSTALLED_ONLY) == 0)
+    {
+      /* WITH_SOURCE case, but we had no match. try SOURCE_ONLY instead */
+      matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+      FOR_PROVIDES(p, pp, matchid)
+       {
+         Solvable *s = pool->solvables + p;
+         if (s->name != id)
+           continue;
+         queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+         return SELECTION_NAME;
+       }
+    }
+  return 0;
+}
+
+/* does not check SELECTION_INSTALLED_ONLY, as it is normally done
+ * by other means */
+static inline int
+solvable_matches_selection_flags(Pool *pool, Solvable *s, int flags)
+{
+  if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+    {
+      if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
+       return 0;
+      /* source package are never installed and never have a bad arch */
+      if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+       return 0;
+    }
+  else
+    {
+      if ((flags & SELECTION_SOURCE_ONLY) != 0)
+       return 0;
+      if (s->repo != pool->installed)
+       {
+         if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+           return 0;
+         if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+           return 0;
+       }
+    }
+  return 1;
+}
+
+/* match the name of a package */
+/* note that for SELECTION_INSTALLED_ONLY the result is not trimmed */
+static int
+selection_name(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  Id id, p;
+  int match;
+  int doglob, nocase;
+  int globflags;
+  const char *n;
+
+  if ((flags & SELECTION_SOURCE_ONLY) != 0)
+    flags &= ~SELECTION_WITH_SOURCE;
+
+  nocase = flags & SELECTION_NOCASE;
+  if (!nocase && !(flags & SELECTION_SKIP_KIND))
+    {
+      /* try the fast path first */
+      id = pool_str2id(pool, name, 0);
+      if (id)
+       {
+         int ret = selection_name_id(pool, selection, id, flags);
+         if (ret)
+           return ret;
+       }
+    }
+
+  doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+  if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
+    return 0;  /* all done above in selection_name_id */
+
+  /* do a name match over all packages. hard work. */
+  match = 0;
+  globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+       continue;
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
+      id = s->name;
+      n = pool_id2str(pool, id);
+      if (flags & SELECTION_SKIP_KIND)
+       n = skipkind(n);
+      if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+       {
+         if ((flags & SELECTION_SOURCE_ONLY) != 0)
+           {
+             if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+               continue;
+             id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+           }
+         queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
+         match = 1;
+       }
+    }
+  if (match)
+    {
+      /* if there was a match widen the selector to include all extra packages */
+      if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+       selection_addextra(pool, selection, flags);
+      return SELECTION_NAME;
+    }
+  return 0;
+}
+
+
+/*****  SELECTION_DOTARCH and SELECTION_REL handling *****/
+
+/* like selection_name, but check for a .arch suffix if the match did
+   not work and SELECTION_DOTARCH is used */
+static int
+selection_name_arch(Pool *pool, Queue *selection, const char *name, int flags, int doprovides, int noprune)
+{
+  int ret;
+  const char *r;
+  Id archid;
+
+  if (doprovides)
+    ret = selection_provides(pool, selection, name, flags);
+  else
+    ret = selection_name(pool, selection, name, flags);
+  if (ret)
+    return ret;
+  if (!(flags & SELECTION_DOTARCH))
+    return 0;
+  /* check if there is an .arch suffix */
+  if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
+    {
+      char *rname = solv_strdup(name);
+      rname[r - name] = 0;
+      if (archid == ARCH_SRC || archid == ARCH_NOSRC)
+       flags |= SELECTION_SOURCE_ONLY;
+      if (doprovides)
+       ret = selection_provides(pool, selection, rname, flags);
+      else
+       ret = selection_name(pool, selection, rname, flags);
+      if (ret)
+       {
+         selection_filter_rel_noprune(pool, selection, REL_ARCH, archid);
+         if (!noprune)
+           selection_prune(pool, selection);
+       }
+      solv_free(rname);
+      return ret && selection->count ? ret | SELECTION_DOTARCH : 0;
+    }
+  return 0;
+}
+
+static char *
+splitrel(char *rname, char *r, int *rflagsp)
+{
+  int nend = r - rname;
+  int rflags = 0;
+  if (nend && *r == '=' && r[-1] == '!')
+    {
+      nend--;
+      r++;
+      rflags = REL_LT|REL_GT;
+    }
+  for (; *r; r++)
+    {
+      if (*r == '<')
+       rflags |= REL_LT;
+      else if (*r == '=')
+       rflags |= REL_EQ;
+      else if (*r == '>')
+       rflags |= REL_GT;
+      else
+       break;
+    }
+  while (*r && (*r == ' ' || *r == '\t'))
+    r++;
+  while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
+    nend--;
+  if (nend <= 0 || !*r || !rflags)
+    return 0;
+  *rflagsp = rflags;
+  rname[nend] = 0;
+  return r;
+}
+
+/* match name/provides, support DOTARCH and REL modifiers
+ */
+static int
+selection_name_arch_rel(Pool *pool, Queue *selection, const char *name, int flags, int doprovides)
+{
+  int ret, rflags = 0, noprune;
+  char *r = 0, *rname = 0;
+
+  /* try to split off an relation part */
+  if ((flags & SELECTION_REL) != 0)
+    {
+      if ((r = strpbrk(name, "<=>")) != 0)
+       {
+         rname = solv_strdup(name);
+         r = rname + (r - name);
+         if ((r = splitrel(rname, r, &rflags)) == 0)
+           rname = solv_free(rname);
+       }
+    }
+
+  /* check if we need to call selection_addextra */
+  noprune = doprovides && (flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH));
+
+  if (!r)
+    {
+      /* could not split off relation */
+      ret = selection_name_arch(pool, selection, name, flags, doprovides, noprune);
+      if (ret && noprune)
+       {
+         selection_addextra(pool, selection, flags);
+         selection_prune(pool, selection);
+       }
+      return ret && selection->count ? ret : 0;
+    }
+
+  /* we could split of a relation. prune name and then filter rel */
+  ret = selection_name_arch(pool, selection, rname, flags, doprovides, noprune);
+  if (ret)
+    {
+      selection_filter_rel_noprune(pool, selection, rflags, pool_str2id(pool, r, 1));
+      if (noprune)
+        selection_addextra(pool, selection, flags);
+      selection_prune(pool, selection);
+    }
+  solv_free(rname);
+  return ret && selection->count ? ret | SELECTION_REL : 0;
+}
+
+/*****  filelist matching  *****/
+
+static int
+selection_filelist_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  const Id *a = ap, *b = bp;
+  if (a[0] != b[0])
+    return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
+  return a[1] - b[1];
+}
+
+static int
+selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  Dataiterator di;
+  Queue q;
+  Id id;
+  int type;
+  int i, j, lastid;
+
+  /* all files in the file list start with a '/' */
+  if (*name != '/')
+    {
+      if (!(flags & SELECTION_GLOB))
+       return 0;
+      if (*name != '*' && *name != '[' && *name != '?')
+       return 0;
+    }
+  type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
+  if ((flags & SELECTION_NOCASE) != 0)
+    type |= SEARCH_NOCASE;
+  queue_init(&q);
+  dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES);
+  while (dataiterator_step(&di))
+    {
+      Solvable *s = pool->solvables + di.solvid;
+      if (!s->repo)
+       continue;
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
+      if ((flags & SELECTION_FLAT) != 0)
+       {
+         /* don't bother with the complex stuff */
+          queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, di.solvid);
+         dataiterator_skip_solvable(&di);
+         continue;
+        }
+      id = pool_str2id(pool, di.kv.str, 1);
+      queue_push2(&q, id, di.solvid);
+    }
+  dataiterator_free(&di);
+  if ((flags & SELECTION_FLAT) != 0)
+    {
+      queue_free(&q);
+      return selection->count ? SELECTION_FILELIST : 0;
+    }
+  if (!q.count)
+    {
+      queue_free(&q);
+      return 0;
+    }
+  solv_sort(q.elements, q.count / 2, 2 * sizeof(Id), selection_filelist_sortcmp, pool);
+  lastid = 0;
+  queue_push2(&q, 0, 0);
+  for (i = j = 0; i < q.count; i += 2)
+    {
+      if (q.elements[i] != lastid)
+       {
+         if (j == 1)
+           queue_pushunique2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
+         else if (j > 1)
+           {
+             int k;
+             Id *idp;
+             /* check if we already have it */
+             for (k = 0; k < selection->count; k += 2)
+               {
+                 if (selection->elements[k] != SOLVER_SOLVABLE_ONE_OF)
+                   continue;
+                 idp = pool->whatprovidesdata + selection->elements[k + 1];
+                 if (!memcmp(idp, q.elements, j * sizeof(Id)) && !idp[j])
+                   break;
+               }
+             if (k == selection->count)
+               queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_ids2whatprovides(pool, q.elements, j));
+           }
+          lastid = q.elements[i];
+          j = 0;
+       }
+      if (!j || q.elements[j - 1] != q.elements[i])
+        q.elements[j++] = q.elements[i + 1];
+    }
+  queue_free(&q);
+  return SELECTION_FILELIST;
+}
+
+
+/*****  canon name matching  *****/
+
+#if defined(MULTI_SEMANTICS)
+# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
+#elif defined(DEBIAN)
+# define EVRCMP_DEPCMP EVRCMP_COMPARE
+#else
+# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
+#endif
+
+/* magic epoch promotion code, works only for SELECTION_NAME selections */
+static void
+selection_filter_evr(Pool *pool, Queue *selection, const char *evr)
+{
+  int i, j;
+  Queue q;
+  Id qbuf[10];
+  const char *sp;
+
+  /* do we already have an epoch? */
+  for (sp = evr; *sp >= '0' && *sp <= '9'; sp++)
+    ;
+  if (*sp == ':' && sp != evr)
+    {
+      /* yes, just add the rel filter */
+      selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, evr, 1));
+      return;
+    }
+
+  queue_init(&q);
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  for (i = j = 0; i < selection->count; i += 2)
+    {
+      Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      Id id = selection->elements[i + 1];
+      Id p, pp;
+      const char *lastepoch = 0;
+      int lastepochlen = 0;
+
+      queue_empty(&q);
+      FOR_JOB_SELECT(p, pp, select, id)
+       {
+         Solvable *s = pool->solvables + p;
+         const char *sevr = pool_id2str(pool, s->evr);
+         for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
+           ;
+         if (*sp != ':')
+           sp = sevr;
+         /* compare vr part */
+         if (strcmp(evr, sp != sevr ? sp + 1 : sevr) != 0)
+           {
+             int r = pool_evrcmp_str(pool, sp != sevr ? sp + 1 : sevr, evr, EVRCMP_DEPCMP);
+             if (r == -1 || r == 1)
+               continue;       /* solvable does not match vr */
+           }
+         queue_push(&q, p);
+         if (sp > sevr)
+           {
+             while (sevr < sp && *sevr == '0') /* normalize epoch */
+               sevr++;
+           }
+         if (!lastepoch)
+           {
+             lastepoch = sevr;
+             lastepochlen = sp - sevr;
+           }
+         else if (lastepochlen != sp - sevr || strncmp(lastepoch, sevr, lastepochlen) != 0)
+           lastepochlen = -1;  /* multiple different epochs */
+       }
+      if (!lastepoch || lastepochlen == 0)
+       id = pool_str2id(pool, evr, 1);         /* no match at all or zero epoch */
+      else if (lastepochlen >= 0)
+       {
+         /* found exactly one epoch, simply prepend */
+         char *evrx = solv_malloc(strlen(evr) + lastepochlen + 2);
+         strncpy(evrx, lastepoch, lastepochlen + 1);
+         strcpy(evrx + lastepochlen + 1, evr);
+         id = pool_str2id(pool, evrx, 1);
+         solv_free(evrx);
+       }
+      else
+       {
+         /* multiple epochs in multiple solvables, convert to list of solvables */
+         selection->elements[j] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
+         selection->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
+         j += 2;
+         continue;
+       }
+      queue_empty(&q);
+      queue_push2(&q, selection->elements[i], selection->elements[i + 1]);
+      selection_filter_rel(pool, &q, REL_EQ, id);
+      if (!q.count)
+        continue;              /* oops, no match */
+      selection->elements[j] = q.elements[0];
+      selection->elements[j + 1] = q.elements[1];
+      j += 2;
+    }
+  queue_truncate(selection, j);
+  queue_free(&q);
+}
+
+/* match the "canonical" name of the package */
+static int
+selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  char *rname, *r, *r2;
+  Id archid = 0;
+  int ret;
+
+  /*
+   * nameglob-version
+   * nameglob-version.arch
+   * nameglob-version-release
+   * nameglob-version-release.arch
+   */
+  flags |= SELECTION_NAME;
+  flags &= ~SELECTION_PROVIDES;
+
+  if (pool->disttype == DISTTYPE_DEB)
+    {
+      if ((r = strchr(name, '_')) == 0)
+       return 0;
+      rname = solv_strdup(name);       /* so we can modify it */
+      r = rname + (r - name);
+      *r++ = 0;
+      if ((ret = selection_name(pool, selection, rname, flags)) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+      /* is there a vaild arch? */
+      if ((r2 = strrchr(r, '_')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
+       {
+         *r2 = 0;      /* split off */
+          selection_filter_rel(pool, selection, REL_ARCH, archid);
+       }
+      selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
+      solv_free(rname);
+      return selection->count ? ret | SELECTION_CANON : 0;
+    }
+
+  if (pool->disttype == DISTTYPE_HAIKU)
+    {
+      if ((r = strchr(name, '-')) == 0)
+       return 0;
+      rname = solv_strdup(name);       /* so we can modify it */
+      r = rname + (r - name);
+      *r++ = 0;
+      if ((ret = selection_name(pool, selection, rname, flags)) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+      /* is there a vaild arch? */
+      if ((r2 = strrchr(r, '-')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
+       {
+         *r2 = 0;      /* split off */
+          selection_filter_rel(pool, selection, REL_ARCH, archid);
+       }
+      selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
+      solv_free(rname);
+      return selection->count ? ret | SELECTION_CANON : 0;
+    }
+
+  if ((r = strrchr(name, '-')) == 0)
+    return 0;
+  rname = solv_strdup(name);   /* so we can modify it */
+  r = rname + (r - name);
+  *r = 0;
+
+  /* split off potential arch part from version */
+  if ((r2 = strrchr(r + 1, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
+    *r2 = 0;   /* found valid arch, split it off */
+  if (archid == ARCH_SRC || archid == ARCH_NOSRC)
+    flags |= SELECTION_SOURCE_ONLY;
+
+  /* try with just the version */
+  if ((ret = selection_name(pool, selection, rname, flags)) == 0)
+    {
+      /* no luck, try with version-release */
+      if ((r2 = strrchr(rname, '-')) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+      *r = '-';
+      *r2 = 0;
+      r = r2;
+      if ((ret = selection_name(pool, selection, rname, flags)) == 0)
+       {
+         solv_free(rname);
+         return 0;
+       }
+    }
+  if (archid)
+    selection_filter_rel(pool, selection, REL_ARCH, archid);
+  selection_filter_evr(pool, selection, r + 1);        /* magic epoch promotion */
+  solv_free(rname);
+  return selection->count ? ret | SELECTION_CANON : 0;
+}
+
+/* return the needed withbits to match the provided selection */
+static int
+selection_extrabits(Pool *pool, Queue *selection, int flags)
+{
+  int i, needflags, isextra;
+  int allflags;
+  Id p;
+  Solvable *s;
+  Queue qlimit;
+
+  allflags = flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH);
+  if (!selection->count)
+    return allflags;
+  if (selection->count == 2 && selection->elements[0] == SOLVER_SOLVABLE_ALL)
+    return allflags;   /* don't bother */
+  queue_init(&qlimit);
+  selection_solvables(pool, selection, &qlimit);
+  needflags = 0;
+  for (i = 0; i < qlimit.count; i++)
+    {
+      p = qlimit.elements[i];
+      s = pool->solvables + p;
+      if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+       continue;
+      isextra = 0;
+      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+       {
+         if (!(flags & SELECTION_WITH_SOURCE))
+           continue;
+          isextra |= SELECTION_WITH_SOURCE;
+         if (pool_disabled_solvable(pool, s))
+           {
+             if (!(flags & SELECTION_WITH_DISABLED))
+               continue;
+             isextra |= SELECTION_WITH_DISABLED;
+           }
+       }
+      else
+       {
+         if ((flags & SELECTION_SOURCE_ONLY) != 0)
+           continue;
+         if (s->repo != pool->installed)
+           {
+             if (pool_disabled_solvable(pool, s))
+               {
+                 if (!(flags & SELECTION_WITH_DISABLED))
+                   continue;
+                 isextra |= SELECTION_WITH_DISABLED;
+               }
+             if (pool_badarch_solvable(pool, s))
+               {
+                 if (!(flags & SELECTION_WITH_BADARCH))
+                   continue;
+                 isextra |= SELECTION_WITH_BADARCH;
+               }
+           }
+       }
+      if (isextra)
+       {
+         needflags |= isextra;
+         if (needflags == allflags)
+           break;
+       }
+    }
+  queue_free(&qlimit);
+  return needflags;
+}
+
+static int
+selection_combine(Pool *pool, Queue *sel1, Queue *sel2, int flags, int ret)
+{
+  if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
+    selection_add(pool, sel1, sel2);
+  else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
+    selection_subtract(pool, sel1, sel2);
+  else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER)
+    {
+      if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
+       {
+         if ((flags & SELECTION_FILTER_SWAPPED) != 0)
+           {
+             selection_filter(pool, sel2, sel1);
+             queue_free(sel1);
+             queue_init_clone(sel1, sel2);
+           }
+         else
+           selection_filter(pool, sel1, sel2);
+       }
+    }
+  else /* SELECTION_REPLACE */
+    {
+      queue_free(sel1);
+      queue_init_clone(sel1, sel2);
+    }
+  queue_free(sel2);
+  return ret;
+}
+
+int
+selection_make(Pool *pool, Queue *selection, const char *name, int flags)
+{
+  int ret = 0;
+  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+    {
+      Queue q;
+
+      if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER)
+       {
+         if (!selection->count)
+           return 0;
+         if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0)
+           {
+             /* try to drop expensive extra bits */
+             flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags);
+           }
+       }
+      queue_init(&q);
+      ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS);
+      return selection_combine(pool, selection, &q, flags, ret);
+    }
+  queue_empty(selection);
+  if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
+    return 0;
+
+  /* here come our four selection modes */
+  if ((flags & SELECTION_FILELIST) != 0)
+    ret = selection_filelist(pool, selection, name, flags);
+  if (!ret && (flags & SELECTION_NAME) != 0)
+    ret = selection_name_arch_rel(pool, selection, name, flags, 0);
+  if (!ret && (flags & SELECTION_PROVIDES) != 0)
+    ret = selection_name_arch_rel(pool, selection, name, flags, 1);
+  if (!ret && (flags & SELECTION_CANON) != 0)
+    ret = selection_canon(pool, selection, name, flags);
+
+  /* now do result filtering */
+  if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0)
+    selection_filter_repo(pool, selection, pool->installed, SOLVER_SETREPO);
+
+  /* flatten if requested */
+  if (ret && (flags & SELECTION_FLAT) != 0)
+    selection_flatten(pool, selection);
+  return selection->count ? ret : 0;
+}
+
+static int
+matchdep_str(const char *pattern, const char *string, int flags)
+{
+  if (!pattern || !string)
+    return 0;
+  if (flags & SELECTION_GLOB)
+    {
+      int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
+      return fnmatch(pattern, string, globflags) == 0 ? 1 : 0;
+    }
+  if (flags & SELECTION_NOCASE)
+    return strcasecmp(pattern, string) == 0 ? 1 : 0;
+  return strcmp(pattern, string) == 0 ? 1 : 0;
+}
+
+/* like pool_match_dep but uses matchdep_str to match the name for glob and nocase matching */
+static int
+matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags)
+{
+  if (ISRELDEP(id))
+    {
+      Reldep *rd = GETRELDEP(pool, id);
+      if (rd->flags > 7)
+       {
+         if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS)
+           {
+             if (matchdep(pool, rd->name, rname, rflags, revr, flags))
+               return 1;
+             if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
+               {
+                 rd = GETRELDEP(pool, rd->evr);
+                 if (rd->flags != REL_ELSE)
+                   return 0;
+               }
+             if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
+               return 1;
+             return 0;
+           }
+         if (rd->flags == REL_ARCH)
+           return matchdep(pool, rd->name, rname, rflags, revr, flags);
+       }
+      if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
+       return 0;
+      if (rflags && !pool_intersect_evrs(pool, rd->flags, rd->evr, rflags, revr))
+       return 0;
+      return 1;
+    }
+  return matchdep_str(rname, pool_id2str(pool, id), flags);
+}
+
+struct limiter {
+  int start;   /* either 2 or repofilter->start */
+  int end;     /* either nsolvables or repofilter->end */
+  Repo *repofilter;
+  Id *mapper;
+  Queue qlimit;
+};
+
+
+static int
+selection_make_matchsolvable_common(Pool *pool, Queue *selection, Queue *solvidq, Id solvid, int flags, int keyname, int marker, struct limiter *limiter)
+{
+  Map m, missc;
+  int reloff;
+  int li, i, j;
+  Id p;
+  Queue q;
+
+  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+    {
+      int ret;
+      Queue q;
+      queue_init(&q);
+      ret = selection_make_matchsolvable_common(pool, &q, solvidq, solvid, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
+      return selection_combine(pool, selection, &q, flags, ret);
+    }
+
+  queue_empty(selection);
+  if (!limiter->end)
+    return 0;
+  if (!solvidq && !solvid)
+    return 0;
+  if (solvidq && solvid)
+    return 0;
+
+  if (solvidq)
+    {
+      map_init(&m, pool->nsolvables);
+      for (i = 0; i < solvidq->count; i++)
+       MAPSET(&m, solvidq->elements[i]);
+    }
+  queue_init(&q);
+  reloff = pool->ss.nstrings;
+  map_init(&missc, reloff + pool->nrels);
+  for (li = limiter->start; li < limiter->end; li++)
+    {
+      Solvable *s;
+      p = limiter->mapper ? limiter->mapper[li] : li;
+      if (solvidq && MAPTST(&m, p))
+       continue;
+      if (!solvidq && p == solvid)
+       continue;
+      s = pool->solvables + p;
+      if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+       continue;
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
+      if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff))
+        queue_push(selection, p);
+    }
+  queue_free(&q);
+  map_free(&missc);
+  if (solvidq)
+    map_free(&m);
+
+  /* convert package list to selection */
+  if (!selection->count)
+    return 0;
+  j = selection->count;
+  queue_insertn(selection, 0, selection->count, 0);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+      selection->elements[i + 1] = selection->elements[j++];
+    }
+  if ((flags & SELECTION_FLAT) != 0)
+    selection_flatten(pool, selection);
+  return SELECTION_PROVIDES;
+}
+
+static int
+selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
+{
+  int li, i, j;
+  int ret = 0;
+  char *rname = 0, *r = 0;
+  int rflags = 0;
+  Id revr = 0;
+  Id p;
+  Queue q;
+
+  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+    {
+      Queue q;
+      queue_init(&q);
+      ret = selection_make_matchdeps_common(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
+      return selection_combine(pool, selection, &q, flags, ret);
+    }
+
+  queue_empty(selection);
+  if (!limiter->end)
+    return 0;
+  if (!name && !dep)
+    return 0;
+  if (name && dep)
+    return 0;
+
+  if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+    flags &= ~SELECTION_REL;
+
+  if (name)
+    {
+      rname = solv_strdup(name);
+      if ((flags & SELECTION_REL) != 0)
+       {
+         if ((r = strpbrk(rname, "<=>")) != 0)
+           {
+             if ((r = splitrel(rname, r, &rflags)) == 0)
+               {
+                 solv_free(rname);
+                 return 0;
+               }
+           }
+         revr = pool_str2id(pool, r, 1);
+         ret |= SELECTION_REL;
+       }
+      if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
+       flags &= ~SELECTION_GLOB;
+
+      if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0)
+       {
+         /* we can use the faster selection_make_matchdepid */
+         dep = pool_str2id(pool, rname, 1);
+         if (rflags)
+           dep = pool_rel2id(pool, dep, revr, rflags, 1);
+         rname = solv_free(rname);
+         name = 0;
+       }
+    }
+  if (dep)
+    {
+      if (keyname == SOLVABLE_NAME && (flags & SELECTION_MATCH_DEPSTR) != 0)
+       {
+         Reldep *rd;
+         if (!ISRELDEP(dep))
+           return 0;
+         rd = GETRELDEP(pool, dep);
+         if (!rd->name || rd->flags != REL_EQ)
+           return 0;
+         dep = rd->name;
+         rflags = rd->flags;
+         revr = rd->evr;
+       }
+    }
+
+  queue_init(&q);
+  for (li = limiter->start; li < limiter->end; li++)
+    {
+      Solvable *s;
+      p = limiter->mapper ? limiter->mapper[li] : li;
+      s = pool->solvables + p;
+      if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+       continue;
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
+      if (keyname == SOLVABLE_NAME)                    /* nevr match hack */
+       {
+         if (dep)
+           {
+             if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+               {
+                 if (s->name != dep || s->evr != revr)
+                   continue;
+               }
+             else
+               {
+                 if (!pool_match_nevr(pool, s, dep))
+                   continue;
+               }
+           }
+         else
+           {
+             if ((flags & SELECTION_MATCH_DEPSTR) != 0)        /* mis-use */
+               {
+                 char *tmp = pool_tmpjoin(pool, pool_id2str(pool, s->name), " = ", pool_id2str(pool, s->evr));
+                 if (!matchdep_str(rname, tmp, flags))
+                   continue;
+               }
+             else
+               {
+                 if (!matchdep(pool, s->name, rname, rflags, revr, flags))
+                   continue;
+                 if (rflags && !pool_intersect_evrs(pool, rflags, revr, REL_EQ, s->evr))
+                   continue;
+               }
+           }
+         queue_push(selection, p);
+         continue;
+       }
+      if (q.count)
+        queue_empty(&q);
+      repo_lookup_deparray(s->repo, p, keyname, &q, marker);
+      if (!q.count)
+       continue;
+      if (dep)
+       {
+         if ((flags & SELECTION_MATCH_DEPSTR) != 0)    /* mis-use */
+           {
+             for (i = 0; i < q.count; i++)
+               if (q.elements[i] == dep)
+                 break;
+           }
+         else
+           {
+             for (i = 0; i < q.count; i++)
+               if (pool_match_dep(pool, q.elements[i], dep))
+                 break;
+           }
+       }
+      else
+       {
+         if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+           {
+             for (i = 0; i < q.count; i++)
+               if (matchdep_str(rname, pool_dep2str(pool, q.elements[i]), flags))
+                 break;
+           }
+         else
+           {
+             for (i = 0; i < q.count; i++)
+               if (matchdep(pool, q.elements[i], rname, rflags, revr, flags))
+                 break;
+           }
+       }
+      if (i < q.count)
+       queue_push(selection, p);
+    }
+  queue_free(&q);
+  solv_free(rname);
+
+  /* convert package list to selection */
+  if (!selection->count)
+    return 0;
+  j = selection->count;
+  queue_insertn(selection, 0, selection->count, 0);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+      selection->elements[i + 1] = selection->elements[j++];
+    }
+
+  if ((flags & SELECTION_FLAT) != 0)
+    selection_flatten(pool, selection);
+  return ret | (keyname == SOLVABLE_NAME ? SELECTION_NAME : SELECTION_PROVIDES);
+}
+
+static void
+setup_limiter(Pool *pool, Queue *selection, int flags, struct limiter *limiter)
+{
+  limiter->start = 2;
+  limiter->end = pool->nsolvables;
+  limiter->mapper = 0;
+  limiter->repofilter = 0;
+  if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+    {
+      Repo *repo = pool->installed;
+      limiter->repofilter = repo;
+      limiter->start = repo ? repo->start : 0;
+      limiter->end = repo ? repo->end : 0;
+    }
+  if ((flags & SELECTION_MODEBITS) != SELECTION_SUBTRACT && (flags & SELECTION_MODEBITS) != SELECTION_FILTER)
+    return;
+  /* the result will be limited to the first selection */
+  if (!selection->count)
+    limiter->start = limiter->end = 0;
+  if (!limiter->end)
+    return;
+  /* check for special cases where we do not need to call selection_solvables() */
+  if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+    return;
+  if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO)
+    {
+      Repo *repo = pool_id2repo(pool, selection->elements[1]);
+      if (limiter->repofilter && repo != limiter->repofilter)
+       repo = 0;
+      limiter->repofilter = repo;
+      limiter->start = repo ? repo->start : 0;
+      limiter->end = repo ? repo->end : 0;
+      return;
+    }
+  /* convert selection into a package list and use it in the limiter */
+  queue_init(&limiter->qlimit);
+  selection_solvables(pool, selection, &limiter->qlimit);
+  limiter->start = 0;
+  limiter->end = limiter->qlimit.count;
+  if (!limiter->qlimit.count)
+    queue_free(&limiter->qlimit);
+  else
+    limiter->mapper = limiter->qlimit.elements;
+}
+
+static void
+free_limiter(struct limiter *limiter)
+{
+  if (limiter->mapper)
+    queue_free(&limiter->qlimit);
+}
+
+/*
+ *  select against the dependencies in keyname
+ *  like SELECTION_PROVIDES, but with the deps in keyname instead of provides.
+ *  supported match modifiers:
+ *    SELECTION_REL
+ *    SELECTION_GLOB
+ *    SELECTION_NOCASE
+ */
+int
+selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
+{
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
+}
+
+/*
+ *  select against the dependency id in keyname
+ */
+int
+selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
+{
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
+}
+
+int
+selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker)
+{
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchsolvable_common(pool, selection, 0, solvid, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
+}
+
+int
+selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker)
+{
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchsolvable_common(pool, selection, solvidq, 0, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
+}
+
+static inline int
+pool_is_kind(Pool *pool, Id name, Id kind)
+{
+  const char *n;
+  if (!kind)
+    return 1;
+  n = pool_id2str(pool, name);
+  if (kind != 1)
+    {
+      const char *kn = pool_id2str(pool, kind);
+      int knl = strlen(kn);
+      return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
+    }
+  else
+    {
+      if (*n == ':')
+        return 1;
+      while(*n >= 'a' && *n <= 'z')
+        n++;
+      return *n == ':' ? 0 : 1;
+    }
+}
+
+static void
+selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
+{
+  int i, j, miss;
+  Queue q;
+  Id p, pp;
+
+  queue_init(&q);
+  for (i = j = 0; i < sel->count; i += 2)
+    {
+      Id select = sel->elements[i] & SOLVER_SELECTMASK;
+      Id id = sel->elements[i + 1];
+      if (q.count)
+        queue_empty(&q);
+      miss = 0;
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         FOR_POOL_SOLVABLES(p)
+           {
+             if (map_tst(m, p))
+               queue_push(&q, p);
+             else
+               miss = 1;
+           }
+       }
+      else if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, id);
+         if (repo)
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               {
+                 if (map_tst(m, p))
+                   queue_push(&q, p);
+                 else
+                   miss = 1;
+               }
+           }
+       }
+      else if (select == SOLVER_SOLVABLE)
+       {
+         if (!map_tst(m, id))
+           continue;
+         sel->elements[j] = sel->elements[i] | setflags;
+         sel->elements[j + 1] = id;
+          j += 2;
+         continue;
+       }
+      else
+       {
+         FOR_JOB_SELECT(p, pp, select, id)
+           {
+             if (map_tst(m, p))
+               queue_pushunique(&q, p);
+             else
+               miss = 1;
+           }
+       }
+      if (!q.count)
+       continue;
+      if (!miss)
+       {
+         sel->elements[j] = sel->elements[i] | setflags;
+         sel->elements[j + 1] = id;
+       }
+      else if (q.count > 1)
+       {
+         sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
+         sel->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
+       }
+      else
+       {
+         sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
+         sel->elements[j + 1] = q.elements[0];
+       }
+      j += 2;
+    }
+  queue_truncate(sel, j);
+  queue_free(&q);
+}
+
+static void
+selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
+{
+  int i, j;
+  Id p, pp, q1filled = 0;
+  Queue q1;
+  Map m2;
+  Id setflags = 0;
+
+  /* handle special cases */
+  if (!sel1->count || !sel2->count)
+    {
+      if (invert && !sel2->count)
+       return;
+      queue_empty(sel1);
+      return;
+    }
+  if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL && !invert)
+    {
+      /* XXX: not 100% correct, but very useful */
+      setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);    /* job & jobflags */
+      queue_free(sel1);
+      queue_init_clone(sel1, sel2);
+      for (i = 0; i < sel1->count; i += 2)
+        sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | setflags;
+      return;
+    }
+  if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert)
+    {
+      Repo *repo = pool_id2repo(pool, sel1->elements[1]);
+      setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_NOAUTOSET);  /* job, jobflags, setflags */
+      queue_free(sel1);
+      queue_init_clone(sel1, sel2);
+      for (i = 0; i < sel1->count; i += 2)
+        sel1->elements[i] &= SOLVER_SELECTMASK | SOLVER_SETMASK;       /* remove job and jobflags */
+      selection_filter_repo(pool, sel1, repo, setflags);
+      return;
+    }
+  if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+    {
+      if (invert)
+       queue_empty(sel1);
+      return;
+    }
+  if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert)
+    {
+      Repo *repo = pool_id2repo(pool, sel2->elements[1]);
+      setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET);
+      selection_filter_repo(pool, sel1, repo, setflags);
+      return;
+    }
+
+  /* convert sel2 into a map */
+  queue_init(&q1);
+  map_init(&m2, pool->nsolvables);
+  for (i = 0; i < sel2->count; i += 2)
+    {
+      Id select = sel2->elements[i] & SOLVER_SELECTMASK;
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         queue_free(&q1);
+         map_free(&m2);
+         if (invert)
+           queue_empty(sel1);
+         return;
+       }
+      if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, sel2->elements[i + 1]);
+         if (repo)
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               map_set(&m2, p);
+           }
+       }
+      else
+       {
+         if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(sel2->elements[i + 1]))
+           {
+             Reldep *rd = GETRELDEP(pool, sel2->elements[i + 1]);
+             if (rd->flags == REL_ARCH && rd->name == 0)
+               {
+                 /* special arch filter */
+                 if (!q1filled++)
+                   selection_solvables(pool, sel1, &q1);
+                 for (j = 0; j < q1.count; j++)
+                   {
+                     Id p = q1.elements[j];
+                     Solvable *s = pool->solvables + p;
+                     if (s->arch == rd->evr || (rd->evr == ARCH_SRC && s->arch == ARCH_NOSRC))
+                       map_set(&m2, p);
+                   }
+                 continue;
+               }
+             else if (rd->flags == REL_KIND && rd->name == 0)
+               {
+                 /* special kind filter */
+                 if (!q1filled++)
+                   selection_solvables(pool, sel1, &q1);
+                 for (j = 0; j < q1.count; j++)
+                   {
+                     Id p = q1.elements[j];
+                     Solvable *s = pool->solvables + p;
+                     if (pool_is_kind(pool, s->name, rd->evr))
+                       map_set(&m2, p);
+                   }
+                 continue;
+               }
+           }
+         FOR_JOB_SELECT(p, pp, select, sel2->elements[i + 1])
+           map_set(&m2, p);
+       }
+    }
+  queue_free(&q1);
+
+  /* now filter sel1 with the map */
+  if (invert)
+    map_invertall(&m2);
+  if (sel2->count == 2)
+    setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET);
+  selection_filter_map(pool, sel1, &m2, setflags);
+  map_free(&m2);
+}
+
+void
+selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
+{
+  selection_filter_int(pool, sel1, sel2, 0);
+}
+
+void
+selection_add(Pool *pool, Queue *sel1, Queue *sel2)
+{
+  if (sel2->count)
+    queue_insertn(sel1, sel1->count, sel2->count, sel2->elements);
+}
+
+void
+selection_subtract(Pool *pool, Queue *sel1, Queue *sel2)
+{
+  selection_filter_int(pool, sel1, sel2, 1);
+}
+
+const char *
+pool_selection2str(Pool *pool, Queue *selection, Id flagmask)
+{
+  char *s;
+  const char *s2;
+  int i;
+  s = pool_tmpjoin(pool, 0, 0, 0);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      Id how = selection->elements[i];
+      if (*s)
+       s = pool_tmpappend(pool, s, " + ", 0);
+      s2 = solver_select2str(pool, how & SOLVER_SELECTMASK, selection->elements[i + 1]);
+      s = pool_tmpappend(pool, s, s2, 0);
+      pool_freetmpspace(pool, s2);
+      how &= flagmask & SOLVER_SETMASK;
+      if (how)
+       {
+         int o = strlen(s);
+         s = pool_tmpappend(pool, s, " ", 0);
+         if (how & SOLVER_SETEV)
+           s = pool_tmpappend(pool, s, ",setev", 0);
+         if (how & SOLVER_SETEVR)
+           s = pool_tmpappend(pool, s, ",setevr", 0);
+         if (how & SOLVER_SETARCH)
+           s = pool_tmpappend(pool, s, ",setarch", 0);
+         if (how & SOLVER_SETVENDOR)
+           s = pool_tmpappend(pool, s, ",setvendor", 0);
+         if (how & SOLVER_SETREPO)
+           s = pool_tmpappend(pool, s, ",setrepo", 0);
+         if (how & SOLVER_NOAUTOSET)
+           s = pool_tmpappend(pool, s, ",noautoset", 0);
+         if (s[o + 1] != ',')
+           s = pool_tmpappend(pool, s, ",?", 0);
+         s[o + 1] = '[';
+         s = pool_tmpappend(pool, s, "]", 0);
+       }
+    }
+  return s;
+}
+
diff --git a/libsolv-0.7.2/src/selection.h b/libsolv-0.7.2/src/selection.h
new file mode 100644 (file)
index 0000000..8e60a27
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * selection.h
+ *
+ */
+
+#ifndef LIBSOLV_SELECTION_H
+#define LIBSOLV_SELECTION_H
+
+#include "pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* what to match */
+#define SELECTION_NAME                 (1 << 0)
+#define SELECTION_PROVIDES             (1 << 1)
+#define SELECTION_FILELIST             (1 << 2)
+#define SELECTION_CANON                        (1 << 3)
+
+/* match extensions */
+#define SELECTION_DOTARCH              (1 << 4)        /* allow ".arch" suffix */
+#define SELECTION_REL                  (1 << 5)        /* allow "<=> rel" suffix */
+
+/* string comparison modifiers */
+#define SELECTION_GLOB                 (1 << 9)
+#define SELECTION_NOCASE               (1 << 11)
+
+/* extra flags */
+#define SELECTION_FLAT                 (1 << 10)       /* flatten the resulting selection */
+#define SELECTION_SKIP_KIND            (1 << 14)       /* remove kind: name prefix in SELECTION_NAME matches */
+#define SELECTION_MATCH_DEPSTR         (1 << 15)       /* match dep2str result */
+
+/* package selection */
+#define SELECTION_INSTALLED_ONLY       (1 << 8)
+#define SELECTION_SOURCE_ONLY          (1 << 12)
+#define SELECTION_WITH_SOURCE          (1 << 13)
+#define SELECTION_WITH_DISABLED                (1 << 16)
+#define SELECTION_WITH_BADARCH         (1 << 17)
+#define SELECTION_WITH_ALL             (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)
+
+/* result operator */
+#define SELECTION_REPLACE              (0 << 28)
+#define SELECTION_ADD                  (1 << 28)
+#define SELECTION_SUBTRACT             (2 << 28)
+#define SELECTION_FILTER               (3 << 28)
+
+
+/* extra SELECTION_FILTER bits */
+#define SELECTION_FILTER_KEEP_IFEMPTY  (1 << 30)
+#define SELECTION_FILTER_SWAPPED       (1 << 31)
+
+/* internal */
+#define SELECTION_MODEBITS             (3 << 28)
+
+extern int  selection_make(Pool *pool, Queue *selection, const char *name, int flags);
+extern int  selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker);
+extern int  selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker);
+extern int selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker);
+extern int selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker);
+
+extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2);
+extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
+extern void selection_subtract(Pool *pool, Queue *sel1, Queue *sel2);
+
+extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs);
+
+extern const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsolv-0.7.2/src/sha1.c b/libsolv-0.7.2/src/sha1.c
new file mode 100644 (file)
index 0000000..668331f
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+       void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+       void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it.  This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 07/2002
+By Ralph Giles <giles@ghostscript.com>
+Still 100% public domain
+modified for use with stdint types, autoconf
+code cleanup, removed attribution comments
+switched SHA1Final() argument order for consistency
+use SHA1_ prefix for public api
+move public api to sha1.h
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "sha1.h"
+
+
+static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+/* FIXME: can we do this in an endian-proof way? */
+#ifdef WORDS_BIGENDIAN
+#define blk0(i) block.l[i]
+#else
+#define blk0(i) (block.l[i] = (rol(block.l[i],24)&0xFF00FF00) \
+    |(rol(block.l[i],8)&0x00FF00FF))
+#endif
+#define blk(i) (block.l[i&15] = rol(block.l[(i+13)&15]^block.l[(i+8)&15] \
+    ^block.l[(i+2)&15]^block.l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
+{
+    uint32_t a, b, c, d, e;
+    typedef union {
+        uint8_t c[64];
+        uint32_t l[16];
+    } CHAR64LONG16;
+    CHAR64LONG16 block;
+
+    memcpy(&block, buffer, 64);
+
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+void solv_SHA1_Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+void solv_SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)
+{
+    size_t i, j;
+
+#ifdef VERBOSE
+    SHAPrintContext(context, "before");
+#endif
+
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1_Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1_Transform(context->state, data + i);
+        }
+        j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+
+#ifdef VERBOSE
+    SHAPrintContext(context, "after ");
+#endif
+}
+
+
+/* Add padding and return the message digest. */
+void solv_SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])
+{
+    uint32_t i;
+    uint8_t  finalcount[8];
+
+    for (i = 0; i < 8; i++) {
+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+    solv_SHA1_Update(context, (uint8_t *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        solv_SHA1_Update(context, (uint8_t *)"\0", 1);
+    }
+    solv_SHA1_Update(context, finalcount, 8);  /* Should cause a SHA1_Transform() */
+    for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+        digest[i] = (uint8_t)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+
+    /* Wipe variables */
+    i = 0;
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, 20);
+    memset(context->count, 0, 8);
+    memset(finalcount, 0, 8);  /* SWR */
+}
diff --git a/libsolv-0.7.2/src/sha1.h b/libsolv-0.7.2/src/sha1.h
new file mode 100644 (file)
index 0000000..0423164
--- /dev/null
@@ -0,0 +1,16 @@
+/* public api for steve reid's public domain SHA-1 implementation */
+/* this file is in the public domain */
+
+#include <stdint.h>
+
+typedef struct {
+    uint32_t state[5];
+    uint32_t count[2];
+    uint8_t  buffer[64];
+} SHA1_CTX;
+
+#define SHA1_DIGEST_SIZE 20
+
+void solv_SHA1_Init(SHA1_CTX* context);
+void solv_SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);
+void solv_SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);
diff --git a/libsolv-0.7.2/src/sha2.c b/libsolv-0.7.2/src/sha2.c
new file mode 100644 (file)
index 0000000..3ca9404
--- /dev/null
@@ -0,0 +1,1022 @@
+/*
+ * FILE:       sha2.c
+ * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
+ */
+
+#include <sys/types.h>
+#include <string.h>     /* memcpy()/memset() or bcopy()/bzero() */
+/* #include <assert.h> */   /* assert() */
+#include <stdio.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "sha2.h"
+
+
+/*
+ * ASSERT NOTE:
+ * Some sanity checking code is included using assert().  On my FreeBSD
+ * system, this additional code can be removed by compiling with NDEBUG
+ * defined.  Check your own systems manpage on assert() to see how to
+ * compile WITHOUT the sanity checking code on your system.
+ *
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file).  Either define on the command line, for example:
+ *
+ *   cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ *   #define SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+ #define SHA2_UNROLL_TRANSFORM
+
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER.  If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ *   #define LITTLE_ENDIAN 1234
+ *   #define BIG_ENDIAN    4321
+ *
+ * And for little-endian machines, add:
+ *
+ *   #define BYTE_ORDER LITTLE_ENDIAN
+ *
+ * Or for big-endian machines:
+ *
+ *   #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+
+/*
+ * Define the following sha2_* types to types of the correct length on
+ * the native archtecture.   Most BSD systems and Linux define u_intXX_t
+ * types.  Machines with very recent ANSI C headers, can use the
+ * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H
+ * during compile or in the sha.h header file.
+ *
+ * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t
+ * will need to define these three typedefs below (and the appropriate
+ * ones in sha.h too) by hand according to their system architecture.
+ *
+ * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t
+ * types and pointing out recent ANSI C support for uintXX_t in inttypes.h.
+ */
+typedef uint8_t  sha2_byte;    /* Exactly 1 byte */
+typedef uint32_t sha2_word32;  /* Exactly 4 bytes */
+typedef uint64_t sha2_word64;  /* Exactly 8 bytes */
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define SHA256_SHORT_BLOCK_LENGTH      (SHA256_BLOCK_LENGTH - 8)
+#define SHA384_SHORT_BLOCK_LENGTH      (SHA384_BLOCK_LENGTH - 16)
+#define SHA512_SHORT_BLOCK_LENGTH      (SHA512_BLOCK_LENGTH - 16)
+
+
+/*** ENDIAN REVERSAL MACROS *******************************************/
+#ifndef WORDS_BIGENDIAN
+#define REVERSE32(w,x) { \
+       sha2_word32 tmp = (w); \
+       tmp = (tmp >> 16) | (tmp << 16); \
+       (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#define REVERSE64(w,x) { \
+       sha2_word64 tmp = (w); \
+       tmp = (tmp >> 32) | (tmp << 32); \
+       tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+             ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+       (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+             ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif /* !WORDS_BIGENDIAN */
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+       (w)[0] += (sha2_word64)(n); \
+       if ((w)[0] < (n)) { \
+               (w)[1]++; \
+       } \
+}
+
+/*
+ * Macros for copying blocks of memory and for zeroing out ranges
+ * of memory.  Using these macros makes it easy to switch from
+ * using memset()/memcpy() and using bzero()/bcopy().
+ *
+ * Please define either SHA2_USE_MEMSET_MEMCPY or define
+ * SHA2_USE_BZERO_BCOPY depending on which function set you
+ * choose to use:
+ */
+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
+/* Default to memset()/memcpy() if no option is specified */
+#define        SHA2_USE_MEMSET_MEMCPY  1
+#endif
+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
+/* Abort with an error if BOTH options are defined */
+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
+#endif
+
+#ifdef SHA2_USE_MEMSET_MEMCPY
+#define MEMSET_BZERO(p,l)      memset((p), 0, (l))
+#define MEMCPY_BCOPY(d,s,l)    memcpy((d), (s), (l))
+#endif
+#ifdef SHA2_USE_BZERO_BCOPY
+#define MEMSET_BZERO(p,l)      bzero((p), (l))
+#define MEMCPY_BCOPY(d,s,l)    bcopy((s), (d), (l))
+#endif
+
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and
+ *   S is a ROTATION) because the SHA-256/384/512 description document
+ *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ *   same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x)                 ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x)       (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x)       (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z)      (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z)     (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x)  (S32(2,  (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x)  (S32(6,  (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x)  (S32(7,  (x)) ^ S32(18, (x)) ^ R(3 ,   (x)))
+#define sigma1_256(x)  (S32(17, (x)) ^ S32(19, (x)) ^ R(10,   (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x)  (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x)  (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x)  (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))
+#define sigma1_512(x)  (S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+static void SHA256_Last(SHA256_CTX*);
+static void SHA512_Last(SHA512_CTX*);
+static void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
+static void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-256: */
+const static sha2_word32 K256[64] = {
+       0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+       0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+       0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+       0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+       0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+       0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+       0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+       0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+       0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+       0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+       0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+       0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+       0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+       0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+       0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+       0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-256: */
+const static sha2_word32 sha256_initial_hash_value[8] = {
+       0x6a09e667UL,
+       0xbb67ae85UL,
+       0x3c6ef372UL,
+       0xa54ff53aUL,
+       0x510e527fUL,
+       0x9b05688cUL,
+       0x1f83d9abUL,
+       0x5be0cd19UL
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+const static sha2_word64 K512[80] = {
+       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+       0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+       0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+       0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+       0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+       0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+       0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+       0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+       0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+       0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+       0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+       0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+       0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+       0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+       0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+       0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+       0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+       0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+       0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+       0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+       0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+       0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+       0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+       0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+       0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+       0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+       0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384 */
+const static sha2_word64 sha384_initial_hash_value[8] = {
+       0xcbbb9d5dc1059ed8ULL,
+       0x629a292a367cd507ULL,
+       0x9159015a3070dd17ULL,
+       0x152fecd8f70e5939ULL,
+       0x67332667ffc00b31ULL,
+       0x8eb44a8768581511ULL,
+       0xdb0c2e0d64f98fa7ULL,
+       0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512 */
+const static sha2_word64 sha512_initial_hash_value[8] = {
+       0x6a09e667f3bcc908ULL,
+       0xbb67ae8584caa73bULL,
+       0x3c6ef372fe94f82bULL,
+       0xa54ff53a5f1d36f1ULL,
+       0x510e527fade682d1ULL,
+       0x9b05688c2b3e6c1fULL,
+       0x1f83d9abfb41bd6bULL,
+       0x5be0cd19137e2179ULL
+};
+
+/* Initial hash value H for SHA-224: */
+const static sha2_word32 sha224_initial_hash_value[8] = {
+       0xc1059ed8UL,
+       0x367cd507UL,
+       0x3070dd17UL,
+       0xf70e5939UL,
+       0xffc00b31UL,
+       0x68581511UL,
+       0x64f98fa7UL,
+       0xbefa4fa4UL
+};
+
+
+/*** SHA-256: *********************************************************/
+void solv_SHA256_Init(SHA256_CTX* context) {
+       if (context == (SHA256_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
+       MEMSET_BZERO((char *)context->buffer, SHA256_BLOCK_LENGTH);
+       context->bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#ifndef WORDS_BIGENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
+       REVERSE32(*data++, W256[j]); \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+             K256[j] + W256[j]; \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+
+#else /* !WORDS_BIGENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)      \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+            K256[j] + (W256[j] = *data++); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+#endif /* !WORDS_BIGENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h)      \
+       s0 = W256[(j+1)&0x0f]; \
+       s0 = sigma0_256(s0); \
+       s1 = W256[(j+14)&0x0f]; \
+       s1 = sigma1_256(s1); \
+       T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+            (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+       j++
+
+static void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+       sha2_word32     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word32     T1, *W256;
+       int             j;
+
+       W256 = context->buffer;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+               /* Rounds 0 to 15 (unrolled): */
+               ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds to 64: */
+       do {
+               ROUND256(a,b,c,d,e,f,g,h);
+               ROUND256(h,a,b,c,d,e,f,g);
+               ROUND256(g,h,a,b,c,d,e,f);
+               ROUND256(f,g,h,a,b,c,d,e);
+               ROUND256(e,f,g,h,a,b,c,d);
+               ROUND256(d,e,f,g,h,a,b,c);
+               ROUND256(c,d,e,f,g,h,a,b);
+               ROUND256(b,c,d,e,f,g,h,a);
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+static void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+       sha2_word32     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word32     T1, T2, *W256;
+       int             j;
+
+       W256 = context->buffer;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#ifndef WORDS_BIGENDIAN
+               /* Copy data while converting to host byte order */
+               REVERSE32(*data++,W256[j]);
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* !WORDS_BIGENDIAN */
+               /* Apply the SHA-256 compression function to update a..h with copy */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* !WORDS_BIGENDIAN */
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W256[(j+1)&0x0f];
+               s0 = sigma0_256(s0);
+               s1 = W256[(j+14)&0x0f]; 
+               s1 = sigma1_256(s1);
+
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+                    (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void solv_SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
+       unsigned int    freespace, usedspace;
+
+       if (len == 0) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       /* assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); */
+
+       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA256_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, freespace);
+                       context->bitcount += freespace << 3;
+                       len -= freespace;
+                       data += freespace;
+                       SHA256_Transform(context, context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, len);
+                       context->bitcount += len << 3;
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA256_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA256_Transform(context, (sha2_word32*)data);
+               context->bitcount += SHA256_BLOCK_LENGTH << 3;
+               len -= SHA256_BLOCK_LENGTH;
+               data += SHA256_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               MEMCPY_BCOPY((char *)context->buffer, data, len);
+               context->bitcount += len << 3;
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+static void SHA256_Last(SHA256_CTX* context) {
+       unsigned int    usedspace;
+
+       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+#ifndef WORDS_BIGENDIAN
+       /* Convert FROM host byte order */
+       REVERSE64(context->bitcount,context->bitcount);
+#endif
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               ((char *)context->buffer)[usedspace++] = 0x80;
+
+               if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < SHA256_BLOCK_LENGTH) {
+                               MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA256_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       SHA256_Transform(context, context->buffer);
+
+                       /* And set-up for the last transform: */
+                       MEMSET_BZERO((char *)context->buffer, SHA256_SHORT_BLOCK_LENGTH);
+               }
+       } else {
+               /* Set-up for the last transform: */
+               MEMSET_BZERO((char *)context->buffer, SHA256_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *((char *)context->buffer) = 0x80;
+       }
+       /* Set the bit count: */
+       MEMCPY_BCOPY(&((char *)context->buffer)[SHA256_SHORT_BLOCK_LENGTH], (char *)(&context->bitcount), 8);
+
+       /* Final transform: */
+       SHA256_Transform(context, context->buffer);
+}
+
+void solv_SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
+       sha2_word32     *d = (sha2_word32*)digest;
+
+       /* Sanity check: */
+       /* assert(context != (SHA256_CTX*)0); */
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA256_Last(context);
+
+#ifndef WORDS_BIGENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE32(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Clean up state data: */
+       MEMSET_BZERO(context, sizeof(*context));
+}
+
+
+/*** SHA-512: *********************************************************/
+void solv_SHA512_Init(SHA512_CTX* context) {
+       if (context == (SHA512_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
+       MEMSET_BZERO((char *)context->buffer, SHA512_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] =  0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+#ifndef WORDS_BIGENDIAN
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
+       REVERSE64(*data++, W512[j]); \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+             K512[j] + W512[j]; \
+       (d) += T1, \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
+       j++
+
+
+#else /* !WORDS_BIGENDIAN */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)      \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
+             K512[j] + (W512[j] = *data++); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+       j++
+
+#endif /* !WORDS_BIGENDIAN */
+
+#define ROUND512(a,b,c,d,e,f,g,h)      \
+       s0 = W512[(j+1)&0x0f]; \
+       s0 = sigma0_512(s0); \
+       s1 = W512[(j+14)&0x0f]; \
+       s1 = sigma1_512(s1); \
+       T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
+             (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
+       (d) += T1; \
+       (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+       j++
+
+static void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
+       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word64     T1, *W512 = context->buffer;
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+               ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds up to 79: */
+       do {
+               ROUND512(a,b,c,d,e,f,g,h);
+               ROUND512(h,a,b,c,d,e,f,g);
+               ROUND512(g,h,a,b,c,d,e,f);
+               ROUND512(f,g,h,a,b,c,d,e);
+               ROUND512(e,f,g,h,a,b,c,d);
+               ROUND512(d,e,f,g,h,a,b,c);
+               ROUND512(c,d,e,f,g,h,a,b);
+               ROUND512(b,c,d,e,f,g,h,a);
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+static void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
+       sha2_word64     a, b, c, d, e, f, g, h, s0, s1;
+       sha2_word64     T1, T2, *W512 = context->buffer;
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = context->state[0];
+       b = context->state[1];
+       c = context->state[2];
+       d = context->state[3];
+       e = context->state[4];
+       f = context->state[5];
+       g = context->state[6];
+       h = context->state[7];
+
+       j = 0;
+       do {
+#ifndef WORDS_BIGENDIAN
+               /* Convert TO host byte order */
+               REVERSE64(*data++, W512[j]);
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+#else /* !WORDS_BIGENDIAN */
+               /* Apply the SHA-512 compression function to update a..h with copy */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
+#endif /* !WORDS_BIGENDIAN */
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W512[(j+1)&0x0f];
+               s0 = sigma0_512(s0);
+               s1 = W512[(j+14)&0x0f];
+               s1 =  sigma1_512(s1);
+
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+                    (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       context->state[0] += a;
+       context->state[1] += b;
+       context->state[2] += c;
+       context->state[3] += d;
+       context->state[4] += e;
+       context->state[5] += f;
+       context->state[6] += g;
+       context->state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void solv_SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
+       unsigned int    freespace, usedspace;
+
+       if (len == 0) {
+               /* Calling with no data is valid - we do nothing */
+               return;
+       }
+
+       /* Sanity check: */
+       /* assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); */
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA512_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, freespace);
+                       ADDINC128(context->bitcount, freespace << 3);
+                       len -= freespace;
+                       data += freespace;
+                       SHA512_Transform(context, context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       MEMCPY_BCOPY(&((char *)context->buffer)[usedspace], data, len);
+                       ADDINC128(context->bitcount, len << 3);
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA512_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA512_Transform(context, (sha2_word64*)data);
+               ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
+               len -= SHA512_BLOCK_LENGTH;
+               data += SHA512_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               MEMCPY_BCOPY((char *)context->buffer, data, len);
+               ADDINC128(context->bitcount, len << 3);
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+static void SHA512_Last(SHA512_CTX* context) {
+       unsigned int    usedspace;
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+#ifndef WORDS_BIGENDIAN
+       /* Convert FROM host byte order */
+       REVERSE64(context->bitcount[0],context->bitcount[0]);
+       REVERSE64(context->bitcount[1],context->bitcount[1]);
+#endif
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               ((char *)context->buffer)[usedspace++] = 0x80;
+
+               if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < SHA512_BLOCK_LENGTH) {
+                               MEMSET_BZERO(&((char *)context->buffer)[usedspace], SHA512_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       SHA512_Transform(context, context->buffer);
+
+                       /* And set-up for the last transform: */
+                       MEMSET_BZERO((char *)context->buffer, SHA512_BLOCK_LENGTH - 2);
+               }
+       } else {
+               /* Prepare for final transform: */
+               MEMSET_BZERO((char *)context->buffer, SHA512_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *((char *)context->buffer) = 0x80;
+       }
+       /* Store the length of input data (in bits): */
+        MEMCPY_BCOPY(&((char *)context->buffer)[SHA512_SHORT_BLOCK_LENGTH], (char *)(&context->bitcount[1]), 8);
+        MEMCPY_BCOPY(&((char *)context->buffer)[SHA512_SHORT_BLOCK_LENGTH + 8], (char *)(&context->bitcount[0]), 8);
+
+       /* Final transform: */
+       SHA512_Transform(context, context->buffer);
+}
+
+void solv_SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+       sha2_word64     *d = (sha2_word64*)digest;
+
+       /* Sanity check: */
+       /* assert(context != (SHA512_CTX*)0); */
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA512_Last(context);
+
+               /* Save the hash data for output: */
+#ifndef WORDS_BIGENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 8; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       MEMSET_BZERO(context, sizeof(*context));
+}
+
+
+/*** SHA-384: *********************************************************/
+void solv_SHA384_Init(SHA384_CTX* context) {
+       if (context == (SHA384_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
+       MEMSET_BZERO((char *)context->buffer, SHA384_BLOCK_LENGTH);
+       context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+void solv_SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
+       solv_SHA512_Update((SHA512_CTX*)context, data, len);
+}
+
+void solv_SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
+       sha2_word64     *d = (sha2_word64*)digest;
+
+       /* Sanity check: */
+       /* assert(context != (SHA384_CTX*)0); */
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA512_Last((SHA512_CTX*)context);
+
+               /* Save the hash data for output: */
+#ifndef WORDS_BIGENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 6; j++) {
+                               REVERSE64(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       MEMSET_BZERO(context, sizeof(*context));
+}
+
+
+/*** SHA-224: *********************************************************/
+
+void solv_SHA224_Init(SHA224_CTX* context) {
+       if (context == (SHA224_CTX*)0) {
+               return;
+       }
+       MEMCPY_BCOPY(context->state, sha224_initial_hash_value, SHA256_DIGEST_LENGTH);
+       MEMSET_BZERO((char *)context->buffer, SHA224_BLOCK_LENGTH);
+       context->bitcount = 0;
+}
+
+void solv_SHA224_Update(SHA224_CTX* context, const sha2_byte* data, size_t len) {
+       solv_SHA256_Update((SHA256_CTX*)context, data, len);
+}
+
+void solv_SHA224_Final(sha2_byte digest[], SHA224_CTX* context) {
+       sha2_word32     *d = (sha2_word32*)digest;
+
+       /* Sanity check: */
+       /* assert(context != (SHA224_CTX*)0); */
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != (sha2_byte*)0) {
+               SHA256_Last(context);
+
+#ifndef WORDS_BIGENDIAN
+               {
+                       /* Convert TO host byte order */
+                       int     j;
+                       for (j = 0; j < 7; j++) {
+                               REVERSE32(context->state[j],context->state[j]);
+                               *d++ = context->state[j];
+                       }
+               }
+#else
+               MEMCPY_BCOPY(d, context->state, SHA224_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Clean up state data: */
+       MEMSET_BZERO(context, sizeof(*context));
+}
diff --git a/libsolv-0.7.2/src/sha2.h b/libsolv-0.7.2/src/sha2.h
new file mode 100644 (file)
index 0000000..5377360
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * FILE:       sha2.h
+ * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
+ */
+
+#include <inttypes.h>
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+#define SHA224_BLOCK_LENGTH            64
+#define SHA224_DIGEST_LENGTH           28
+#define SHA256_BLOCK_LENGTH            64
+#define SHA256_DIGEST_LENGTH           32
+#define SHA384_BLOCK_LENGTH            128
+#define SHA384_DIGEST_LENGTH           48
+#define SHA512_BLOCK_LENGTH            128
+#define SHA512_DIGEST_LENGTH           64
+
+
+/*** SHA-256/384/512 Context Structures *******************************/
+/* NOTE: If your architecture does not define either u_intXX_t types or
+ * uintXX_t (from inttypes.h), you may need to define things by hand
+ * for your system:
+ */
+typedef struct s_SHA256_CTX {
+       uint32_t        state[8];
+       uint64_t        bitcount;
+       uint32_t        buffer[SHA256_BLOCK_LENGTH/4];
+} SHA256_CTX;
+typedef struct s_SHA512_CTX {
+       uint64_t        state[8];
+       uint64_t        bitcount[2];
+       uint64_t        buffer[SHA512_BLOCK_LENGTH/8];
+} SHA512_CTX;
+
+typedef SHA256_CTX SHA224_CTX;
+typedef SHA512_CTX SHA384_CTX;
+
+
+/*** SHA-224/256/384/512 Function Prototypes ******************************/
+void solv_SHA224_Init(SHA224_CTX *);
+void solv_SHA224_Update(SHA224_CTX*, const uint8_t*, size_t);
+void solv_SHA224_Final(uint8_t[SHA224_DIGEST_LENGTH], SHA224_CTX*);
+
+void solv_SHA256_Init(SHA256_CTX *);
+void solv_SHA256_Update(SHA256_CTX*, const uint8_t*, size_t);
+void solv_SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
+
+void solv_SHA384_Init(SHA384_CTX*);
+void solv_SHA384_Update(SHA384_CTX*, const uint8_t*, size_t);
+void solv_SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
+
+void solv_SHA512_Init(SHA512_CTX*);
+void solv_SHA512_Update(SHA512_CTX*, const uint8_t*, size_t);
+void solv_SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
diff --git a/libsolv-0.7.2/src/solvable.c b/libsolv-0.7.2/src/solvable.c
new file mode 100644 (file)
index 0000000..331f290
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solvable.c
+ *
+ * set/retrieve data from solvables
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "policy.h"
+#include "poolvendor.h"
+#include "chksum.h"
+#include "linkedpkg.h"
+
+const char *
+pool_solvable2str(Pool *pool, Solvable *s)
+{
+  const char *n, *e, *a;
+  int nl, el, al;
+  char *p;
+  n = pool_id2str(pool, s->name);
+  e = pool_id2str(pool, s->evr);
+  /* XXX: may want to skip the epoch here */
+  a = pool_id2str(pool, s->arch);
+  nl = strlen(n);
+  el = strlen(e);
+  al = strlen(a);
+  if (pool->havedistepoch)
+    {
+      /* strip the distepoch from the evr */
+      const char *de = strrchr(e, '-');
+      if (de && (de = strchr(de, ':')) != 0)
+       el = de - e;
+    }
+  p = pool_alloctmpspace(pool, nl + el + al + 3);
+  strcpy(p, n);
+  if (el)
+    {
+      p[nl++] = '-';
+      strncpy(p + nl, e, el);
+      p[nl + el] = 0;
+    }
+  if (al)
+    {
+      p[nl + el] = pool->disttype == DISTTYPE_HAIKU ? '-' : '.';
+      strcpy(p + nl + el + 1, a);
+    }
+  return p;
+}
+
+Id
+solvable_lookup_type(Solvable *s, Id keyname)
+{
+  if (!s->repo)
+    return 0;
+  return repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname);
+}
+
+Id
+solvable_lookup_id(Solvable *s, Id keyname)
+{
+  if (!s->repo)
+    return 0;
+  return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
+}
+
+int
+solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
+{
+  if (!s->repo)
+    {
+      queue_empty(q);
+      return 0;
+    }
+  return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
+}
+
+int
+solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
+{
+  if (!s->repo)
+    {
+      queue_empty(q);
+      return 0;
+    }
+  return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
+}
+
+static const char *
+solvable_lookup_str_joinarray(Solvable *s, Id keyname, const char *joinstr)
+{
+  Queue q;
+  Id qbuf[10];
+  char *str = 0;
+
+  queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
+  if (solvable_lookup_idarray(s, keyname, &q) && q.count)
+    {
+      Pool *pool = s->repo->pool;
+      int i;
+      str = pool_tmpjoin(pool, pool_id2str(pool, q.elements[0]), 0, 0);
+      for (i = 1; i < q.count; i++)
+       str = pool_tmpappend(pool, str, joinstr, pool_id2str(pool, q.elements[i]));
+    }
+  queue_free(&q);
+  return str;
+}
+
+const char *
+solvable_lookup_str(Solvable *s, Id keyname)
+{
+  const char *str;
+  if (!s->repo)
+    return 0;
+  str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
+  if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP))
+    str = solvable_lookup_str_joinarray(s, keyname, ", ");
+  return str;
+}
+
+static const char *
+solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
+{
+  Pool *pool;
+  const char *str, *basestr;
+  Id p, pp, name;
+  Solvable *s2;
+  int pass;
+
+  if (!s->repo)
+    return 0;
+  pool = s->repo->pool;
+  str = solvable_lookup_str(s, keyname);
+  if (str || keyname == basekeyname)
+    return str;
+  basestr = solvable_lookup_str(s, basekeyname);
+  if (!basestr)
+    return 0;
+  /* search for a solvable with same name and same base that has the
+   * translation */
+  if (!pool->whatprovides)
+    return usebase ? basestr : 0;
+  name = s->name;
+  /* we do this in two passes, first same vendor, then all other vendors */
+  for (pass = 0; pass < 2; pass++)
+    {
+      FOR_PROVIDES(p, pp, name)
+       {
+         s2 = pool->solvables + p;
+         if (s2->name != name)
+           continue;
+         if ((s->vendor == s2->vendor) != (pass == 0))
+           continue;
+         str = solvable_lookup_str(s2, basekeyname);
+         if (!str || strcmp(str, basestr))
+           continue;
+         str = solvable_lookup_str(s2, keyname);
+         if (str)
+           return str;
+       }
+#ifdef ENABLE_LINKED_PKGS
+      /* autopattern/product translation magic */
+      if (pass)
+       {
+         const char *n = pool_id2str(pool, name);
+         if (*n == 'p')
+           {
+             if (!strncmp("pattern:", n, 8) && (name = find_autopattern_name(pool, s)) != 0)
+               pass = -1;
+             if (!strncmp("product:", n, 8) && (name = find_autoproduct_name(pool, s)) != 0)
+               pass = -1;
+           }
+       }
+#endif
+    }
+  return usebase ? basestr : 0;
+}
+
+const char *
+solvable_lookup_str_poollang(Solvable *s, Id keyname)
+{
+  Pool *pool;
+  int i, cols;
+  const char *str;
+  Id *row;
+
+  if (!s->repo)
+    return 0;
+  pool = s->repo->pool;
+  if (!pool->nlanguages)
+    return solvable_lookup_str(s, keyname);
+  cols = pool->nlanguages + 1;
+  if (!pool->languagecache)
+    {
+      pool->languagecache = solv_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
+      pool->languagecacheother = 0;
+    }
+  if (keyname >= ID_NUM_INTERNAL)
+    {
+      row = pool->languagecache + ID_NUM_INTERNAL * cols;
+      for (i = 0; i < pool->languagecacheother; i++, row += cols)
+       if (*row == keyname)
+         break;
+      if (i >= pool->languagecacheother)
+       {
+         pool->languagecache = solv_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
+         row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
+         *row = keyname;
+       }
+    }
+  else
+    row = pool->languagecache + keyname * cols;
+  row++;       /* skip keyname */
+  for (i = 0; i < pool->nlanguages; i++, row++)
+    {
+      if (!*row)
+        *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
+      str = solvable_lookup_str_base(s, *row, keyname, 0);
+      if (str)
+       return str;
+    }
+  return solvable_lookup_str(s, keyname);
+}
+
+const char *
+solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
+{
+  if (s->repo)
+    {
+      Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
+      if (id)
+        return solvable_lookup_str_base(s, id, keyname, usebase);
+      if (!usebase)
+       return 0;
+    }
+  return solvable_lookup_str(s, keyname);
+}
+
+unsigned long long
+solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
+{
+  if (!s->repo)
+    return notfound;
+  return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
+}
+
+unsigned long long
+solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound)
+{
+  unsigned long long size;
+  if (!s->repo)
+    return notfound;
+  size = solvable_lookup_num(s, keyname, (unsigned long long)-1);
+  return size == (unsigned long long)-1 ? notfound : ((size + 1023) >> 10);
+}
+
+int
+solvable_lookup_void(Solvable *s, Id keyname)
+{
+  if (!s->repo)
+    return 0;
+  return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
+}
+
+int
+solvable_lookup_bool(Solvable *s, Id keyname)
+{
+  if (!s->repo)
+    return 0;
+  /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
+  if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
+    return 1;
+  return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
+}
+
+const unsigned char *
+solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
+{
+  Repo *repo = s->repo;
+
+  if (!repo)
+    {
+      *typep = 0;
+      return 0;
+    }
+  return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
+}
+
+const char *
+solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
+{
+  const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
+  return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
+}
+
+static inline const char *
+evrid2vrstr(Pool *pool, Id evrid)
+{
+  const char *p, *evr = pool_id2str(pool, evrid);
+  if (!evr)
+    return evr;
+  for (p = evr; *p >= '0' && *p <= '9'; p++)
+    ;
+  return p != evr && *p == ':' && p[1] ? p + 1 : evr;
+}
+
+const char *
+solvable_lookup_location(Solvable *s, unsigned int *medianrp)
+{
+  Pool *pool;
+  int l = 0;
+  char *loc;
+  const char *mediadir, *mediafile;
+
+  if (medianrp)
+    *medianrp = 0;
+  if (!s->repo)
+    return 0;
+  pool = s->repo->pool;
+  if (medianrp)
+    *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0);
+  if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
+    mediadir = pool_id2str(pool, s->arch);
+  else
+    mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
+  if (mediadir)
+    l = strlen(mediadir) + 1;
+  if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
+    {
+      const char *name, *evr, *arch;
+      name = pool_id2str(pool, s->name);
+      evr = evrid2vrstr(pool, s->evr);
+      arch = pool_id2str(pool, s->arch);
+      /* name-vr.arch.rpm */
+      loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
+      if (mediadir)
+       sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
+      else
+       sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
+    }
+  else
+    {
+      mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
+      if (!mediafile)
+       return 0;
+      loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
+      if (mediadir)
+       sprintf(loc, "%s/%s", mediadir, mediafile);
+      else
+       strcpy(loc, mediafile);
+    }
+  return loc;
+}
+
+const char *
+solvable_get_location(Solvable *s, unsigned int *medianrp)
+{
+  const char *loc = solvable_lookup_location(s, medianrp);
+  if (medianrp && *medianrp == 0)
+    *medianrp = 1;     /* compat, to be removed */
+  return loc;
+}
+
+const char *
+solvable_lookup_sourcepkg(Solvable *s)
+{
+  Pool *pool;
+  const char *evr, *name;
+  Id archid;
+
+  if (!s->repo)
+    return 0;
+  pool = s->repo->pool;
+  if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
+    name = pool_id2str(pool, s->name);
+  else
+    name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
+  if (!name)
+    return 0;
+  archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH);
+  if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
+    evr = evrid2vrstr(pool, s->evr);
+  else
+    evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
+  if (archid == ARCH_SRC || archid == ARCH_NOSRC)
+    {
+      char *str;
+      str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr);
+      str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid));
+      return pool_tmpappend(pool, str, ".rpm", 0);
+    }
+  else
+    return name;       /* FIXME */
+}
+
+
+/*****************************************************************************/
+
+/*
+ * Create maps containing the state of each solvable. Input is a "installed" queue,
+ * it contains all solvable ids that are considered to be installed.
+ *
+ * The created maps can be used for * pool_calc_duchanges() and
+ * pool_calc_installsizechange().
+ *
+ */
+void
+pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
+{
+  int i;
+  Solvable *s;
+  Id p, *dp;
+  Id *conp, con;
+
+  map_init(installedmap, pool->nsolvables);
+  if (conflictsmap)
+    map_init(conflictsmap, pool->nsolvables);
+  for (i = 0; i < installed->count; i++)
+    {
+      p = installed->elements[i];
+      if (p <= 0)      /* makes it work with decisionq */
+       continue;
+      MAPSET(installedmap, p);
+      if (!conflictsmap)
+       continue;
+      s = pool->solvables + p;
+      if (!s->conflicts)
+       continue;
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+       {
+         dp = pool_whatprovides_ptr(pool, con);
+         for (; *dp; dp++)
+           MAPSET(conflictsmap, *dp);
+       }
+    }
+}
+
+/* Tests if two solvables have identical content. Currently
+ * both solvables need to come from the same pool
+ */
+
+int
+solvable_identical(Solvable *s1, Solvable *s2)
+{
+  unsigned int bt1, bt2;
+  Id rq1, rq2;
+  Id *reqp;
+  if (s1->name != s2->name)
+    return 0;
+  if (s1->arch != s2->arch)
+    return 0;
+  if (s1->evr != s2->evr)
+    return 0;
+
+  /* check vendor, map missing vendor to empty string */
+  if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
+    {
+      /* workaround for bug 881493 */
+      if (s1->repo && !strncmp(pool_id2str(s1->repo->pool, s1->name), "product:", 8))
+       return 1;
+      return 0;
+    }
+
+  /* looking good, try some fancier stuff */
+  /* might also look up the package checksum here */
+  bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
+  bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
+  if (bt1 && bt2)
+    {
+      if (bt1 != bt2)
+        return 0;
+    }
+  else
+    {
+      if (s1->repo)
+       {
+          /* workaround for bugs 881493 and 885830*/
+         const char *n = pool_id2str(s1->repo->pool, s1->name);
+         if (!strncmp(n, "product:", 8) || !strncmp(n, "application:", 12))
+           return 1;
+       }
+      /* look at requires in a last attempt to find recompiled packages */
+      rq1 = rq2 = 0;
+      if (s1->requires)
+       for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
+         rq1 ^= *reqp;
+      if (s2->requires)
+       for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
+         rq2 ^= *reqp;
+      if (rq1 != rq2)
+        return 0;
+    }
+  return 1;
+}
+
+/* return the self provide dependency of a solvable */
+Id
+solvable_selfprovidedep(Solvable *s)
+{
+  Pool *pool;
+  Reldep *rd;
+  Id prov, *provp;
+
+  if (!s->repo)
+    return s->name;
+  pool = s->repo->pool;
+  if (s->provides)
+    {
+      provp = s->repo->idarraydata + s->provides;
+      while ((prov = *provp++) != 0)
+       {
+         if (!ISRELDEP(prov))
+           continue;
+         rd = GETRELDEP(pool, prov);
+         if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
+           return prov;
+       }
+    }
+  return pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
+}
+
+/* setter functions, simply call the repo variants */
+void
+solvable_set_id(Solvable *s, Id keyname, Id id)
+{
+  repo_set_id(s->repo, s - s->repo->pool->solvables, keyname, id);
+}
+
+void
+solvable_set_num(Solvable *s, Id keyname, unsigned long long num)
+{
+  repo_set_num(s->repo, s - s->repo->pool->solvables, keyname, num);
+}
+
+void
+solvable_set_str(Solvable *s, Id keyname, const char *str)
+{
+  repo_set_str(s->repo, s - s->repo->pool->solvables, keyname, str);
+}
+
+void
+solvable_set_poolstr(Solvable *s, Id keyname, const char *str)
+{
+  repo_set_poolstr(s->repo, s - s->repo->pool->solvables, keyname, str);
+}
+
+void
+solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str)
+{
+  repo_add_poolstr_array(s->repo, s - s->repo->pool->solvables, keyname, str);
+}
+
+void
+solvable_add_idarray(Solvable *s, Id keyname, Id id)
+{
+  repo_add_idarray(s->repo, s - s->repo->pool->solvables, keyname, id);
+}
+
+void
+solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker)
+{
+  repo_add_deparray(s->repo, s - s->repo->pool->solvables, keyname, dep, marker);
+}
+
+void
+solvable_set_idarray(Solvable *s, Id keyname, Queue *q)
+{
+  repo_set_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
+}
+
+void
+solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
+{
+  repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
+}
+
+void
+solvable_unset(Solvable *s, Id keyname)
+{
+  repo_unset(s->repo, s - s->repo->pool->solvables, keyname);
+}
+
+/* return true if a dependency intersects dep in the keyname array */
+int
+solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker)
+{
+  int i;
+  Pool *pool = s->repo->pool;
+  Queue q;
+
+  if (keyname == SOLVABLE_NAME)
+    return pool_match_nevr(pool, s, dep) ? 1 : 0;      /* nevr match hack */
+  queue_init(&q);
+  solvable_lookup_deparray(s, keyname, &q, marker);
+  for (i = 0; i < q.count; i++)
+    if (pool_match_dep(pool, q.elements[i], dep))
+      break;
+  i = i == q.count ? 0 : 1;
+  queue_free(&q);
+  return i;
+}
+
+int
+solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff)
+{
+  Pool *pool = s->repo->pool;
+  int i, boff;
+  Id *wp;
+
+  if (depq->count)
+    queue_empty(depq);
+  solvable_lookup_deparray(s, keyname, depq, marker);
+  for (i = 0; i < depq->count; i++)
+    {
+      Id dep = depq->elements[i];
+      boff = ISRELDEP(dep) ? reloff + GETRELID(dep) : dep;
+      if (MAPTST(missc, boff))
+       continue;
+      if (ISRELDEP(dep))
+       {
+         Reldep *rd = GETRELDEP(pool, dep);
+         if (!ISRELDEP(rd->name) && rd->flags < 8)
+           {
+             /* do pre-filtering on the base */
+             if (MAPTST(missc, rd->name))
+               continue;
+             wp = pool_whatprovides_ptr(pool, rd->name);
+             if (solvidmap)
+               {
+                 for (; *wp; wp++)
+                   if (MAPTST(solvidmap, *wp))
+                     break;
+               }
+             else
+               {
+                 for (; *wp; wp++)
+                   if (*wp == solvid)
+                     break;
+               }
+             if (!*wp)
+               {
+                 /* the base does not include solvid, no need to check the complete dep */
+                 MAPSET(missc, rd->name);
+                 MAPSET(missc, boff);
+                 continue;
+               }
+           }
+       }
+      wp = pool_whatprovides_ptr(pool, dep);
+      if (solvidmap)
+       {
+         for (; *wp; wp++)
+           if (MAPTST(solvidmap, *wp))
+             return 1;
+       }
+      else
+       {
+         for (; *wp; wp++)
+           if (*wp == solvid)
+             return 1;
+       }
+      MAPSET(missc, boff);
+    }
+  return 0;
+}
diff --git a/libsolv-0.7.2/src/solvable.h b/libsolv-0.7.2/src/solvable.h
new file mode 100644 (file)
index 0000000..bf92a00
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007-2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solvable.h
+ *
+ * A solvable represents an object with name-epoch:version-release.arch
+ * and dependencies
+ */
+
+#ifndef LIBSOLV_SOLVABLE_H
+#define LIBSOLV_SOLVABLE_H
+
+#include "pooltypes.h"
+#include "queue.h"
+#include "bitmap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct s_Repo;
+
+typedef struct s_Solvable {
+  Id name;
+  Id arch;
+  Id evr;                      /* epoch:version-release */
+  Id vendor;
+
+  struct s_Repo *repo;         /* repo we belong to */
+
+  /* dependencies are offsets into repo->idarraydata */
+  Offset provides;             /* terminated with Id 0 */
+  Offset obsoletes;
+  Offset conflicts;
+
+  Offset requires;
+  Offset recommends;
+  Offset suggests;
+
+  Offset supplements;
+  Offset enhances;
+
+} Solvable;
+
+/* lookup functions */
+Id solvable_lookup_type(Solvable *s, Id keyname);
+Id solvable_lookup_id(Solvable *s, Id keyname);
+unsigned long long solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound);
+unsigned long long solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound);
+const char *solvable_lookup_str(Solvable *s, Id keyname);
+const char *solvable_lookup_str_poollang(Solvable *s, Id keyname);
+const char *solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase);
+int solvable_lookup_bool(Solvable *s, Id keyname);
+int solvable_lookup_void(Solvable *s, Id keyname);
+const char *solvable_get_location(Solvable *s, unsigned int *medianrp);        /* old name */
+const char *solvable_lookup_location(Solvable *s, unsigned int *medianrp);
+const char *solvable_lookup_sourcepkg(Solvable *s);
+const unsigned char *solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep);
+const char *solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep);
+int solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q);
+int solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker);
+
+/* setter functions */
+void solvable_set_id(Solvable *s, Id keyname, Id id);
+void solvable_set_num(Solvable *s, Id keyname, unsigned long long num);
+void solvable_set_str(Solvable *s, Id keyname, const char *str);
+void solvable_set_poolstr(Solvable *s, Id keyname, const char *str);
+void solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str);
+void solvable_add_idarray(Solvable *s, Id keyname, Id id);
+void solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker);
+void solvable_set_idarray(Solvable *s, Id keyname, Queue *q);
+void solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker);
+void solvable_unset(Solvable *s, Id keyname);
+
+int solvable_identical(Solvable *s1, Solvable *s2);
+Id solvable_selfprovidedep(Solvable *s);
+
+int solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker);
+
+/* internal */
+int solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff);
+
+
+/* weird suse stuff */
+int solvable_is_irrelevant_patch(Solvable *s, Map *installedmap);
+int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap);
+int solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap);
+int solvable_trivial_installable_repo(Solvable *s, struct s_Repo *installed, Map *multiversionmap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_SOLVABLE_H */
diff --git a/libsolv-0.7.2/src/solver.c b/libsolv-0.7.2/src/solver.c
new file mode 100644 (file)
index 0000000..57fa3e4
--- /dev/null
@@ -0,0 +1,4791 @@
+/*
+ * Copyright (c) 2007-2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solver.c
+ *
+ * SAT based dependency solver
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "policy.h"
+#include "poolarch.h"
+#include "solverdebug.h"
+#include "cplxdeps.h"
+#include "linkedpkg.h"
+
+#define RULES_BLOCK 63
+
+
+/************************************************************************/
+
+/*
+ * enable/disable learnt rules
+ *
+ * we have enabled or disabled some of our rules. We now reenable all
+ * of our learnt rules except the ones that were learnt from rules that
+ * are now disabled.
+ */
+static void
+enabledisablelearntrules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  Id why, *whyp;
+  int i;
+
+  POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
+  for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
+    {
+      whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
+      while ((why = *whyp++) != 0)
+       {
+         assert(why > 0 && why < i);
+         if (solv->rules[why].d < 0)
+           break;
+       }
+      /* why != 0: we found a disabled rule, disable the learnt rule */
+      if (why && r->d >= 0)
+       {
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
+          solver_disablerule(solv, r);
+       }
+      else if (!why && r->d < 0)
+       {
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
+          solver_enablerule(solv, r);
+       }
+    }
+}
+
+
+/*
+ * make assertion rules into decisions
+ *
+ * Go through rules and add direct assertions to the decisionqueue.
+ * If we find a conflict, disable rules and add them to problem queue.
+ */
+
+static int
+makeruledecisions(Solver *solv, int disablerules)
+{
+  Pool *pool = solv->pool;
+  int i, ri, ii, ori;
+  Rule *r, *rr;
+  Id v, vv;
+  int decisionstart;
+  int record_proof = 1;
+  int oldproblemcount;
+  int havedisabled = 0;
+  int doautouninstall;
+
+  /* The system solvable is always installed first */
+  assert(solv->decisionq.count == 0);
+  queue_push(&solv->decisionq, SYSTEMSOLVABLE);
+  queue_push(&solv->decisionq_why, 0);
+  queue_push2(&solv->decisionq_reason, 0, 0);
+  solv->decisionmap[SYSTEMSOLVABLE] = 1;       /* installed at level '1' */
+
+  decisionstart = solv->decisionq.count;
+  for (;;)
+    {
+      /* if we needed to re-run, back up decisions to decisionstart */
+      while (solv->decisionq.count > decisionstart)
+       {
+         v = solv->decisionq.elements[--solv->decisionq.count];
+         --solv->decisionq_why.count;
+         vv = v > 0 ? v : -v;
+         solv->decisionmap[vv] = 0;
+       }
+
+      /* note that the ruleassertions queue is ordered */
+      for (ii = 0; ii < solv->ruleassertions.count; ii++)
+       {
+         ri = solv->ruleassertions.elements[ii];
+         r = solv->rules + ri;
+
+          if (havedisabled && ri >= solv->learntrules)
+           {
+             /* just started with learnt rule assertions. If we have disabled
+               * some rules, adapt the learnt rule status */
+             enabledisablelearntrules(solv);
+             havedisabled = 0;
+           }
+
+         if (r->d < 0 || !r->p || r->w2)       /* disabled, dummy or no assertion */
+           continue;
+
+         /* do weak rules in phase 2 */
+         if (ri < solv->learntrules && solv->weakrulemap.size && MAPTST(&solv->weakrulemap, ri))
+           continue;
+
+         v = r->p;
+         vv = v > 0 ? v : -v;
+
+         if (!solv->decisionmap[vv])          /* if not yet decided */
+           {
+             queue_push(&solv->decisionq, v);
+             queue_push(&solv->decisionq_why, ri);
+             solv->decisionmap[vv] = v > 0 ? 1 : -1;
+             IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+               {
+                 Solvable *s = solv->pool->solvables + vv;
+                 if (v < 0)
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
+                 else
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
+               }
+             continue;
+           }
+
+         /* check against previous decision: is there a conflict? */
+         if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
+           continue;
+         if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
+           continue;
+
+         /*
+          * found a conflict!
+          *
+          * The rule (r) we're currently processing says something
+          * different (v = r->p) than a previous decision (decisionmap[abs(v)])
+          * on this literal
+          */
+
+         if (ri >= solv->learntrules)
+           {
+             /* conflict with a learnt rule */
+             /* can happen when packages cannot be installed for multiple reasons. */
+             /* we disable the learnt rule in this case */
+             /* (XXX: we should really do something like analyze_unsolvable_rule here!) */
+             solver_disablerule(solv, r);
+             continue;
+           }
+
+         POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n");
+         assert(ri >= solv->pkgrules_end);     /* must not have a conflict in the pkg rules! */
+
+         /*
+          * find the decision which is the "opposite" of the rule
+          */
+         for (i = 0; i < solv->decisionq.count; i++)
+           if (solv->decisionq.elements[i] == -v)
+             break;
+         assert(i < solv->decisionq.count);         /* assert that we found it */
+         if (v == -SYSTEMSOLVABLE)
+           ori = 0;
+         else
+           {
+             ori = solv->decisionq_why.elements[i];            /* the conflicting rule */
+             assert(ori > 0);
+           }
+
+         /*
+           * record the problem
+           */
+         doautouninstall = 0;
+         oldproblemcount = solv->problems.count;
+         queue_push(&solv->problems, 0);                       /* start problem */
+         if (ori < solv->pkgrules_end)
+           {
+             /* easy: conflict with system solvable or pkg rule */
+             assert(v > 0 || v == -SYSTEMSOLVABLE);
+             IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
+               {
+                 if (ori)
+                   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
+                 else
+                   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
+                 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+                 if (ori)
+                   solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ori);
+               }
+             solver_recordproblem(solv, ri);
+             if (ri >= solv->featurerules && ri < solv->updaterules_end)
+               doautouninstall = 1;
+           }
+         else
+           {
+             POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
+             /*
+              * push all of our rules (can only be feature or job rules)
+              * asserting this literal on the problem stack
+              */
+             for (i = solv->pkgrules_end, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
+               {
+                 if (rr->d < 0                          /* disabled */
+                     || rr->w2)                         /*  or no assertion */
+                   continue;
+                 if (rr->p != vv                        /* not affecting the literal */
+                     && rr->p != -vv)
+                   continue;
+                 if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
+                   continue;
+                   
+                 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
+                 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
+                 solver_recordproblem(solv, i);
+                 if (i >= solv->featurerules && i < solv->updaterules_end)
+                   doautouninstall = 1;
+               }
+           }
+         queue_push(&solv->problems, 0);                       /* finish problem */
+
+         /* try autouninstall if requested */
+         if (doautouninstall)
+           {
+             if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
+               if (solver_autouninstall(solv, oldproblemcount) != 0)
+                 {
+                   solv->problems.count = oldproblemcount;
+                   havedisabled = 1;
+                   break;      /* start over */
+                 }
+           }
+
+         /* record the proof if requested */
+         if (record_proof)
+           {
+             solv->problems.elements[oldproblemcount] = solv->learnt_pool.count;
+             queue_push(&solv->learnt_pool, ri);
+             if (ori)
+               queue_push(&solv->learnt_pool, ori);
+             queue_push(&solv->learnt_pool, 0);
+           }
+
+         if (!disablerules)
+           {
+             POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
+             return -1;
+           }
+         /* disable all problem rules */
+         solver_disableproblemset(solv, oldproblemcount);
+         havedisabled = 1;
+         break;        /* start over */
+       }
+      if (ii < solv->ruleassertions.count)
+       continue;
+
+      /*
+       * phase 2: now do the weak assertions
+       */
+      if (!solv->weakrulemap.size)
+       break;                          /* no weak rules, no phase 2 */
+      for (ii = 0; ii < solv->ruleassertions.count; ii++)
+       {
+         ri = solv->ruleassertions.elements[ii];
+         r = solv->rules + ri;
+         if (r->d < 0 || r->w2)                         /* disabled or no assertion */
+           continue;
+         if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
+           continue;
+         v = r->p;
+         vv = v > 0 ? v : -v;
+
+         if (!solv->decisionmap[vv])          /* if not yet decided */
+           {
+             queue_push(&solv->decisionq, v);
+             queue_push(&solv->decisionq_why, r - solv->rules);
+             solv->decisionmap[vv] = v > 0 ? 1 : -1;
+             IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+               {
+                 Solvable *s = solv->pool->solvables + vv;
+                 if (v < 0)
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
+                 else
+                   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
+               }
+             continue;
+           }
+         /* check against previous decision: is there a conflict? */
+         if (v > 0 && solv->decisionmap[vv] > 0)
+           continue;
+         if (v < 0 && solv->decisionmap[vv] < 0)
+           continue;
+
+         POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
+         solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
+         solver_fixproblem(solv, ri);
+         havedisabled = 1;
+         break;        /* start over */
+       }
+      if (ii == solv->ruleassertions.count)
+       break;  /* finished! */
+    }
+  return 1;            /* the new level */
+}
+
+
+/********************************************************************/
+/* watches */
+
+
+/*-------------------------------------------------------------------
+ * makewatches
+ *
+ * initial setup for all watches
+ */
+
+static void
+makewatches(Solver *solv)
+{
+  Rule *r;
+  int i;
+  int nsolvables = solv->pool->nsolvables;
+
+  solv_free(solv->watches);
+  /* lower half for removals, upper half for installs */
+  solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
+  for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
+    {
+      if (!r->w2)              /* assertions do not need watches */
+       continue;
+
+      /* see addwatches_rule(solv, r) */
+      r->n1 = solv->watches[nsolvables + r->w1];
+      solv->watches[nsolvables + r->w1] = r - solv->rules;
+
+      r->n2 = solv->watches[nsolvables + r->w2];
+      solv->watches[nsolvables + r->w2] = r - solv->rules;
+    }
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * add watches (for a new learned rule)
+ * sets up watches for a single rule
+ *
+ * see also makewatches() above.
+ */
+
+static inline void
+addwatches_rule(Solver *solv, Rule *r)
+{
+  int nsolvables = solv->pool->nsolvables;
+
+  r->n1 = solv->watches[nsolvables + r->w1];
+  solv->watches[nsolvables + r->w1] = r - solv->rules;
+
+  r->n2 = solv->watches[nsolvables + r->w2];
+  solv->watches[nsolvables + r->w2] = r - solv->rules;
+}
+
+
+/********************************************************************/
+/*
+ * rule propagation
+ */
+
+
+/* shortcuts to check if a literal (positive or negative) assignment
+ * evaluates to 'true' or 'false'
+ */
+#define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
+#define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
+#define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
+
+/*-------------------------------------------------------------------
+ *
+ * propagate
+ *
+ * make decision and propagate to all rules
+ *
+ * Evaluate each term affected by the decision (linked through watches).
+ * If we find unit rules we make new decisions based on them.
+ *
+ * return : 0 = everything is OK
+ *          rule = conflict found in this rule
+ */
+
+static Rule *
+propagate(Solver *solv, int level)
+{
+  Pool *pool = solv->pool;
+  Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
+  Rule *r;                    /* rule */
+  Id p, pkg, other_watch;
+  Id *dp;
+  Id *decisionmap = solv->decisionmap;
+  Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
+
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
+
+  /* foreach non-propagated decision */
+  while (solv->propagate_index < solv->decisionq.count)
+    {
+      /*
+       * 'pkg' was just decided
+       * negate because our watches trigger if literal goes FALSE
+       */
+      pkg = -solv->decisionq.elements[solv->propagate_index++];
+       
+      IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+        {
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
+         solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
+        }
+
+      /* foreach rule where 'pkg' is now FALSE */
+      for (rp = watches + pkg; *rp; rp = next_rp)
+       {
+         r = solv->rules + *rp;
+         if (r->d < 0)
+           {
+             /* rule is disabled, goto next */
+             if (pkg == r->w1)
+               next_rp = &r->n1;
+             else
+               next_rp = &r->n2;
+             continue;
+           }
+
+         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+           {
+             POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
+             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
+           }
+
+         /*
+           * 'pkg' was just decided (was set to FALSE), so this rule
+          * may now be unit.
+          */
+         /* find the other watch */
+         if (pkg == r->w1)
+           {
+             other_watch = r->w2;
+             next_rp = &r->n1;
+           }
+         else
+           {
+             other_watch = r->w1;
+             next_rp = &r->n2;
+           }
+
+         /*
+          * if the other watch is true we have nothing to do
+          */
+         if (DECISIONMAP_TRUE(other_watch))
+           continue;
+
+         /*
+          * The other literal is FALSE or UNDEF
+          *
+          */
+
+          if (r->d)
+           {
+             /* Not a binary clause, try to move our watch.
+              *
+              * Go over all literals and find one that is
+              *   not other_watch
+              *   and not FALSE
+              *
+              * (TRUE is also ok, in that case the rule is fulfilled)
+              * As speed matters here we do not use the FOR_RULELITERALS
+              * macro.
+              */
+             if (r->p                                /* we have a 'p' */
+                 && r->p != other_watch              /* which is not watched */
+                 && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
+               {
+                 p = r->p;
+               }
+             else                                    /* go find a 'd' to make 'true' */
+               {
+                 /* foreach p in 'd'
+                    we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
+                  */
+                 for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
+                   {
+                     if (p != other_watch              /* which is not watched */
+                         && !DECISIONMAP_FALSE(p))     /* and not FALSE */
+                       break;
+                   }
+               }
+
+             if (p)
+               {
+                 /*
+                  * if we found some p that is UNDEF or TRUE, move
+                  * watch to it
+                  */
+                 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+                   {
+                     if (p > 0)
+                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
+                     else
+                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
+                   }
+
+                 *rp = *next_rp;
+                 next_rp = rp;
+
+                 if (pkg == r->w1)
+                   {
+                     r->w1 = p;
+                     r->n1 = watches[p];
+                   }
+                 else
+                   {
+                     r->w2 = p;
+                     r->n2 = watches[p];
+                   }
+                 watches[p] = r - solv->rules;
+                 continue;
+               }
+             /* search failed, thus all unwatched literals are FALSE */
+               
+           } /* not binary */
+
+          /*
+          * unit clause found, set literal other_watch to TRUE
+          */
+
+         if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
+           return r;                              /* eek, a conflict! */
+
+         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+           {
+             POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "  unit ");
+             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
+           }
+
+         if (other_watch > 0)
+            decisionmap[other_watch] = level;    /* install! */
+         else
+           decisionmap[-other_watch] = -level;  /* remove! */
+
+         queue_push(&solv->decisionq, other_watch);
+         queue_push(&solv->decisionq_why, r - solv->rules);
+
+         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+           {
+             if (other_watch > 0)
+               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
+             else
+               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
+           }
+
+       } /* foreach rule involving 'pkg' */
+       
+    } /* while we have non-decided decisions */
+
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
+
+  return 0;    /* all is well */
+}
+
+
+/********************************************************************/
+/* Analysis */
+
+/*-------------------------------------------------------------------
+ *
+ * revert
+ * revert decisionq to a level
+ */
+
+static void
+revert(Solver *solv, int level)
+{
+  Pool *pool = solv->pool;
+  Id v, vv;
+  while (solv->decisionq.count)
+    {
+      v = solv->decisionq.elements[solv->decisionq.count - 1];
+      vv = v > 0 ? v : -v;
+      if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
+        break;
+      POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
+      solv->decisionmap[vv] = 0;
+      solv->decisionq.count--;
+      solv->decisionq_why.count--;
+      solv->propagate_index = solv->decisionq.count;
+    }
+  while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= level)
+    solv->branches.count -= solv->branches.elements[solv->branches.count - 2];
+  if (solv->recommends_index > solv->decisionq.count)
+    solv->recommends_index = -1;       /* rebuild recommends/suggests maps */
+  solv->decisionq_reason.count = level + 1;
+}
+
+/*-------------------------------------------------------------------
+ *
+ * watch2onhighest - put watch2 on literal with highest level
+ */
+
+static inline void
+watch2onhighest(Solver *solv, Rule *r)
+{
+  int l, wl = 0;
+  Id d, v, *dp;
+
+  d = r->d < 0 ? -r->d - 1 : r->d;
+  if (!d)
+    return;    /* binary rule, both watches are set */
+  dp = solv->pool->whatprovidesdata + d;
+  while ((v = *dp++) != 0)
+    {
+      l = solv->decisionmap[v < 0 ? -v : v];
+      if (l < 0)
+       l = -l;
+      if (l > wl)
+       {
+         r->w2 = dp[-1];
+         wl = l;
+       }
+    }
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * analyze
+ *   and learn
+ */
+
+static int
+analyze(Solver *solv, int level, Rule *c, Rule **lrp)
+{
+  Pool *pool = solv->pool;
+  Queue q;
+  Rule *r;
+  Id q_buf[8];
+  int rlevel = 1;
+  Map seen;            /* global? */
+  Id p = 0, pp, v, vv, why;
+  int l, i, idx;
+  int num = 0, l1num = 0;
+  int learnt_why = solv->learnt_pool.count;
+  Id *decisionmap = solv->decisionmap;
+
+  queue_init_buffer(&q, q_buf, sizeof(q_buf)/sizeof(*q_buf));
+
+  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
+  map_init(&seen, pool->nsolvables);
+  idx = solv->decisionq.count;
+  for (;;)
+    {
+      IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
+       solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
+      queue_push(&solv->learnt_pool, c - solv->rules);
+      FOR_RULELITERALS(v, pp, c)
+       {
+         if (DECISIONMAP_TRUE(v))      /* the one true literal */
+           continue;
+         vv = v > 0 ? v : -v;
+         if (MAPTST(&seen, vv))
+           continue;
+         MAPSET(&seen, vv);            /* mark that we also need to look at this literal */
+         l = solv->decisionmap[vv];
+         if (l < 0)
+           l = -l;
+         if (l == 1)
+           l1num++;                    /* need to do this one in level1 pass */
+         else if (l == level)
+           num++;                      /* need to do this one as well */
+         else
+           {
+             queue_push(&q, v);        /* not level1 or conflict level, add to new rule */
+             if (l > rlevel)
+               rlevel = l;
+           }
+       }
+l1retry:
+      if (!num && !--l1num)
+       break;  /* all literals done */
+
+      /* find the next literal to investigate */
+      /* (as num + l1num > 0, we know that we'll always find one) */
+      for (;;)
+       {
+         assert(idx > 0);
+         v = solv->decisionq.elements[--idx];
+         vv = v > 0 ? v : -v;
+         if (MAPTST(&seen, vv))
+           break;
+       }
+      MAPCLR(&seen, vv);
+
+      if (num && --num == 0)
+       {
+         /* done with normal literals, now start level 1 literal processing */
+         p = -v;       /* so that v doesn't get lost */
+         if (!l1num)
+           break;
+         POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
+         /* clear non-l1 bits from seen map */
+         for (i = 0; i < q.count; i++)
+           {
+             v = q.elements[i];
+             MAPCLR(&seen, v > 0 ? v : -v);
+           }
+         /* only level 1 marks left in seen map */
+         l1num++;      /* as l1retry decrements it */
+         goto l1retry;
+       }
+
+      why = solv->decisionq_why.elements[idx];
+      if (why <= 0)    /* just in case, maybe for SYSTEMSOLVABLE */
+       goto l1retry;
+      c = solv->rules + why;
+    }
+  map_free(&seen);
+  assert(p != 0);
+  assert(rlevel > 0 && rlevel < level);
+  IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
+    {
+      POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
+      solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
+      for (i = 0; i < q.count; i++)
+        solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, q.elements[i]);
+    }
+  /* push end marker on learnt reasons stack */
+  queue_push(&solv->learnt_pool, 0);
+  solv->stats_learned++;
+
+  POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, rlevel);
+  level = rlevel;
+  revert(solv, level);
+  if (q.count < 2)
+    {
+      Id d = q.count ? q.elements[0] : 0;
+      queue_free(&q);
+      r = solver_addrule(solv, p, d, 0);
+    }
+  else
+    {
+      Id d = pool_queuetowhatprovides(pool, &q);
+      queue_free(&q);
+      r = solver_addrule(solv, p, 0, d);
+    }
+  assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
+  queue_push(&solv->learnt_why, learnt_why);
+  if (r->w2)
+    {
+      /* needs watches */
+      watch2onhighest(solv, r);
+      addwatches_rule(solv, r);
+    }
+  else
+    {
+      /* rule is an assertion */
+      queue_push(&solv->ruleassertions, r - solv->rules);
+    }
+  *lrp = r;
+  return level;
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * solver_reset
+ *
+ * reset all solver decisions
+ * called after rules have been enabled/disabled
+ */
+
+void
+solver_reset(Solver *solv)
+{
+  int i;
+  Id v;
+
+  /* rewind all decisions */
+  for (i = solv->decisionq.count - 1; i >= 0; i--)
+    {
+      v = solv->decisionq.elements[i];
+      solv->decisionmap[v > 0 ? v : -v] = 0;
+    }
+  queue_empty(&solv->decisionq_why);
+  queue_empty(&solv->decisionq);
+  queue_empty(&solv->decisionq_reason);
+  solv->recommends_index = -1;
+  solv->propagate_index = 0;
+  queue_empty(&solv->branches);
+
+  /* adapt learnt rule status to new set of enabled/disabled rules */
+  enabledisablelearntrules(solv);
+}
+
+static inline int
+queue_contains(Queue *q, Id id)
+{
+  int i;
+  for (i = 0; i < q->count; i++)
+    if (q->elements[i] == id)
+      return 1;
+  return 0;
+}
+
+static void
+disable_recommendsrules(Solver *solv, Queue *weakq)
+{
+  Pool *pool = solv->pool;
+  int i;
+  for (i = 0; i < weakq->count; i++)
+    {
+      Rule *r;
+      if (!queue_contains(solv->recommendsruleq, weakq->elements[i]))
+       continue;
+      r = solv->rules + weakq->elements[i];
+      if (r->d >= 0)
+       {
+         POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
+         solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
+         solver_disablerule(solv, r);
+       }
+    }
+}
+
+/*-------------------------------------------------------------------
+ *
+ * analyze_unsolvable_rule
+ *
+ * recursion helper used by analyze_unsolvable
+ */
+
+static void
+analyze_unsolvable_rule(Solver *solv, Rule *r, Queue *weakq, Map *rseen)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id why = r - solv->rules;
+
+  IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
+    solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
+  if (solv->learntrules && why >= solv->learntrules)
+    {
+      if (MAPTST(rseen, why - solv->learntrules))
+       return;
+      MAPSET(rseen, why - solv->learntrules);
+      for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
+       if (solv->learnt_pool.elements[i] > 0)
+         analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], weakq, rseen);
+      return;
+    }
+  if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why) && weakq)
+    queue_push(weakq, why);
+  /* add non-pkg rules to problem and disable */
+  if (why >= solv->pkgrules_end)
+    solver_recordproblem(solv, why);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * analyze_unsolvable (called from setpropagatelearn)
+ *
+ * We know that the problem is not solvable. Record all involved
+ * rules (i.e. the "proof") into solv->learnt_pool.
+ * Record the learnt pool index and all non-pkg rules into
+ * solv->problems. (Our solutions to fix the problems are to
+ * disable those rules.)
+ *
+ * If the proof contains at least one weak rule, we disable the
+ * last of them.
+ *
+ * Otherwise we return -1 if disablerules is not set or disable
+ * _all_ of the problem rules and return 0.
+ *
+ * return:  0 - disabled some rules, try again
+ *         -1 - hopeless
+ */
+
+static int
+analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  Map involved;                /* global to speed things up? */
+  Map rseen;
+  Queue weakq;
+  Id pp, v, vv, why;
+  int i, idx;
+  Id *decisionmap = solv->decisionmap;
+  int oldproblemcount;
+  int oldlearntpoolcount;
+  int record_proof = 1;
+
+  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
+  solv->stats_unsolvable++;
+  oldproblemcount = solv->problems.count;
+  oldlearntpoolcount = solv->learnt_pool.count;
+
+  /* make room for proof index */
+  /* must update it later, as analyze_unsolvable_rule would confuse
+   * it with a rule index if we put the real value in already */
+  queue_push(&solv->problems, 0);
+
+  r = cr;
+  map_init(&involved, pool->nsolvables);
+  map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
+  queue_init(&weakq);
+  if (record_proof)
+    queue_push(&solv->learnt_pool, r - solv->rules);
+  analyze_unsolvable_rule(solv, r, &weakq, &rseen);
+  FOR_RULELITERALS(v, pp, r)
+    {
+      if (DECISIONMAP_TRUE(v)) /* the one true literal */
+         continue;
+      vv = v > 0 ? v : -v;
+      MAPSET(&involved, vv);
+    }
+  idx = solv->decisionq.count;
+  while (idx > 0)
+    {
+      v = solv->decisionq.elements[--idx];
+      vv = v > 0 ? v : -v;
+      if (!MAPTST(&involved, vv) || vv == SYSTEMSOLVABLE)
+       continue;
+      why = solv->decisionq_why.elements[idx];
+      assert(why > 0);
+      if (record_proof)
+        queue_push(&solv->learnt_pool, why);
+      r = solv->rules + why;
+      analyze_unsolvable_rule(solv, r, &weakq, &rseen);
+      FOR_RULELITERALS(v, pp, r)
+       {
+         if (DECISIONMAP_TRUE(v))      /* the one true literal */
+             continue;
+         vv = v > 0 ? v : -v;
+         MAPSET(&involved, vv);
+       }
+    }
+  map_free(&involved);
+  map_free(&rseen);
+  queue_push(&solv->problems, 0);      /* mark end of this problem */
+
+  if (weakq.count)
+    {
+      Id lastweak;
+      /* revert problems */
+      solv->problems.count = oldproblemcount;
+      solv->learnt_pool.count = oldlearntpoolcount;
+      /* find last weak */
+      lastweak = 0;
+      for (i = 0; i < weakq.count; i++)
+       if (weakq.elements[i] > lastweak)
+         lastweak = weakq.elements[i];
+      if (lastweak < solv->pkgrules_end && solv->strongrecommends && solv->recommendsruleq && queue_contains(solv->recommendsruleq, lastweak))
+       {
+         disable_recommendsrules(solv, &weakq);
+         queue_free(&weakq);
+         solver_reset(solv);
+         return 0;
+       }
+      queue_free(&weakq);
+      POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
+      solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
+      if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
+       solver_disablechoicerules(solv, solv->rules + lastweak);
+      solver_fixproblem(solv, lastweak);
+      solver_reset(solv);
+      return 0;
+    }
+  queue_free(&weakq);
+
+  if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
+    if (solver_autouninstall(solv, oldproblemcount) != 0)
+      {
+       solv->problems.count = oldproblemcount;
+       solv->learnt_pool.count = oldlearntpoolcount;
+       solver_reset(solv);
+       return 0;
+      }
+
+  /* finish proof */
+  if (record_proof)
+    {
+      queue_push(&solv->learnt_pool, 0);
+      solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
+    }
+
+  /* + 2: index + trailing zero */
+  if (disablerules && oldproblemcount + 2 < solv->problems.count)
+    {
+      solver_disableproblemset(solv, oldproblemcount);
+      /* XXX: might want to enable all weak rules again */
+      solver_reset(solv);
+      return 0;
+    }
+  POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
+  return -1;
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * setpropagatelearn
+ *
+ * add free decision (solvable to install) to decisionq
+ * increase level and propagate decision
+ * return if no conflict.
+ *
+ * in conflict case, analyze conflict rule, add resulting
+ * rule to learnt rule set, make decision from learnt
+ * rule (always unit) and re-propagate.
+ *
+ * returns the new solver level or -1 if unsolvable
+ *
+ */
+
+static int
+setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid, Id reason)
+{
+  Pool *pool = solv->pool;
+  Rule *r, *lr;
+
+  if (decision)
+    {
+      level++;
+      if (decision > 0)
+        solv->decisionmap[decision] = level;
+      else
+        solv->decisionmap[-decision] = -level;
+      queue_push(&solv->decisionq, decision);
+      queue_push(&solv->decisionq_why, -ruleid);       /* <= 0 -> free decision */
+      queue_push(&solv->decisionq_reason, reason);
+    }
+  assert(ruleid >= 0 && level > 0);
+  for (;;)
+    {
+      r = propagate(solv, level);
+      if (!r)
+       break;
+      if (level == 1)
+       return analyze_unsolvable(solv, r, disablerules);
+      POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
+      level = analyze(solv, level, r, &lr);
+      /* the new rule is unit by design */
+      decision = lr->p;
+      solv->decisionmap[decision > 0 ? decision : -decision] = decision > 0 ? level : -level;
+      queue_push(&solv->decisionq, decision);
+      queue_push(&solv->decisionq_why, lr - solv->rules);
+      IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
+       {
+         POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
+         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, decision);
+         POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
+         solver_printrule(solv, SOLV_DEBUG_ANALYZE, lr);
+       }
+    }
+  return level;
+}
+
+static void
+reorder_dq_for_future_installed(Solver *solv, int level, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int i, j, haveone = 0, dqcount = dq->count;
+  int decisionqcount = solv->decisionq.count;
+  Id p;
+  Solvable *s;
+
+  /* at the time we process jobrules the installed packages are not kept yet */
+  /* reorder so that "future-supplemented" packages come first */
+  FOR_REPO_SOLVABLES(solv->installed, p, s)
+    {
+      if (MAPTST(&solv->noupdate, p - solv->installed->start))
+       continue;
+      if (solv->decisionmap[p] == 0)
+       {
+         if (s->recommends || s->suggests)
+           queue_push(&solv->decisionq, p);
+         solv->decisionmap[p] = level + 1;
+         haveone = 1;
+       }
+    }
+  if (!haveone)
+    return;
+  policy_update_recommendsmap(solv);
+  for (i = 0; i < dqcount; i++)
+    {
+      p = dq->elements[i];
+      if (!(pool->solvables[p].repo == solv->installed || MAPTST(&solv->suggestsmap, p) || solver_is_enhancing(solv, pool->solvables + p)))
+        {
+         queue_push(dq, p);
+         dq->elements[i] = 0;
+        }
+    }
+  dqcount = dq->count;
+  for (i = 0; i < dqcount; i++)
+    {
+      p = dq->elements[i];
+      if (p && !(pool->solvables[p].repo == solv->installed || MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
+        {
+         queue_push(dq, p);
+         dq->elements[i] = 0;
+        }
+    }
+  for (i = j = 0; i < dq->count; i++)
+    if (dq->elements[i])
+      dq->elements[j++] = dq->elements[i];
+  queue_truncate(dq, j);
+  FOR_REPO_SOLVABLES(solv->installed, p, s)
+    if (solv->decisionmap[p] == level + 1)
+      solv->decisionmap[p] = 0;
+  if (solv->decisionq.count != decisionqcount)
+    {
+      solv->recommends_index = -1;
+      queue_truncate(&solv->decisionq, decisionqcount);
+    }
+  /* but obey favored maps */
+  policy_prefer_favored(solv, dq);
+}
+
+/*-------------------------------------------------------------------
+ *
+ * branch handling
+ */
+
+static void
+createbranch(Solver *solv, int level, Queue *dq, Id p, Id data)
+{
+  Pool *pool = solv->pool;
+  int i;
+  IF_POOLDEBUG (SOLV_DEBUG_POLICY)
+    {
+      POOL_DEBUG (SOLV_DEBUG_POLICY, "creating a branch:\n");
+      for (i = 0; i < dq->count; i++)
+       POOL_DEBUG (SOLV_DEBUG_POLICY, "  - %s\n", pool_solvid2str(pool, dq->elements[i]));
+    }
+  queue_push(&solv->branches, -dq->elements[0]);
+  for (i = 1; i < dq->count; i++)
+    queue_push(&solv->branches, dq->elements[i]);
+  queue_push2(&solv->branches, p, data);
+  queue_push2(&solv->branches, dq->count + 4, level);
+}
+
+static int
+takebranch(Solver *solv, int pos, int end, const char *msg, int disablerules)
+{
+  Pool *pool = solv->pool;
+  int level;
+  Id p, why, reason;
+#if 0
+  {
+    int i;
+    printf("branch group level %d [%d-%d] %d %d:\n", solv->branches.elements[end - 1], start, end, solv->branches.elements[end - 4], solv->branches.elements[end - 3]);
+    for (i = end - solv->branches.elements[end - 2]; i < end - 4; i++)
+      printf("%c %c%s\n", i == pos ? 'x' : ' ', solv->branches.elements[i] >= 0 ? ' ' : '-', pool_solvid2str(pool, solv->branches.elements[i] >= 0 ? solv->branches.elements[i] : -solv->branches.elements[i]));
+  }
+#endif
+  level = solv->branches.elements[end - 1];
+  p = solv->branches.elements[pos];
+  solv->branches.elements[pos] = -p;
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "%s %d -> %d with %s\n", msg, solv->decisionmap[p], level, pool_solvid2str(pool, p));
+  /* hack: set level to zero so that revert does not remove the branch */
+  solv->branches.elements[end - 1] = 0;
+  revert(solv, level);
+  solv->branches.elements[end - 1] = level;
+  /* hack: revert simply sets the count, so we can still access the reverted elements */
+  why = -solv->decisionq_why.elements[solv->decisionq_why.count];
+  assert(why >= 0);
+  reason = solv->decisionq_reason.elements[level + 1];
+  return setpropagatelearn(solv, level, p, disablerules, why, reason);
+}
+
+/*-------------------------------------------------------------------
+ *
+ * select and install
+ *
+ * install best package from the queue. We add an extra package, inst, if
+ * provided. See comment in weak install section.
+ *
+ * returns the new solver level or -1 if unsolvable
+ *
+ */
+
+static int
+selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid, Id reason)
+{
+  Pool *pool = solv->pool;
+  Id p;
+
+  if (dq->count > 1)
+    policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+  /* if we're resolving rules and didn't resolve the installed packages yet,
+   * do some special supplements ordering */
+  if (dq->count > 1 && solv->do_extra_reordering)
+    reorder_dq_for_future_installed(solv, level, dq);
+  /* if we have multiple candidates we open a branch */
+  if (dq->count > 1)
+    createbranch(solv, level, dq, 0, ruleid);
+  p = dq->elements[0];
+  POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
+  return setpropagatelearn(solv, level, p, disablerules, ruleid, reason);
+}
+
+
+/********************************************************************/
+/* Main solver interface */
+
+
+/*-------------------------------------------------------------------
+ *
+ * solver_create
+ * create solver structure
+ *
+ * pool: all available solvables
+ * installed: installed Solvables
+ *
+ *
+ * Upon solving, rules are created to flag the Solvables
+ * of the 'installed' Repo as installed.
+ */
+
+Solver *
+solver_create(Pool *pool)
+{
+  Solver *solv;
+  solv = (Solver *)solv_calloc(1, sizeof(Solver));
+  solv->pool = pool;
+  solv->installed = pool->installed;
+
+  solv->allownamechange = 1;
+
+  solv->dup_allowdowngrade = 1;
+  solv->dup_allownamechange = 1;
+  solv->dup_allowarchchange = 1;
+  solv->dup_allowvendorchange = 1;
+
+  solv->keepexplicitobsoletes = pool->noobsoletesmultiversion ? 0 : 1;
+
+  queue_init(&solv->ruletojob);
+  queue_init(&solv->decisionq);
+  queue_init(&solv->decisionq_why);
+  queue_init(&solv->decisionq_reason);
+  queue_init(&solv->problems);
+  queue_init(&solv->orphaned);
+  queue_init(&solv->learnt_why);
+  queue_init(&solv->learnt_pool);
+  queue_init(&solv->branches);
+  queue_init(&solv->weakruleq);
+  queue_init(&solv->ruleassertions);
+  queue_init(&solv->addedmap_deduceq);
+
+  queue_push(&solv->learnt_pool, 0);   /* so that 0 does not describe a proof */
+
+  map_init(&solv->recommendsmap, pool->nsolvables);
+  map_init(&solv->suggestsmap, pool->nsolvables);
+  map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
+  solv->recommends_index = 0;
+
+  solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
+  solv->nrules = 1;
+  solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
+  memset(solv->rules, 0, sizeof(Rule));
+
+  return solv;
+}
+
+
+
+/*-------------------------------------------------------------------
+ *
+ * solver_free
+ */
+
+static inline void
+queuep_free(Queue **qp)
+{
+  if (!*qp)
+    return;
+  queue_free(*qp);
+  *qp = solv_free(*qp);
+}
+
+static inline void
+map_zerosize(Map *m)
+{
+  if (m->size)
+    {
+      map_free(m);
+      map_init(m, 0);
+    }
+}
+
+void
+solver_free(Solver *solv)
+{
+  queue_free(&solv->job);
+  queue_free(&solv->ruletojob);
+  queue_free(&solv->decisionq);
+  queue_free(&solv->decisionq_why);
+  queue_free(&solv->decisionq_reason);
+  queue_free(&solv->learnt_why);
+  queue_free(&solv->learnt_pool);
+  queue_free(&solv->problems);
+  queue_free(&solv->solutions);
+  queue_free(&solv->orphaned);
+  queue_free(&solv->branches);
+  queue_free(&solv->weakruleq);
+  queue_free(&solv->ruleassertions);
+  queue_free(&solv->addedmap_deduceq);
+  queuep_free(&solv->cleandeps_updatepkgs);
+  queuep_free(&solv->cleandeps_mistakes);
+  queuep_free(&solv->update_targets);
+  queuep_free(&solv->installsuppdepq);
+  queuep_free(&solv->recommendscplxq);
+  queuep_free(&solv->suggestscplxq);
+  queuep_free(&solv->brokenorphanrules);
+  queuep_free(&solv->favorq);
+  queuep_free(&solv->recommendsruleq);
+
+  map_free(&solv->recommendsmap);
+  map_free(&solv->suggestsmap);
+  map_free(&solv->noupdate);
+  map_free(&solv->weakrulemap);
+  map_free(&solv->multiversion);
+
+  map_free(&solv->updatemap);
+  map_free(&solv->bestupdatemap);
+  map_free(&solv->fixmap);
+  map_free(&solv->dupmap);
+  map_free(&solv->dupinvolvedmap);
+  map_free(&solv->droporphanedmap);
+  map_free(&solv->cleandepsmap);
+  map_free(&solv->allowuninstallmap);
+  map_free(&solv->favormap);
+  map_free(&solv->isdisfavormap);
+
+  solv_free(solv->decisionmap);
+  solv_free(solv->rules);
+  solv_free(solv->watches);
+  solv_free(solv->obsoletes);
+  solv_free(solv->obsoletes_data);
+  solv_free(solv->specialupdaters);
+  solv_free(solv->choicerules_ref);
+  solv_free(solv->bestrules_pkg);
+  solv_free(solv->yumobsrules_info);
+  solv_free(solv->instbuddy);
+  solv_free(solv);
+}
+
+int
+solver_get_flag(Solver *solv, int flag)
+{
+  switch (flag)
+  {
+  case SOLVER_FLAG_ALLOW_DOWNGRADE:
+    return solv->allowdowngrade;
+  case SOLVER_FLAG_ALLOW_NAMECHANGE:
+    return solv->allownamechange;
+  case SOLVER_FLAG_ALLOW_ARCHCHANGE:
+    return solv->allowarchchange;
+  case SOLVER_FLAG_ALLOW_VENDORCHANGE:
+    return solv->allowvendorchange;
+  case SOLVER_FLAG_ALLOW_UNINSTALL:
+    return solv->allowuninstall;
+  case SOLVER_FLAG_NO_UPDATEPROVIDE:
+    return solv->noupdateprovide;
+  case SOLVER_FLAG_SPLITPROVIDES:
+    return solv->dosplitprovides;
+  case SOLVER_FLAG_IGNORE_RECOMMENDED:
+    return solv->dontinstallrecommended;
+  case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
+    return solv->addalreadyrecommended;
+  case SOLVER_FLAG_NO_INFARCHCHECK:
+    return solv->noinfarchcheck;
+  case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
+    return solv->keepexplicitobsoletes;
+  case SOLVER_FLAG_BEST_OBEY_POLICY:
+    return solv->bestobeypolicy;
+  case SOLVER_FLAG_NO_AUTOTARGET:
+    return solv->noautotarget;
+  case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
+    return solv->dup_allowdowngrade;
+  case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
+    return solv->dup_allownamechange;
+  case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
+    return solv->dup_allowarchchange;
+  case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
+    return solv->dup_allowvendorchange;
+  case SOLVER_FLAG_KEEP_ORPHANS:
+    return solv->keep_orphans;
+  case SOLVER_FLAG_BREAK_ORPHANS:
+    return solv->break_orphans;
+  case SOLVER_FLAG_FOCUS_INSTALLED:
+    return solv->focus_installed;
+  case SOLVER_FLAG_FOCUS_BEST:
+    return solv->focus_best;
+  case SOLVER_FLAG_YUM_OBSOLETES:
+    return solv->do_yum_obsoletes;
+  case SOLVER_FLAG_NEED_UPDATEPROVIDE:
+    return solv->needupdateprovide;
+  case SOLVER_FLAG_URPM_REORDER:
+    return solv->urpmreorder;
+  case SOLVER_FLAG_STRONG_RECOMMENDS:
+    return solv->strongrecommends;
+  case SOLVER_FLAG_INSTALL_ALSO_UPDATES:
+    return solv->install_also_updates;
+  case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
+    return solv->only_namespace_recommended;
+  default:
+    break;
+  }
+  return -1;
+}
+
+int
+solver_set_flag(Solver *solv, int flag, int value)
+{
+  int old = solver_get_flag(solv, flag);
+  switch (flag)
+  {
+  case SOLVER_FLAG_ALLOW_DOWNGRADE:
+    solv->allowdowngrade = value;
+    break;
+  case SOLVER_FLAG_ALLOW_NAMECHANGE:
+    solv->allownamechange = value;
+    break;
+  case SOLVER_FLAG_ALLOW_ARCHCHANGE:
+    solv->allowarchchange = value;
+    break;
+  case SOLVER_FLAG_ALLOW_VENDORCHANGE:
+    solv->allowvendorchange = value;
+    break;
+  case SOLVER_FLAG_ALLOW_UNINSTALL:
+    solv->allowuninstall = value;
+    break;
+  case SOLVER_FLAG_NO_UPDATEPROVIDE:
+    solv->noupdateprovide = value;
+    break;
+  case SOLVER_FLAG_SPLITPROVIDES:
+    solv->dosplitprovides = value;
+    break;
+  case SOLVER_FLAG_IGNORE_RECOMMENDED:
+    solv->dontinstallrecommended = value;
+    break;
+  case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
+    solv->addalreadyrecommended = value;
+    break;
+  case SOLVER_FLAG_NO_INFARCHCHECK:
+    solv->noinfarchcheck = value;
+    break;
+  case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
+    solv->keepexplicitobsoletes = value;
+    break;
+  case SOLVER_FLAG_BEST_OBEY_POLICY:
+    solv->bestobeypolicy = value;
+    break;
+  case SOLVER_FLAG_NO_AUTOTARGET:
+    solv->noautotarget = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
+    solv->dup_allowdowngrade = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
+    solv->dup_allownamechange = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
+    solv->dup_allowarchchange = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
+    solv->dup_allowvendorchange = value;
+    break;
+  case SOLVER_FLAG_KEEP_ORPHANS:
+    solv->keep_orphans = value;
+    break;
+  case SOLVER_FLAG_BREAK_ORPHANS:
+    solv->break_orphans = value;
+    break;
+  case SOLVER_FLAG_FOCUS_INSTALLED:
+    solv->focus_installed = value;
+    break;
+  case SOLVER_FLAG_FOCUS_BEST:
+    solv->focus_best = value;
+    break;
+  case SOLVER_FLAG_YUM_OBSOLETES:
+    solv->do_yum_obsoletes = value;
+    break;
+  case SOLVER_FLAG_NEED_UPDATEPROVIDE:
+    solv->needupdateprovide = value;
+    break;
+  case SOLVER_FLAG_URPM_REORDER:
+    solv->urpmreorder = value;
+    break;
+  case SOLVER_FLAG_STRONG_RECOMMENDS:
+    solv->strongrecommends = value;
+    break;
+  case SOLVER_FLAG_INSTALL_ALSO_UPDATES:
+    solv->install_also_updates = value;
+    break;
+  case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
+    solv->only_namespace_recommended = value;
+    break;
+  default:
+    break;
+  }
+  return old;
+}
+
+static int
+resolve_jobrules(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int oldlevel = level;
+  int i, olevel;
+  Rule *r;
+
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
+  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
+    {
+      Id l, pp;
+      if (r->d < 0)            /* ignore disabled rules */
+       continue;
+      queue_empty(dq);
+      FOR_RULELITERALS(l, pp, r)
+       {
+         if (l < 0)
+           {
+             if (solv->decisionmap[-l] <= 0)
+               break;
+           }
+         else
+           {
+             if (solv->decisionmap[l] > 0)
+               break;
+             if (solv->decisionmap[l] == 0)
+               queue_push(dq, l);
+           }
+       }
+      if (l || !dq->count)
+       continue;
+      /* prune to installed if not updating */
+      if (dq->count > 1 && solv->installed && !solv->updatemap_all &&
+         !solv->install_also_updates &&
+         !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
+       {
+         int j = dq->count, k;
+         if (solv->updatemap.size)
+           {
+             /* do not prune if an installed package wants to be updated */
+             for (j = 0; j < dq->count; j++)
+               if (pool->solvables[dq->elements[j]].repo == solv->installed
+                   && MAPTST(&solv->updatemap, dq->elements[j] - solv->installed->start))
+                 break;
+           }
+         if (j == dq->count)
+           {
+             for (j = k = 0; j < dq->count; j++)
+               if (pool->solvables[dq->elements[j]].repo == solv->installed)
+                 dq->elements[k++] = dq->elements[j];
+             if (k)
+               dq->count = k;
+           }
+       }
+      olevel = level;
+      level = selectandinstall(solv, level, dq, disablerules, i, SOLVER_REASON_RESOLVE_JOB);
+      if (level <= olevel)
+       {
+         if (level == olevel)
+           {
+             i--;
+             r--;
+             continue; /* try something else */
+           }
+         if (level < oldlevel)
+           return level;
+         /* redo from start of jobrules */
+         i = solv->jobrules - 1;
+         r = solv->rules + i;
+       }
+    }
+  return level;
+}
+
+static void
+prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
+{
+  int i, j;
+  Id p, *cp2;
+  for (i = j = 0; i < q->count; i++)
+    {
+      p = q->elements[i];
+      for (cp2 = cp; *cp2; cp2++)
+       if (*cp2 == p)
+         {
+           q->elements[j++] = p;
+           break;
+         }
+    }
+  queue_truncate(q, j);
+}
+
+static int
+resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int i, n, pass;
+  int installedpos = solv->installedpos;
+  Solvable *s;
+  Id p, pp;
+  int olevel, origlevel = level;
+
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
+  if (!installedpos)
+    installedpos = installed->start;
+  /* we use two passes if we need to update packages
+   * to create a better user experience */
+  for (pass = solv->updatemap.size ? 0 : 1; pass < 2; )
+    {
+      int passlevel = level;
+      Id *specialupdaters = solv->specialupdaters;
+      /* start with installedpos, the position that gave us problems the last time */
+      for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
+       {
+         Rule *r, *rr;
+         Id d;
+
+         if (i == installed->end)
+           i = installed->start;
+         s = pool->solvables + i;
+         if (s->repo != installed)
+           continue;
+
+         if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start]))
+           continue;           /* already decided */
+         if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
+           continue;           /* updates first */
+         r = solv->rules + solv->updaterules + (i - installed->start);
+         rr = r;
+         if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
+           rr -= solv->installed->end - solv->installed->start;
+         if (!rr->p)           /* identical to update rule? */
+           rr = r;
+         if (!rr->p)
+           continue;           /* orpaned package or pseudo package */
+
+         /* check if we should update this package to the latest version
+          * noupdate is set for erase jobs, in that case we want to deinstall
+          * the installed package and not replace it with a newer version
+          * rr->p != i is for dup jobs where the installed package cannot be kept */
+         if (dq->count)
+           queue_empty(dq);
+         if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i)))
+           {
+             if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
+               {
+                 /* special multiversion handling, make sure best version is chosen */
+                 if (rr->p == i && solv->decisionmap[i] >= 0)
+                   queue_push(dq, i);
+                 while ((p = pool->whatprovidesdata[d++]) != 0)
+                   if (solv->decisionmap[p] >= 0)
+                     queue_push(dq, p);
+                 if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start])
+                   prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq);
+                 if (dq->count)
+                   {
+                     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+                     p = dq->elements[0];
+                     if (p != i && solv->decisionmap[p] == 0)
+                       {
+                         rr = solv->rules + solv->featurerules + (i - solv->installed->start);
+                         if (!rr->p)           /* update rule == feature rule? */
+                           rr = rr - solv->featurerules + solv->updaterules;
+                         dq->count = 1;
+                       }
+                     else
+                       dq->count = 0;
+                   }
+               }
+             else
+               {
+                 /* update to best package of the update rule */
+                 FOR_RULELITERALS(p, pp, rr)
+                   {
+                     if (solv->decisionmap[p] > 0)
+                       {
+                         dq->count = 0;                /* already fulfilled */
+                         break;
+                       }
+                     if (!solv->decisionmap[p])
+                       queue_push(dq, p);
+                   }
+               }
+           }
+         if (dq->count && solv->update_targets && solv->update_targets->elements[i - installed->start])
+           prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], dq);
+         /* install best version */
+         if (dq->count)
+           {
+             olevel = level;
+             level = selectandinstall(solv, level, dq, disablerules, rr - solv->rules, SOLVER_REASON_UPDATE_INSTALLED);
+             if (level <= olevel)
+               {
+                 if (level < passlevel)
+                   break;      /* trouble */
+                 if (level < olevel)
+                   n = installed->start;       /* redo all */
+                 i--;
+                 n--;
+                 continue;
+               }
+           }
+         /* if still undecided keep package */
+         if (solv->decisionmap[i] == 0)
+           {
+             olevel = level;
+             if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
+               {
+#if 0
+                 POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
+                 level = setpropagatelearn(solv, level, -i, disablerules, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+#else
+                 continue;
+#endif
+               }
+             else
+               {
+                 POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
+                 level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules, SOLVER_REASON_KEEP_INSTALLED);
+               }
+             if (level <= olevel)
+               {
+                 if (level < passlevel)
+                   break;      /* trouble */
+                 if (level < olevel)
+                   n = installed->start;       /* redo all */
+                 i--;
+                 n--;
+                 continue;     /* retry with learnt rule */
+               }
+           }
+       }
+      if (n < installed->end)
+       {
+         installedpos = i;     /* retry problem solvable next time */
+         if (level < origlevel)
+           break;              /* ran into trouble */
+         /* re-run all passes */
+          pass = solv->updatemap.size ? 0 : 1;
+         continue;
+       }
+      /* reset installedpos, advance to next pass */
+      installedpos = installed->start;
+      pass++;
+    }
+  solv->installedpos = installedpos;
+  return level;
+}
+
+static int
+resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  int i, j, n;
+  int postponed;
+  Rule *r;
+  int origlevel = level;
+  Id p, *dp;
+
+  /*
+   * decide
+   */
+  POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
+  postponed = 0;
+  for (i = 1, n = 1; ; i++, n++)
+    {
+      if (n >= solv->nrules)
+       {
+         if (postponed <= 0)
+           break;
+         i = postponed;
+         postponed = -1;
+         n = 1;
+       }
+      if (i == solv->nrules)
+       i = 1;
+      r = solv->rules + i;
+      if (r->d < 0)            /* ignore disabled rules */
+       continue;
+      if (r->p < 0)            /* most common cases first */
+       {
+         if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
+           continue;
+       }
+      if (dq->count)
+       queue_empty(dq);
+      if (r->d == 0)
+       {
+         /* binary or unary rule */
+         /* need two positive undecided literals, r->p already checked above */
+         if (r->w2 <= 0)
+           continue;
+         if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
+           continue;
+         queue_push(dq, r->p);
+         queue_push(dq, r->w2);
+       }
+      else
+       {
+         /* make sure that
+          * all negative literals are installed
+          * no positive literal is installed
+          * i.e. the rule is not fulfilled and we
+          * just need to decide on the positive literals
+          * (decisionmap[-r->p] for the r->p < 0 case is already checked above)
+          */
+         if (r->p >= 0)
+           {
+             if (solv->decisionmap[r->p] > 0)
+               continue;
+             if (solv->decisionmap[r->p] == 0)
+               queue_push(dq, r->p);
+           }
+         dp = pool->whatprovidesdata + r->d;
+         while ((p = *dp++) != 0)
+           {
+             if (p < 0)
+               {
+                 if (solv->decisionmap[-p] <= 0)
+                   break;
+               }
+             else
+               {
+                 if (solv->decisionmap[p] > 0)
+                   break;
+                 if (solv->decisionmap[p] == 0)
+                   queue_push(dq, p);
+               }
+           }
+         if (p)
+           continue;
+       }
+      IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+       {
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
+         solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
+       }
+      /* dq->count < 2 cannot happen as this means that
+       * the rule is unit */
+      assert(dq->count > 1);
+
+      /* prune to cleandeps packages */
+      if (solv->cleandepsmap.size && solv->installed)
+       {
+         Repo *installed = solv->installed;
+         for (j = 0; j < dq->count; j++)
+           if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start))
+             break;
+         if (j < dq->count)
+           {
+             dq->elements[0] = dq->elements[j];
+             queue_truncate(dq, 1);
+           }
+       }
+
+      if (dq->count > 1 && postponed >= 0)
+       {
+         policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE_NOREORDER);
+         if (dq->count > 1)
+           {
+             if (!postponed)
+               postponed = i;
+             continue;
+           }
+       }
+
+      level = selectandinstall(solv, level, dq, disablerules, r - solv->rules, SOLVER_REASON_RESOLVE);
+      if (level < origlevel)
+       break;          /* trouble */
+      /* something changed, so look at all rules again */
+      n = 0;
+    }
+  return level;
+}
+
+
+#ifdef ENABLE_COMPLEX_DEPS
+
+static void
+add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
+{
+  Pool *pool = solv->pool;
+  int oldcnt = dq->count;
+  int cutcnt, blkcnt;
+  Id p;
+  int i, j;
+
+#if 0
+  printf("ADD_COMPLEX_RECOMMENDS %s\n", pool_dep2str(pool, rec));
+#endif
+  i = pool_normalize_complex_dep(pool, rec, dq, CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    return;
+  cutcnt = dq->count;
+  for (i = oldcnt; i < cutcnt; i++)
+    {
+      blkcnt = dq->count;
+      for (; (p = dq->elements[i]) != 0; i++)
+       {
+         if (p < 0)
+           {
+             if (solv->decisionmap[-p] <= 0)
+               break;
+             continue;
+           }
+         if (solv->decisionmap[p] > 0)
+           {
+             queue_truncate(dq, blkcnt);
+             break;
+           }
+         if (dqmap)
+           {
+             if (!MAPTST(dqmap, p))
+               continue;
+           }
+         else
+           {
+             if (solv->decisionmap[p] < 0)
+               continue;
+             if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+               continue;
+           }
+         queue_push(dq, p);
+       }
+      while (dq->elements[i])
+       i++;
+    }
+  queue_deleten(dq, oldcnt, cutcnt - oldcnt);
+  /* unify */
+  if (dq->count != oldcnt)
+    {
+      for (j = oldcnt; j < dq->count; j++)
+       {
+         p = dq->elements[j];
+         for (i = 0; i < j; i++)
+           if (dq->elements[i] == p)
+             {
+               dq->elements[j] = 0;
+               break;
+             }
+       }
+      for (i = j = oldcnt; j < dq->count; j++)
+       if (dq->elements[j])
+         dq->elements[i++] = dq->elements[j];
+      queue_truncate(dq, i);
+    }
+#if 0
+  printf("RETURN:\n");
+  for (i = oldcnt; i < dq->count; i++)
+    printf("  - %s\n", pool_solvid2str(pool, dq->elements[i]));
+#endif
+}
+
+static void
+do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected)
+{
+  Pool *pool = solv->pool;
+  Queue dq;
+  Id p;
+  int i, blk;
+
+#if 0
+  printf("DO_COMPLEX_RECOMMENDATIONS %s\n", pool_dep2str(pool, rec));
+#endif
+  queue_init(&dq);
+  i = pool_normalize_complex_dep(pool, rec, &dq, CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    {
+      queue_free(&dq);
+      return;
+    }
+  for (i = 0; i < dq.count; i++)
+    {
+      blk = i;
+      for (; (p = dq.elements[i]) != 0; i++)
+       {
+         if (p < 0)
+           {
+             if (solv->decisionmap[-p] <= 0)
+               break;
+             continue;
+           }
+         if (solv->decisionmap[p] > 0)
+           {
+             if (noselected)
+               break;
+             MAPSET(m, p);
+             for (i++; (p = dq.elements[i]) != 0; i++)
+               if (p > 0 && solv->decisionmap[p] > 0)
+                 MAPSET(m, p);
+             p = 1;
+             break;
+           }
+       }
+      if (!p)
+       {
+         for (i = blk; (p = dq.elements[i]) != 0; i++)
+           if (p > 0)
+             MAPSET(m, p);
+       }
+      while (dq.elements[i])
+       i++;
+    }
+  queue_free(&dq);
+}
+
+#endif
+
+static void
+prune_disfavored(Solver *solv, Queue *plist)
+{
+  int i, j;
+  if (!solv->isdisfavormap.size)
+    return;
+  for (i = j = 0; i < plist->count; i++) 
+    {    
+      Id p = plist->elements[i];
+      if (!MAPTST(&solv->isdisfavormap, p))
+        plist->elements[j++] = p; 
+    }    
+  if (i != j)
+    queue_truncate(plist, j);
+}
+
+static int
+resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, int *rerunp)
+{
+  Pool *pool = solv->pool;
+  int i, j, qcount;
+  int olevel;
+  Solvable *s;
+  Map dqmap;
+  int decisioncount;
+  Id p;
+
+  POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
+  if (dq->count)
+    queue_empty(dq);   /* recommended packages */
+  if (dqs->count)
+    queue_empty(dqs);  /* supplemented packages */
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      if (solv->decisionmap[i] < 0)
+       continue;
+      s = pool->solvables + i;
+      if (solv->decisionmap[i] > 0)
+       {
+         /* installed, check for recommends */
+         Id *recp, rec, pp, p;
+         if (!solv->addalreadyrecommended && s->repo == solv->installed)
+           continue;
+         if (s->recommends)
+           {
+             recp = s->repo->idarraydata + s->recommends;
+             while ((rec = *recp++) != 0)
+               {
+                 /* cheat: we just look if there is REL_NAMESPACE in the dep */
+                 if (solv->only_namespace_recommended && !solver_is_namespace_dep(solv, rec))
+                   continue;
+#ifdef ENABLE_COMPLEX_DEPS
+                 if (pool_is_complex_dep(pool, rec))
+                   {
+                     add_complex_recommends(solv, rec, dq, 0);
+                     continue;
+                   }
+#endif
+                 qcount = dq->count;
+                 FOR_PROVIDES(p, pp, rec)
+                   {
+                     if (solv->decisionmap[p] > 0)
+                       {
+                         dq->count = qcount;
+                         break;
+                       }
+                     else if (solv->decisionmap[p] == 0)
+                       {
+                         if (solv->process_orphans && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
+                           continue;
+                         queue_pushunique(dq, p);
+                       }
+                   }
+               }
+           }
+       }
+      else
+       {
+         /* not yet installed, check if supplemented */
+         if (!s->supplements)
+           continue;
+         if (!pool_installable(pool, s))
+           continue;
+         if (!solver_is_supplementing(solv, s))
+           continue;
+         if (solv->process_orphans && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
+           continue;
+         if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, i))
+           continue;   /* disfavored supplements, do not install */
+         queue_push(dqs, i);
+       }
+    }
+
+  /* filter out disfavored recommended packages */
+  if (dq->count && solv->isdisfavormap.size)
+    prune_disfavored(solv, dq);
+
+  /* filter out all packages obsoleted by installed packages */
+  /* this is no longer needed if we have (and trust) reverse obsoletes */
+  if ((dqs->count || dq->count) && solv->installed)
+    {
+      Map obsmap;
+      Id obs, *obsp, po, ppo;
+
+      map_init(&obsmap, pool->nsolvables);
+      for (p = solv->installed->start; p < solv->installed->end; p++)
+       {
+         s = pool->solvables + p;
+         if (s->repo != solv->installed || !s->obsoletes)
+           continue;
+         if (solv->decisionmap[p] <= 0)
+           continue;
+         if (!solv->keepexplicitobsoletes && solv->multiversion.size && MAPTST(&solv->multiversion, p))
+           continue;
+         obsp = s->repo->idarraydata + s->obsoletes;
+         /* foreach obsoletes */
+         while ((obs = *obsp++) != 0)
+           FOR_PROVIDES(po, ppo, obs)
+             {
+               Solvable *pos = pool->solvables + po;
+               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pos, obs))
+                 continue;
+               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pos))
+                 continue;
+               MAPSET(&obsmap, po);
+             }
+       }
+      for (i = j = 0; i < dqs->count; i++)
+       if (!MAPTST(&obsmap, dqs->elements[i]))
+         dqs->elements[j++] = dqs->elements[i];
+      dqs->count = j;
+      for (i = j = 0; i < dq->count; i++)
+       if (!MAPTST(&obsmap, dq->elements[i]))
+         dq->elements[j++] = dq->elements[i];
+      dq->count = j;
+      map_free(&obsmap);
+    }
+
+  /* filter out all already supplemented packages if requested */
+  if ((!solv->addalreadyrecommended || solv->only_namespace_recommended) && dqs->count)
+    {
+      /* filter out old supplements */
+      for (i = j = 0; i < dqs->count; i++)
+       {
+         p = dqs->elements[i];
+         s = pool->solvables + p;
+         if (s->supplements && solver_is_supplementing_alreadyinstalled(solv, s))
+           dqs->elements[j++] = p;
+       }
+      dqs->count = j;
+    }
+
+  /* multiversion doesn't mix well with supplements.
+   * filter supplemented packages where we already decided
+   * to install a different version (see bnc#501088) */
+  if (dqs->count && solv->multiversion.size)
+    {
+      for (i = j = 0; i < dqs->count; i++)
+       {
+         p = dqs->elements[i];
+         if (MAPTST(&solv->multiversion, p))
+           {
+             Id p2, pp2;
+             s = pool->solvables + p;
+             FOR_PROVIDES(p2, pp2, s->name)
+               if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
+                 break;
+             if (p2)
+               continue;       /* ignore this package */
+           }
+         dqs->elements[j++] = p;
+       }
+      dqs->count = j;
+    }
+
+  /* implicitobsoleteusescolors doesn't mix well with supplements.
+   * filter supplemented packages where we already decided
+   * to install a different architecture */
+  if (dqs->count && pool->implicitobsoleteusescolors)
+    {
+      for (i = j = 0; i < dqs->count; i++)
+       {
+         Id p2, pp2;
+         p = dqs->elements[i];
+         s = pool->solvables + p;
+         FOR_PROVIDES(p2, pp2, s->name)
+           if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name && pool->solvables[p2].arch != s->arch)
+             break;
+         if (p2)
+           continue;   /* ignore this package */
+         dqs->elements[j++] = p;
+       }
+      dqs->count = j;
+    }
+
+  /* make dq contain both recommended and supplemented pkgs */
+  if (dqs->count)
+    {
+      for (i = 0; i < dqs->count; i++)
+       queue_pushunique(dq, dqs->elements[i]);
+    }
+
+  if (!dq->count)
+    return level;
+  *rerunp = 1;
+
+  if (dq->count == 1)
+    {
+      /* simple case, just one package. no need to choose to best version */
+      p = dq->elements[0];
+      if (dqs->count)
+       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
+      else
+       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
+      return setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP);
+    }
+
+  /* filter packages, this gives us the best versions */
+  policy_filter_unwanted(solv, dq, POLICY_MODE_RECOMMEND);
+
+  /* create map of result */
+  map_init(&dqmap, pool->nsolvables);
+  for (i = 0; i < dq->count; i++)
+    MAPSET(&dqmap, dq->elements[i]);
+
+  /* prune dqs so that it only contains the best versions */
+  for (i = j = 0; i < dqs->count; i++)
+    {
+      p = dqs->elements[i];
+      if (MAPTST(&dqmap, p))
+       dqs->elements[j++] = p;
+    }
+  dqs->count = j;
+
+  /* install all supplemented packages, but order first */
+  if (dqs->count > 1)
+    policy_filter_unwanted(solv, dqs, POLICY_MODE_SUPPLEMENT);
+  decisioncount = solv->decisionq.count;
+  for (i = 0; i < dqs->count; i++)
+    {
+      p = dqs->elements[i];
+      if (solv->decisionmap[p])
+       continue;
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP);
+      if (level <= olevel)
+       break;
+    }
+  if (i < dqs->count || solv->decisionq.count < decisioncount)
+    {
+      map_free(&dqmap);
+      return level;
+    }
+
+  /* install all recommended packages */
+  /* more work as we want to created branches if multiple
+   * choices are valid */
+  for (i = 0; i < decisioncount; i++)
+    {
+      Id rec, *recp, pp;
+      p = solv->decisionq.elements[i];
+      if (p < 0)
+       continue;
+      s = pool->solvables + p;
+      if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
+       continue;
+      if (!s->recommends)
+       continue;
+      recp = s->repo->idarraydata + s->recommends;
+      while ((rec = *recp++) != 0)
+       {
+         queue_empty(dq);
+#ifdef ENABLE_COMPLEX_DEPS
+         if (pool_is_complex_dep(pool, rec))
+             add_complex_recommends(solv, rec, dq, &dqmap);
+         else
+#endif
+         FOR_PROVIDES(p, pp, rec)
+           {
+             if (solv->decisionmap[p] > 0)
+               {
+                 dq->count = 0;
+                 break;
+               }
+             else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
+               queue_push(dq, p);
+           }
+         if (!dq->count)
+           continue;
+         if (dq->count > 1)
+           policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+         /* if we have multiple candidates we open a branch */
+         if (dq->count > 1)
+             createbranch(solv, level, dq, s - pool->solvables, rec);
+         p = dq->elements[0];
+         POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
+         olevel = level;
+         level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_WEAKDEP);
+         if (level <= olevel || solv->decisionq.count < decisioncount)
+           break;      /* we had to revert some decisions */
+       }
+      if (rec)
+       break;  /* had a problem above, quit loop */
+    }
+  map_free(&dqmap);
+  return level;
+}
+
+static int
+resolve_cleandeps(Solver *solv, int level, int disablerules, int *rerunp)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int olevel;
+  Id p;
+  Solvable *s;
+
+  if (!installed || !solv->cleandepsmap.size)
+    return level;
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding cleandeps packages\n");
+  for (p = installed->start; p < installed->end; p++)
+    {
+      s = pool->solvables + p;
+      if (s->repo != installed)
+       continue;
+      if (solv->decisionmap[p] != 0 || !MAPTST(&solv->cleandepsmap, p - installed->start))
+       continue;
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+      if (level < olevel)
+       break;
+    }
+  if (p < installed->end)
+    *rerunp = 1;
+  return level;
+}
+
+static int
+resolve_orphaned(Solver *solv, int level, int disablerules, Queue *dq, int *rerunp)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id p;
+  int installedone = 0;
+  int olevel;
+
+  /* let's see if we can install some unsupported package */
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
+  for (i = 0; i < solv->orphaned.count; i++)
+    {
+      p = solv->orphaned.elements[i];
+      if (solv->decisionmap[p])
+       continue;       /* already decided */
+      if (solv->droporphanedmap_all)
+       continue;
+      if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
+       continue;
+      POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN);
+      installedone = 1;
+      if (level < olevel)
+       break;
+    }
+  if (installedone || i < solv->orphaned.count)
+    {
+      *rerunp = 1;
+      return level;
+    }
+  for (i = 0; i < solv->orphaned.count; i++)
+    {
+      p = solv->orphaned.elements[i];
+      if (solv->decisionmap[p])
+       continue;       /* already decided */
+      POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
+      olevel = level;
+      level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN);
+      if (level < olevel)
+       {
+         *rerunp = 1;
+         return level;
+       }
+    }
+  if (solv->brokenorphanrules)
+    {
+      solver_check_brokenorphanrules(solv, dq);
+      if (dq->count)
+       {
+         policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
+         for (i = 0; i < dq->count; i++)
+           {
+             p = dq->elements[i];
+             POOL_DEBUG(SOLV_DEBUG_POLICY, "installing orphaned dep %s\n", pool_solvid2str(pool, p));
+             olevel = level;
+             level = setpropagatelearn(solv, level, p, 0, 0, SOLVER_REASON_RESOLVE_ORPHAN);
+             if (level < olevel)
+               break;
+           }
+         *rerunp = 1;
+       }
+    }
+  return level;
+}
+
+/*-------------------------------------------------------------------
+ *
+ * solver_run_sat
+ *
+ * all rules have been set up, now actually run the solver
+ *
+ */
+
+void
+solver_run_sat(Solver *solv, int disablerules, int doweak)
+{
+  Queue dq;            /* local decisionqueue */
+  Queue dqs;           /* local decisionqueue for supplements */
+  int systemlevel;
+  int level, olevel;
+  Rule *r;
+  int i;
+  Solvable *s;
+  Pool *pool = solv->pool;
+  Id p;
+  int minimizationsteps;
+
+  IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
+    {
+      POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
+      for (i = 1; i < solv->nrules; i++)
+       solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
+    }
+
+  /* start SAT algorithm */
+  level = 0;
+  systemlevel = level + 1;
+  POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
+
+  queue_init(&dq);
+  queue_init(&dqs);
+  solv->installedpos = 0;
+  solv->do_extra_reordering = 0;
+
+  /*
+   * here's the main loop:
+   * 1) decide assertion rules and propagate
+   * 2) fulfill jobs
+   * 3) try to keep installed packages
+   * 4) fulfill all unresolved rules
+   * 5) install recommended packages
+   * 6) minimalize solution if we had choices
+   * if we encounter a problem, we rewind to a safe level and restart
+   * with step 1
+   */
+
+  minimizationsteps = 0;
+  for (;;)
+    {
+      /*
+       * initial propagation of the assertions
+       */
+      if (level <= 0)
+       {
+         if (level < 0)
+           break;
+         level = makeruledecisions(solv, disablerules);
+         if (level < 0)
+           break;
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
+         if ((r = propagate(solv, level)) != 0)
+           {
+             level = analyze_unsolvable(solv, r, disablerules);
+             continue;
+           }
+         systemlevel = level + 1;
+       }
+
+      /*
+       * resolve jobs first (unless focus_installed is set)
+       */
+     if (level < systemlevel && !solv->focus_installed)
+       {
+         if (solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
+           solv->do_extra_reordering = 1;
+         olevel = level;
+         level = resolve_jobrules(solv, level, disablerules, &dq);
+         solv->do_extra_reordering = 0;
+         if (level < olevel)
+           continue;
+         systemlevel = level + 1;
+       }
+
+      /* resolve job dependencies in the focus_best case */
+      if (level < systemlevel && solv->focus_best && !solv->focus_installed && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
+       {
+         solv->do_extra_reordering = 1;
+         olevel = level;
+         level = resolve_dependencies(solv, level, disablerules, &dq);
+         solv->do_extra_reordering = 0;
+         if (level < olevel)
+           continue;           /* start over */
+         systemlevel = level + 1;
+       }
+
+      /*
+       * installed packages
+       */
+      if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
+       {
+         olevel = level;
+         level = resolve_installed(solv, level, disablerules, &dq);
+         if (level < olevel)
+           continue;
+         systemlevel = level + 1;
+       }
+
+     /* resolve jobs in focus_installed case */
+     if (level < systemlevel && solv->focus_installed)
+       {
+         olevel = level;
+         level = resolve_jobrules(solv, level, disablerules, &dq);
+         if (level < olevel)
+           continue;
+         systemlevel = level + 1;
+       }
+
+      if (level < systemlevel)
+        systemlevel = level;
+
+      /* resolve all dependencies */
+      olevel = level;
+      level = resolve_dependencies(solv, level, disablerules, &dq);
+      if (level < olevel)
+        continue;              /* start over */
+
+      /* decide leftover cleandeps packages */
+      if (solv->cleandepsmap.size && solv->installed)
+       {
+         int rerun = 0;
+         level = resolve_cleandeps(solv, level, disablerules, &rerun);
+         if (rerun)
+           continue;
+       }
+
+      /* at this point we have a consistent system. now do the extras... */
+
+      if (doweak)
+       {
+         int rerun = 0;
+         level = resolve_weak(solv, level, disablerules, &dq, &dqs, &rerun);
+         if (rerun)
+           continue;
+       }
+
+      if (solv->installed && (solv->orphaned.count || solv->brokenorphanrules))
+       {
+         int rerun = 0;
+         level = resolve_orphaned(solv, level, disablerules, &dq, &rerun);
+         if (rerun)
+           continue;
+       }
+         
+     /* one final pass to make sure we decided all installed packages */
+      if (solv->installed)
+       {
+         for (p = solv->installed->start; p < solv->installed->end; p++)
+           {
+             if (solv->decisionmap[p])
+               continue;       /* already decided */
+             s = pool->solvables + p;
+             if (s->repo != solv->installed)
+               continue;
+             POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p));
+             olevel = level;
+             level = setpropagatelearn(solv, level, -p, 0, 0, SOLVER_REASON_CLEANDEPS_ERASE);
+             if (level < olevel)
+               break;
+           }
+         if (p < solv->installed->end)
+           continue;           /* back to main loop */
+       }
+
+      if (solv->installed && solv->cleandepsmap.size && solver_check_cleandeps_mistakes(solv))
+       {
+         solver_reset(solv);
+         level = 0;    /* restart from scratch */
+         continue;
+       }
+
+      if (solv->solution_callback)
+       {
+         solv->solution_callback(solv, solv->solution_callback_data);
+         if (solv->branches.count)
+           {
+             int l, endi = 0;
+             p = l = 0;
+             for (i = solv->branches.count - 1; i >= 0; i--)
+               {
+                 p = solv->branches.elements[i];
+                 if (p > 0 && !l)
+                   {
+                     endi = i + 1;
+                     l = p;
+                     i -= 3;   /* skip: p data count */
+                   }
+                 else if (p > 0)
+                   break;
+                 else if (p < 0)
+                   l = 0;
+               }
+             if (i >= 0)
+               {
+                 while (i > 0 && solv->branches.elements[i - 1] > 0)
+                   i--;
+                 level = takebranch(solv, i, endi, "branching", disablerules);
+                 continue;
+               }
+           }
+         /* all branches done, we're finally finished */
+         break;
+       }
+
+      /* auto-minimization step */
+      if (solv->branches.count)
+       {
+         int endi, lasti = -1, lastiend = -1;
+         if (solv->recommends_index < solv->decisionq.count)
+           policy_update_recommendsmap(solv);
+         for (endi = solv->branches.count; endi > 0;)
+           {
+             int l, lastsi = -1, starti = endi - solv->branches.elements[endi - 2];
+             l = solv->branches.elements[endi - 1];
+             for (i = starti; i < endi - 4; i++)
+               {
+                 p = solv->branches.elements[i];
+                 if (p <= 0)
+                   continue;
+                 if (solv->decisionmap[p] > l)
+                   {
+                     lasti = i;
+                     lastiend = endi;
+                     lastsi = -1;
+                     break;
+                   }
+                 if (solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p))
+                   continue;
+                 if (lastsi < 0 && (MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
+                   lastsi = i;
+               }
+             if (lastsi >= 0)
+               {
+                 /* we have a recommended package that could not be installed */
+                 /* take it if our current selection is not recommended */
+                 for (i = starti; i < endi - 4; i++)
+                   {
+                     p = -solv->branches.elements[i];
+                     if (p <= 0 || solv->decisionmap[p] != l + 1)
+                       continue;
+                     if (solv->favormap.size && MAPTST(&solv->favormap, p))
+                       if (!(solv->isdisfavormap.size && MAPTST(&solv->isdisfavormap, p)))
+                         continue;     /* current selection is favored */
+                     if (!(MAPTST(&solv->recommendsmap, p) || solver_is_supplementing(solv, pool->solvables + p)))
+                       {
+                         lasti = lastsi;
+                         lastiend = endi;
+                         break;
+                       }
+                   }
+               }
+             endi = starti;
+           }
+         if (lasti >= 0)
+           {
+             minimizationsteps++;
+             level = takebranch(solv, lasti, lastiend, "minimizing", disablerules);
+             continue;         /* back to main loop */
+           }
+       }
+      /* no minimization found, we're finally finished! */
+      break;
+    }
+  assert(level == -1 || level + 1 == solv->decisionq_reason.count);
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
+  queue_free(&dq);
+  queue_free(&dqs);
+#if 0
+  solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
+#endif
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * remove disabled conflicts
+ *
+ * purpose: update the decisionmap after some rules were disabled.
+ * this is used to calculate the suggested/recommended package list.
+ * Also returns a "removed" list to undo the discisionmap changes.
+ */
+
+static void
+removedisabledconflicts(Solver *solv, Queue *removed)
+{
+  Pool *pool = solv->pool;
+  int i, n;
+  Id p, why, *dp;
+  Id new;
+  Rule *r;
+  Id *decisionmap = solv->decisionmap;
+
+  queue_empty(removed);
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p > 0)
+       continue;       /* conflicts only, please */
+      why = solv->decisionq_why.elements[i];
+      if (why == 0)
+       {
+         /* no rule involved, must be a orphan package drop */
+         continue;
+       }
+      /* we never do conflicts on free decisions, so there
+       * must have been an unit rule */
+      assert(why > 0);
+      r = solv->rules + why;
+      if (r->d < 0 && decisionmap[-p])
+       {
+         /* rule is now disabled, remove from decisionmap */
+         POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
+         queue_push(removed, -p);
+         queue_push(removed, decisionmap[-p]);
+         decisionmap[-p] = 0;
+       }
+    }
+  if (!removed->count)
+    return;
+  /* we removed some confliced packages. some of them might still
+   * be in conflict, so search for unit rules and re-conflict */
+  new = 0;
+  for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
+    {
+      if (i == solv->nrules)
+       {
+         i = 1;
+         r = solv->rules + i;
+       }
+      if (r->d < 0)
+       continue;
+      if (!r->w2)
+       {
+         if (r->p < 0 && !decisionmap[-r->p])
+           new = r->p;
+       }
+      else if (!r->d)
+       {
+         /* binary rule */
+         if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
+           new = r->p;
+         else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
+           new = r->w2;
+       }
+      else
+       {
+         if (r->p < 0 && decisionmap[-r->p] == 0)
+           new = r->p;
+         if (new || DECISIONMAP_FALSE(r->p))
+           {
+             dp = pool->whatprovidesdata + r->d;
+             while ((p = *dp++) != 0)
+               {
+                 if (new && p == new)
+                   continue;
+                 if (p < 0 && decisionmap[-p] == 0)
+                   {
+                     if (new)
+                       {
+                         new = 0;
+                         break;
+                       }
+                     new = p;
+                   }
+                 else if (!DECISIONMAP_FALSE(p))
+                   {
+                     new = 0;
+                     break;
+                   }
+               }
+           }
+       }
+      if (new)
+       {
+         POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
+         decisionmap[-new] = -1;
+         new = 0;
+         n = 0;        /* redo all rules */
+       }
+    }
+}
+
+static inline void
+undo_removedisabledconflicts(Solver *solv, Queue *removed)
+{
+  int i;
+  for (i = 0; i < removed->count; i += 2)
+    solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * weaken solvable dependencies
+ */
+
+static void
+weaken_solvable_deps(Solver *solv, Id p)
+{
+  int i;
+  Rule *r;
+
+  for (i = 1, r = solv->rules + i; i < solv->pkgrules_end; i++, r++)
+    {
+      if (r->p != -p)
+       continue;
+      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
+       continue;       /* conflict */
+      queue_push(&solv->weakruleq, i);
+    }
+}
+
+
+/********************************************************************/
+/* main() */
+
+
+void
+solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap)
+{
+  int i;
+  Id how, what, select;
+  Id p, pp;
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) != SOLVER_MULTIVERSION)
+       continue;
+      what = job->elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
+      if (!multiversionmap->size)
+       map_grow(multiversionmap, pool->nsolvables);
+      if (select == SOLVER_SOLVABLE_ALL)
+       {
+         FOR_POOL_SOLVABLES(p)
+           MAPSET(multiversionmap, p);
+       }
+      else if (select == SOLVER_SOLVABLE_REPO)
+       {
+         Solvable *s;
+         Repo *repo = pool_id2repo(pool, what);
+         if (repo)
+           {
+             FOR_REPO_SOLVABLES(repo, p, s)
+               MAPSET(multiversionmap, p);
+           }
+       }
+      FOR_JOB_SELECT(p, pp, select, what)
+        MAPSET(multiversionmap, p);
+    }
+}
+
+void
+solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap)
+{
+  solver_calculate_multiversionmap(pool, job, multiversionmap);
+}
+
+/*
+ * add a rule created by a job, record job number and weak flag
+ */
+static inline void
+solver_addjobrule(Solver *solv, Id p, Id p2, Id d, Id job, int weak)
+{
+  solver_addrule(solv, p, p2, d);
+  queue_push(&solv->ruletojob, job);
+  if (weak)
+    queue_push(&solv->weakruleq, solv->nrules - 1);
+}
+
+static inline void
+add_cleandeps_updatepkg(Solver *solv, Id p)
+{
+  if (!solv->cleandeps_updatepkgs)
+    {
+      solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
+      queue_init(solv->cleandeps_updatepkgs);
+    }
+  queue_pushunique(solv->cleandeps_updatepkgs, p);
+}
+
+static void
+add_update_target(Solver *solv, Id p, Id how)
+{
+  Pool *pool = solv->pool;
+  Solvable *s = pool->solvables + p;
+  Repo *installed = solv->installed;
+  Id pi, pip, identicalp;
+  int startcnt, endcnt;
+
+  if (!solv->update_targets)
+    {
+      solv->update_targets = solv_calloc(1, sizeof(Queue));
+      queue_init(solv->update_targets);
+    }
+  if (s->repo == installed)
+    {
+      queue_push2(solv->update_targets, p, p);
+      return;
+    }
+  identicalp = 0;
+  startcnt = solv->update_targets->count;
+  FOR_PROVIDES(pi, pip, s->name)
+    {
+      Solvable *si = pool->solvables + pi;
+      if (si->repo != installed || si->name != s->name)
+       continue;
+      if (how & SOLVER_FORCEBEST)
+       {
+         if (!solv->bestupdatemap.size)
+           map_grow(&solv->bestupdatemap, installed->end - installed->start);
+         MAPSET(&solv->bestupdatemap, pi - installed->start);
+       }
+      if (how & SOLVER_CLEANDEPS)
+       add_cleandeps_updatepkg(solv, pi);
+      queue_push2(solv->update_targets, pi, p);
+      /* remember an installed package that is identical to p */
+      if (s->evr == si->evr && solvable_identical(s, si))
+       identicalp = pi;
+    }
+  if (s->obsoletes)
+    {
+      Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+      while ((obs = *obsp++) != 0)
+       {
+         FOR_PROVIDES(pi, pip, obs)
+           {
+             Solvable *si = pool->solvables + pi;
+             if (si->repo != installed)
+               continue;
+             if (si->name == s->name)
+               continue;       /* already handled above */
+             if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
+               continue;
+             if (how & SOLVER_FORCEBEST)
+               {
+                 if (!solv->bestupdatemap.size)
+                   map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                 MAPSET(&solv->bestupdatemap, pi - installed->start);
+               }
+             if (how & SOLVER_CLEANDEPS)
+               add_cleandeps_updatepkg(solv, pi);
+             queue_push2(solv->update_targets, pi, p);
+           }
+       }
+    }
+  /* also allow upgrading to an identical installed package */
+  if (identicalp)
+    {
+      for (endcnt = solv->update_targets->count; startcnt < endcnt; startcnt += 2)
+       queue_push2(solv->update_targets, solv->update_targets->elements[startcnt], identicalp);
+    }
+}
+
+static int
+transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap;
+  const Id *b = bp;
+  if (a[0] - b[0])
+    return a[0] - b[0];
+  return a[1] - b[1];
+}
+
+static void
+transform_update_targets(Solver *solv)
+{
+  Repo *installed = solv->installed;
+  Queue *update_targets = solv->update_targets;
+  int i, j;
+  Id p, q, lastp, lastq;
+
+  if (!update_targets->count)
+    {
+      queue_free(update_targets);
+      solv->update_targets = solv_free(update_targets);
+      return;
+    }
+  if (update_targets->count > 2)
+    solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
+  queue_insertn(update_targets, 0, installed->end - installed->start, 0);
+  lastp = lastq = 0;
+  for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
+    {
+      if ((p = update_targets->elements[i]) != lastp)
+       {
+         if (!solv->updatemap.size)
+           map_grow(&solv->updatemap, installed->end - installed->start);
+         MAPSET(&solv->updatemap, p - installed->start);
+         update_targets->elements[j++] = 0;                    /* finish old set */
+         update_targets->elements[p - installed->start] = j;   /* start new set */
+         lastp = p;
+         lastq = 0;
+       }
+      if ((q = update_targets->elements[i + 1]) != lastq)
+       {
+          update_targets->elements[j++] = q;
+         lastq = q;
+       }
+    }
+  queue_truncate(update_targets, j);
+  queue_push(update_targets, 0);       /* finish last set */
+}
+
+
+static void
+addedmap2deduceq(Solver *solv, Map *addedmap)
+{
+  Pool *pool = solv->pool;
+  int i, j;
+  Id p;
+  Rule *r;
+
+  queue_empty(&solv->addedmap_deduceq);
+  for (i = 2, j = solv->pkgrules_end - 1; i < pool->nsolvables && j > 0; j--)
+    {
+      r = solv->rules + j;
+      if (r->p >= 0)
+       continue;
+      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
+       continue;
+      p = -r->p;
+      if (!MAPTST(addedmap, p))
+       {
+         /* should never happen, but... */
+         if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
+            queue_push(&solv->addedmap_deduceq, -p);
+         continue;
+       }
+      for (; i < p; i++)
+        if (MAPTST(addedmap, i))
+          queue_push(&solv->addedmap_deduceq, i);
+      if (i == p)
+        i++;
+    }
+  for (; i < pool->nsolvables; i++)
+    if (MAPTST(addedmap, i))
+      queue_push(&solv->addedmap_deduceq, i);
+  j = 0;
+  for (i = 2; i < pool->nsolvables; i++)
+    if (MAPTST(addedmap, i))
+      j++;
+}
+
+static void
+deduceq2addedmap(Solver *solv, Map *addedmap)
+{
+  int j;
+  Id p;
+  Rule *r;
+  for (j = solv->pkgrules_end - 1; j > 0; j--)
+    {
+      r = solv->rules + j;
+      if (r->d < 0 && r->p)
+       solver_enablerule(solv, r);
+      if (r->p >= 0)
+       continue;
+      if ((r->d == 0 || r->d == -1) && r->w2 < 0)
+       continue;
+      p = -r->p;
+      MAPSET(addedmap, p);
+    }
+  for (j = 0; j < solv->addedmap_deduceq.count; j++)
+    {
+      p = solv->addedmap_deduceq.elements[j];
+      if (p > 0)
+       MAPSET(addedmap, p);
+      else
+       MAPCLR(addedmap, p);
+    }
+}
+
+#ifdef ENABLE_COMPLEX_DEPS
+static int
+add_complex_jobrules(Solver *solv, Id dep, int flags, int jobidx, int weak)
+{
+  Pool *pool = solv->pool;
+  Queue bq;
+  int i, j;
+
+  queue_init(&bq);
+  i = pool_normalize_complex_dep(pool, dep, &bq, flags | CPLXDEPS_EXPAND);
+  if (i == 0 || i == 1)
+    {
+      queue_free(&bq);
+      if (i == 0)
+        solver_addjobrule(solv, -SYSTEMSOLVABLE, 0, 0, jobidx, weak);
+      return 0;
+    }
+  for (i = 0; i < bq.count; i++)
+    {
+      if (!bq.elements[i])
+       continue;
+      for (j = 0; bq.elements[i + j + 1]; j++)
+        ;
+      if (j > 1)
+        solver_addjobrule(solv, bq.elements[i], 0, pool_ids2whatprovides(pool, bq.elements + i + 1, j), jobidx, weak);
+      else
+        solver_addjobrule(solv, bq.elements[i], bq.elements[i + 1], 0, jobidx, weak);
+      i += j + 1;
+    }
+  queue_free(&bq);
+  return 1;
+}
+#endif
+
+/* sort by package id, last entry wins */
+static int
+setup_favormaps_cmp(const void *ap, const void *bp, void *dp)
+{
+  const Id *a = ap, *b = bp;
+  if ((*a - *b) != 0)
+    return *a - *b;
+  return (b[1] < 0 ? -b[1] : b[1]) - (a[1] < 0 ? -a[1] : a[1]);
+}
+
+static void
+setup_favormaps(Solver *solv)
+{
+  Queue *q = solv->favorq;
+  Pool *pool = solv->pool;
+  int i;
+  Id oldp = 0;
+  if (q->count > 2)
+    solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), setup_favormaps_cmp, solv);
+  map_grow(&solv->favormap, pool->nsolvables);
+  for (i = 0; i < q->count; i += 2)
+    {
+      Id p = q->elements[i];
+      if (p == oldp)
+       continue;
+      oldp = p;
+      MAPSET(&solv->favormap, p);
+      if (q->elements[i + 1] < 0)
+       {
+         if (!solv->isdisfavormap.size)
+           map_grow(&solv->isdisfavormap, pool->nsolvables);
+         MAPSET(&solv->isdisfavormap, p);
+       }
+    }
+}
+
+/*
+ *
+ * solve job queue
+ *
+ */
+
+int
+solver_solve(Solver *solv, Queue *job)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  int i;
+  int oldnrules, initialnrules;
+  Map addedmap;                       /* '1' == have pkg-rules for solvable */
+  Map installcandidatemap;
+  Id how, what, select, name, weak, p, pp, d;
+  Queue q;
+  Solvable *s, *name_s;
+  Rule *r;
+  int now, solve_start;
+  int needduprules = 0;
+  int hasbestinstalljob = 0;
+
+  solve_start = solv_timems(0);
+
+  /* log solver options */
+  POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
+  POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d onlynamespacerecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended, solv->only_namespace_recommended);
+
+  /* create whatprovides if not already there */
+  if (!pool->whatprovides)
+    pool_createwhatprovides(pool);
+
+  /* create obsolete index */
+  policy_create_obsolete_index(solv);
+
+  /* remember job */
+  queue_free(&solv->job);
+  queue_init_clone(&solv->job, job);
+  solv->pooljobcnt = pool->pooljobs.count;
+  if (pool->pooljobs.count)
+    queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
+  job = &solv->job;
+
+  /* free old stuff in case we re-run a solver */
+  queuep_free(&solv->update_targets);
+  queuep_free(&solv->cleandeps_updatepkgs);
+  queue_empty(&solv->ruleassertions);
+  solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
+  solv->yumobsrules_info = solv_free(solv->yumobsrules_info);
+  solv->choicerules_ref = solv_free(solv->choicerules_ref);
+  if (solv->noupdate.size)
+    map_empty(&solv->noupdate);
+  map_zerosize(&solv->multiversion);
+  solv->updatemap_all = 0;
+  map_zerosize(&solv->updatemap);
+  solv->bestupdatemap_all = 0;
+  map_zerosize(&solv->bestupdatemap);
+  solv->fixmap_all = 0;
+  map_zerosize(&solv->fixmap);
+  map_zerosize(&solv->dupmap);
+  map_zerosize(&solv->dupinvolvedmap);
+  solv->process_orphans = 0;
+  solv->droporphanedmap_all = 0;
+  map_zerosize(&solv->droporphanedmap);
+  solv->allowuninstall_all = 0;
+  map_zerosize(&solv->allowuninstallmap);
+  map_zerosize(&solv->cleandepsmap);
+  map_zerosize(&solv->weakrulemap);
+  map_zerosize(&solv->favormap);
+  map_zerosize(&solv->isdisfavormap);
+  queue_empty(&solv->weakruleq);
+  solv->watches = solv_free(solv->watches);
+  queue_empty(&solv->ruletojob);
+  if (solv->decisionq.count)
+    memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
+  queue_empty(&solv->decisionq);
+  queue_empty(&solv->decisionq_why);
+  queue_empty(&solv->decisionq_reason);
+  queue_empty(&solv->learnt_why);
+  queue_empty(&solv->learnt_pool);
+  queue_empty(&solv->branches);
+  solv->propagate_index = 0;
+  queue_empty(&solv->problems);
+  queue_empty(&solv->solutions);
+  queue_empty(&solv->orphaned);
+  solv->stats_learned = solv->stats_unsolvable = 0;
+  if (solv->recommends_index)
+    {
+      map_empty(&solv->recommendsmap);
+      map_empty(&solv->suggestsmap);
+      queuep_free(&solv->recommendscplxq);
+      queuep_free(&solv->suggestscplxq);
+      solv->recommends_index = 0;
+    }
+  queuep_free(&solv->brokenorphanrules);
+  solv->specialupdaters = solv_free(solv->specialupdaters);
+
+
+  /*
+   * create basic rule set of all involved packages
+   * use addedmap bitmap to make sure we don't create rules twice
+   */
+
+  /* create multiversion map if needed */
+  solver_calculate_multiversionmap(pool, job, &solv->multiversion);
+
+  map_init(&addedmap, pool->nsolvables);
+  MAPSET(&addedmap, SYSTEMSOLVABLE);
+
+  map_init(&installcandidatemap, pool->nsolvables);
+  queue_init(&q);
+
+  now = solv_timems(0);
+  /*
+   * create rules for all package that could be involved with the solving
+   * so called: pkg rules
+   *
+   */
+  initialnrules = solv->pkgrules_end ? solv->pkgrules_end : 1;
+  if (initialnrules > 1)
+    deduceq2addedmap(solv, &addedmap);
+  if (solv->nrules != initialnrules)
+    solver_shrinkrules(solv, initialnrules);
+  solv->lastpkgrule = 0;
+  solv->pkgrules_end = 0;
+
+  if (installed)
+    {
+      /* check for update/verify jobs as they need to be known early */
+      /* also setup the droporphaned map, we need it when creating update rules */
+      for (i = 0; i < job->count; i += 2)
+       {
+         how = job->elements[i];
+         what = job->elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         switch (how & SOLVER_JOBMASK)
+           {
+           case SOLVER_VERIFY:
+             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
+               solv->fixmap_all = 1;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 if (s->repo != installed)
+                   continue;
+                 if (!solv->fixmap.size)
+                   map_grow(&solv->fixmap, installed->end - installed->start);
+                 MAPSET(&solv->fixmap, p - installed->start);
+               }
+             break;
+           case SOLVER_UPDATE:
+             if (select == SOLVER_SOLVABLE_ALL)
+               {
+                 solv->updatemap_all = 1;
+                 if (how & SOLVER_FORCEBEST)
+                   solv->bestupdatemap_all = 1;
+                 if (how & SOLVER_CLEANDEPS)
+                   {
+                     FOR_REPO_SOLVABLES(installed, p, s)
+                       add_cleandeps_updatepkg(solv, p);
+                   }
+               }
+             else if (select == SOLVER_SOLVABLE_REPO)
+               {
+                 Repo *repo = pool_id2repo(pool, what);
+                 if (!repo)
+                   break;
+                 if (repo == installed && !(how & SOLVER_TARGETED))
+                   {
+                     solv->updatemap_all = 1;
+                     if (how & SOLVER_FORCEBEST)
+                       solv->bestupdatemap_all = 1;
+                     if (how & SOLVER_CLEANDEPS)
+                       {
+                         FOR_REPO_SOLVABLES(installed, p, s)
+                           add_cleandeps_updatepkg(solv, p);
+                       }
+                     break;
+                   }
+                 if (solv->noautotarget && !(how & SOLVER_TARGETED))
+                   break;
+                 /* targeted update */
+                 FOR_REPO_SOLVABLES(repo, p, s)
+                   add_update_target(solv, p, how);
+               }
+             else
+               {
+                 if (!(how & SOLVER_TARGETED))
+                   {
+                     int targeted = 1;
+                     FOR_JOB_SELECT(p, pp, select, what)
+                       {
+                         s = pool->solvables + p;
+                         if (s->repo != installed)
+                           continue;
+                         if (!solv->updatemap.size)
+                           map_grow(&solv->updatemap, installed->end - installed->start);
+                         MAPSET(&solv->updatemap, p - installed->start);
+                         if (how & SOLVER_FORCEBEST)
+                           {
+                             if (!solv->bestupdatemap.size)
+                               map_grow(&solv->bestupdatemap, installed->end - installed->start);
+                             MAPSET(&solv->bestupdatemap, p - installed->start);
+                           }
+                         if (how & SOLVER_CLEANDEPS)
+                           add_cleandeps_updatepkg(solv, p);
+                         targeted = 0;
+                       }
+                     if (!targeted || solv->noautotarget)
+                       break;
+                   }
+                 FOR_JOB_SELECT(p, pp, select, what)
+                   add_update_target(solv, p, how);
+               }
+             break;
+           case SOLVER_DROP_ORPHANED:
+             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
+               solv->droporphanedmap_all = 1;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 if (s->repo != installed)
+                   continue;
+                 if (!solv->droporphanedmap.size)
+                   map_grow(&solv->droporphanedmap, installed->end - installed->start);
+                 MAPSET(&solv->droporphanedmap, p - installed->start);
+               }
+             break;
+           case SOLVER_ALLOWUNINSTALL:
+             if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
+               solv->allowuninstall_all = 1;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 if (s->repo != installed)
+                   continue;
+                 if (!solv->allowuninstallmap.size)
+                   map_grow(&solv->allowuninstallmap, installed->end - installed->start);
+                 MAPSET(&solv->allowuninstallmap, p - installed->start);
+               }
+             break;
+           default:
+             break;
+           }
+       }
+
+      if (solv->update_targets)
+       transform_update_targets(solv);
+
+      oldnrules = solv->nrules;
+      FOR_REPO_SOLVABLES(installed, p, s)
+       solver_addpkgrulesforsolvable(solv, s, &addedmap);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for installed solvables\n", solv->nrules - oldnrules);
+      oldnrules = solv->nrules;
+      FOR_REPO_SOLVABLES(installed, p, s)
+       solver_addpkgrulesforupdaters(solv, s, &addedmap, 1);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for updaters of installed solvables\n", solv->nrules - oldnrules);
+    }
+
+  /*
+   * create rules for all packages involved in the job
+   * (to be installed or removed)
+   */
+
+  oldnrules = solv->nrules;
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      what = job->elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
+
+      switch (how & SOLVER_JOBMASK)
+       {
+       case SOLVER_INSTALL:
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             MAPSET(&installcandidatemap, p);
+             solver_addpkgrulesforsolvable(solv, pool->solvables + p, &addedmap);
+           }
+         break;
+       case SOLVER_DISTUPGRADE:
+         needduprules = 1;
+         if (select == SOLVER_SOLVABLE_ALL)
+           solv->process_orphans = 1;
+         break;
+       default:
+         break;
+       }
+    }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules for packages involved in a job\n", solv->nrules - oldnrules);
+
+
+  /*
+   * add rules for suggests, enhances
+   */
+  oldnrules = solv->nrules;
+  solver_addpkgrulesforweak(solv, &addedmap);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of weak dependencies\n", solv->nrules - oldnrules);
+
+#ifdef ENABLE_LINKED_PKGS
+  oldnrules = solv->nrules;
+  solver_addpkgrulesforlinked(solv, &addedmap);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "added %d pkg rules because of linked packages\n", solv->nrules - oldnrules);
+#endif
+
+  /*
+   * first pass done, we now have all the pkg rules we need.
+   * unify existing rules before going over all job rules and
+   * policy rules.
+   * at this point the system is always solvable,
+   * as an empty system (remove all packages) is a valid solution
+   */
+
+  IF_POOLDEBUG (SOLV_DEBUG_STATS)
+    {
+      int possible = 0, installable = 0;
+      for (i = 1; i < pool->nsolvables; i++)
+       {
+         if (pool_installable(pool, pool->solvables + i))
+           installable++;
+         if (MAPTST(&addedmap, i))
+           possible++;
+       }
+      POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
+    }
+
+  if (solv->nrules > initialnrules)
+    solver_unifyrules(solv);                   /* remove duplicate pkg rules */
+  solv->pkgrules_end = solv->nrules;           /* mark end of pkg rules */
+  solv->lastpkgrule = 0;
+
+  if (solv->nrules > initialnrules)
+    addedmap2deduceq(solv, &addedmap);         /* so that we can recreate the addedmap */
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "pkg rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "pkg rule creation took %d ms\n", solv_timems(now));
+
+  /* create dup maps if needed. We need the maps early to create our
+   * update rules */
+  if (needduprules)
+    solver_createdupmaps(solv);
+
+  /*
+   * create feature rules
+   *
+   * foreach installed:
+   *   create assertion (keep installed, if no update available)
+   *   or
+   *   create update rule (A|update1(A)|update2(A)|...)
+   *
+   * those are used later on to keep a version of the installed packages in
+   * best effort mode
+   */
+
+  solv->featurerules = solv->nrules;              /* mark start of feature rules */
+  if (installed)
+    {
+      /* foreach possibly installed solvable */
+      for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
+       {
+         if (s->repo != installed)
+           {
+             solver_addrule(solv, 0, 0, 0);    /* create dummy rule */
+             continue;
+           }
+         solver_addfeaturerule(solv, s);
+       }
+      /* make sure we accounted for all rules */
+      assert(solv->nrules - solv->featurerules == installed->end - installed->start);
+    }
+  solv->featurerules_end = solv->nrules;
+
+    /*
+     * Add update rules for installed solvables
+     *
+     * almost identical to feature rules
+     * except that downgrades/archchanges/vendorchanges are not allowed
+     */
+
+  solv->updaterules = solv->nrules;
+
+  if (installed)
+    { /* foreach installed solvables */
+      /* we create all update rules, but disable some later on depending on the job */
+      for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
+       {
+         Rule *sr;
+
+         if (s->repo != installed)
+           {
+             solver_addrule(solv, 0, 0, 0);    /* create dummy rule */
+             continue;
+           }
+         solver_addupdaterule(solv, s);
+         /*
+          * check for and remove duplicate
+          */
+         r = solv->rules + solv->nrules - 1;           /* r: update rule */
+         sr = r - (installed->end - installed->start); /* sr: feature rule */
+          if (!r->p)
+           {
+             if (sr->p)
+               memset(sr, 0, sizeof(*sr));             /* no feature rules without update rules */
+             continue;
+           }
+         /* it's also orphaned if the feature rule consists just of the installed package */
+         if (!solv->process_orphans && sr->p == i && !sr->d && !sr->w2)
+           queue_push(&solv->orphaned, i);
+
+         if (!solver_rulecmp(solv, r, sr))
+           memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
+         else if (sr->p)
+           solver_disablerule(solv, sr);       /* disable feature rule for now */
+       }
+      /* consistency check: we added a rule for _every_ installed solvable */
+      assert(solv->nrules - solv->updaterules == installed->end - installed->start);
+    }
+  solv->updaterules_end = solv->nrules;
+
+
+  /*
+   * now add all job rules
+   */
+
+  solv->jobrules = solv->nrules;
+  for (i = 0; i < job->count; i += 2)
+    {
+      oldnrules = solv->nrules;
+
+      if (i && i == solv->pooljobcnt)
+        POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
+      how = job->elements[i];
+      what = job->elements[i + 1];
+      weak = how & SOLVER_WEAK;
+      select = how & SOLVER_SELECTMASK;
+      switch (how & SOLVER_JOBMASK)
+       {
+       case SOLVER_INSTALL:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
+         if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
+           map_grow(&solv->cleandepsmap, installed->end - installed->start);
+         if (select == SOLVER_SOLVABLE)
+           {
+             p = what;
+             d = 0;
+           }
+#ifdef ENABLE_COMPLEX_DEPS
+         else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what))
+           {
+             if (add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? CPLXDEPS_NAME : 0, i, weak))
+               if (how & SOLVER_FORCEBEST)
+                 hasbestinstalljob = 1;
+             break;
+           }
+#endif
+         else
+           {
+             queue_empty(&q);
+             FOR_JOB_SELECT(p, pp, select, what)
+               queue_push(&q, p);
+             if (!q.count)
+               {
+                 if (select == SOLVER_SOLVABLE_ONE_OF)
+                   break;      /* ignore empty installs */
+                 /* no candidate found or unsupported, make this an impossible rule */
+                 queue_push(&q, -SYSTEMSOLVABLE);
+               }
+             p = queue_shift(&q);      /* get first candidate */
+             d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
+           }
+         /* force install of namespace supplements hack */
+         if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
+           {
+             Reldep *rd = GETRELDEP(pool, what);
+             if (rd->flags == REL_NAMESPACE)
+               {
+                 p = SYSTEMSOLVABLE;
+                 if (!solv->installsuppdepq)
+                   {
+                     solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
+                     queue_init(solv->installsuppdepq);
+                   }
+                 queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
+               }
+           }
+         solver_addjobrule(solv, p, 0, d, i, weak);
+          if (how & SOLVER_FORCEBEST)
+           hasbestinstalljob = 1;
+         break;
+       case SOLVER_ERASE:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
+         if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
+           map_grow(&solv->cleandepsmap, installed->end - installed->start);
+         /* specific solvable: by id or by nevra */
+         name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
+         name_s = 0;
+         if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
+           {
+             FOR_POOL_SOLVABLES(p)
+               solver_addjobrule(solv, -p, 0, 0, i, weak);
+           }
+         else if (select == SOLVER_SOLVABLE_REPO)
+           {
+             Repo *repo = pool_id2repo(pool, what);
+             if (repo)
+               {
+                 FOR_REPO_SOLVABLES(repo, p, s)
+                   solver_addjobrule(solv, -p, 0, 0, i, weak);
+               }
+           }
+#ifdef ENABLE_COMPLEX_DEPS
+         else if ((select == SOLVER_SOLVABLE_PROVIDES || select == SOLVER_SOLVABLE_NAME) && pool_is_complex_dep(pool, what))
+           {
+             /* no special "erase a specific solvable" handling? */
+             add_complex_jobrules(solv, what, select == SOLVER_SOLVABLE_NAME ? (CPLXDEPS_NAME | CPLXDEPS_TODNF | CPLXDEPS_INVERT) : (CPLXDEPS_TODNF | CPLXDEPS_INVERT), i, weak);
+             break;
+           }
+#endif
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             s = pool->solvables + p;
+             if (installed && s->repo == installed)
+               {
+                 name = !name ? s->name : -1;
+                 name_s = s;
+               }
+             solver_addjobrule(solv, -p, 0, 0, i, weak);
+           }
+         /* special case for "erase a specific solvable": we also
+          * erase all other solvables with that name, so that they
+          * don't get picked up as replacement.
+          * name is > 0 if exactly one installed solvable matched.
+          */
+         /* XXX: look also at packages that obsolete this package? */
+         if (name > 0)
+           {
+             int j, k;
+             k = solv->nrules;
+             FOR_PROVIDES(p, pp, name)
+               {
+                 s = pool->solvables + p;
+                 if (s->name != name)
+                   continue;
+                 /* keep other versions installed */
+                 if (s->repo == installed)
+                   continue;
+                 /* keep installcandidates of other jobs */
+                 if (MAPTST(&installcandidatemap, p))
+                   continue;
+                 if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, name_s, s))
+                   continue;
+                 /* don't add the same rule twice */
+                 for (j = oldnrules; j < k; j++)
+                   if (solv->rules[j].p == -p)
+                     break;
+                 if (j == k)
+                   solver_addjobrule(solv, -p, 0, 0, i, weak); /* remove by id */
+               }
+           }
+         break;
+
+       case SOLVER_UPDATE:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_VERIFY:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_WEAKENDEPS:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
+         if (select != SOLVER_SOLVABLE)
+           break;
+         s = pool->solvables + what;
+         weaken_solvable_deps(solv, what);
+         break;
+       case SOLVER_MULTIVERSION:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %smultiversion %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_LOCK:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
+         if (select == SOLVER_SOLVABLE_ALL)
+           {
+             FOR_POOL_SOLVABLES(p)
+               solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
+           }
+          else if (select == SOLVER_SOLVABLE_REPO)
+           {
+             Repo *repo = pool_id2repo(pool, what);
+             if (repo)
+               {
+                 FOR_REPO_SOLVABLES(repo, p, s)
+                   solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
+               }
+           }
+         FOR_JOB_SELECT(p, pp, select, what)
+           solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
+         break;
+       case SOLVER_DISTUPGRADE:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_DROP_ORPHANED:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_USERINSTALLED:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_ALLOWUNINSTALL:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: allowuninstall %s\n", solver_select2str(pool, select, what));
+         break;
+       case SOLVER_FAVOR:
+       case SOLVER_DISFAVOR:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s %s\n", (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? "favor" : "disfavor", solver_select2str(pool, select, what));
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             int j;
+             if (!solv->favorq)
+               {
+                 solv->favorq = solv_calloc(1, sizeof(Queue));
+                 queue_init(solv->favorq);
+               }
+             j = solv->favorq->count + 1;
+             queue_push2(solv->favorq, p, (how & SOLVER_JOBMASK) == SOLVER_FAVOR ? j : -j);
+           }
+         break;
+       default:
+         POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
+         break;
+       }
+       
+      IF_POOLDEBUG (SOLV_DEBUG_JOB)
+       {
+         int j;
+         if (solv->nrules == oldnrules)
+           POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
+         for (j = oldnrules; j < solv->nrules; j++)
+           {
+             POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
+             solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
+           }
+       }
+    }
+  assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
+  solv->jobrules_end = solv->nrules;
+
+  /* transform favorq into two maps */
+  if (solv->favorq)
+    setup_favormaps(solv);
+
+  /* now create infarch and dup rules */
+  if (!solv->noinfarchcheck)
+    solver_addinfarchrules(solv, &addedmap);
+  else
+    solv->infarchrules = solv->infarchrules_end = solv->nrules;
+
+  if (solv->dupinvolvedmap_all || solv->dupinvolvedmap.size)
+    solver_addduprules(solv, &addedmap);
+  else
+    solv->duprules = solv->duprules_end = solv->nrules;
+
+#ifdef ENABLE_LINKED_PKGS
+  if (solv->instbuddy && solv->updatemap.size)
+    extend_updatemap_to_buddies(solv);
+#endif
+
+  if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
+    solver_addbestrules(solv, hasbestinstalljob);
+  else
+    solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules;
+
+  if (needduprules)
+    solver_freedupmaps(solv);  /* no longer needed */
+
+  if (solv->do_yum_obsoletes)
+    solver_addyumobsrules(solv);
+  else
+    solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
+
+  if (1)
+    solver_addchoicerules(solv);
+  else
+    solv->choicerules = solv->choicerules_end = solv->nrules;
+
+  if (0)
+    {
+      for (i = solv->featurerules; i < solv->nrules; i++)
+        solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
+    }
+  /* all rules created
+   * --------------------------------------------------------------
+   * prepare for solving
+   */
+
+  /* free unneeded memory */
+  map_free(&addedmap);
+  map_free(&installcandidatemap);
+  queue_free(&q);
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
+
+  /* create weak map */
+  if (solv->weakruleq.count || solv->recommendsruleq)
+    {
+      map_grow(&solv->weakrulemap, solv->nrules);
+      for (i = 0; i < solv->weakruleq.count; i++)
+       {
+         p = solv->weakruleq.elements[i];
+         MAPSET(&solv->weakrulemap, p);
+       }
+      if (solv->recommendsruleq)
+       {
+         for (i = 0; i < solv->recommendsruleq->count; i++)
+           {
+             p = solv->recommendsruleq->elements[i];
+             MAPSET(&solv->weakrulemap, p);
+           }
+       }
+    }
+
+  /* enable cleandepsmap creation if we have updatepkgs */
+  if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
+    map_grow(&solv->cleandepsmap, installed->end - installed->start);
+  /* no mistakes */
+  if (solv->cleandeps_mistakes)
+    {
+      queue_free(solv->cleandeps_mistakes);
+      solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
+    }
+
+  /* all new rules are learnt after this point */
+  solv->learntrules = solv->nrules;
+
+  /* create watches chains */
+  makewatches(solv);
+
+  /* create assertion index. it is only used to speed up
+   * makeruledecsions() a bit */
+  for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
+    if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
+      queue_push(&solv->ruleassertions, i);
+
+  /* disable update rules that conflict with our job */
+  solver_disablepolicyrules(solv);
+
+  /* break orphans if requested */
+  if (solv->process_orphans && solv->orphaned.count && solv->break_orphans)
+    solver_breakorphans(solv);
+
+  /*
+   * ********************************************
+   * solve!
+   * ********************************************
+   */
+
+  now = solv_timems(0);
+  solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
+
+  /*
+   * prepare solution queue if there were problems
+   */
+  solver_prepare_solutions(solv);
+
+  POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
+
+  /* return number of problems */
+  return solv->problems.count ? solv->problems.count / 2 : 0;
+}
+
+Transaction *
+solver_create_transaction(Solver *solv)
+{
+  return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->multiversion);
+}
+
+void solver_get_orphaned(Solver *solv, Queue *orphanedq)
+{
+  queue_free(orphanedq);
+  queue_init_clone(orphanedq, &solv->orphaned);
+}
+
+void solver_get_cleandeps(Solver *solv, Queue *cleandepsq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Solvable *s;
+  Rule *r;
+  Id p, pp, pr;
+
+  queue_empty(cleandepsq);
+  if (!installed || !solv->cleandepsmap.size)
+    return;
+  FOR_REPO_SOLVABLES(installed, p, s)
+    {
+      if (!MAPTST(&solv->cleandepsmap, p - installed->start) || solv->decisionmap[p] >= 0)
+       continue;
+      /* now check the update rule */
+      r = solv->rules + solv->updaterules + (p - solv->installed->start);
+      if (r->p)
+       {
+         FOR_RULELITERALS(pr, pp, r)
+           if (solv->decisionmap[pr] > 0)
+             break;
+         if (pr)
+           continue;
+       }
+      queue_push(cleandepsq, p);
+    }
+}
+
+void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
+{
+  Pool *pool = solv->pool;
+  Queue redoq, disabledq;
+  int goterase, i;
+  Solvable *s;
+  Rule *r;
+  Map obsmap;
+
+  if (!recommendationsq && !suggestionsq)
+    return;
+
+  map_init(&obsmap, pool->nsolvables);
+  if (solv->installed)
+    {
+      Id obs, *obsp, p, po, ppo;
+      for (p = solv->installed->start; p < solv->installed->end; p++)
+       {
+         s = pool->solvables + p;
+         if (s->repo != solv->installed || !s->obsoletes)
+           continue;
+         if (solv->decisionmap[p] <= 0)
+           continue;
+         if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
+           continue;
+         obsp = s->repo->idarraydata + s->obsoletes;
+         /* foreach obsoletes */
+         while ((obs = *obsp++) != 0)
+           FOR_PROVIDES(po, ppo, obs)
+             MAPSET(&obsmap, po);
+       }
+    }
+
+  queue_init(&redoq);
+  queue_init(&disabledq);
+  goterase = 0;
+  /* disable all erase jobs (including weak "keep uninstalled" rules) */
+  for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
+    {
+      if (r->d < 0)    /* disabled ? */
+       continue;
+      if (r->p >= 0)   /* install job? */
+       continue;
+      queue_push(&disabledq, i);
+      solver_disablerule(solv, r);
+      goterase++;
+    }
+
+  if (goterase)
+    {
+      enabledisablelearntrules(solv);
+      removedisabledconflicts(solv, &redoq);
+    }
+
+  /*
+   * find recommended packages
+   */
+  if (recommendationsq)
+    {
+      Id rec, *recp, p, pp;
+
+      queue_empty(recommendationsq);
+      /* create map of all recommened packages */
+      solv->recommends_index = -1;
+      MAPZERO(&solv->recommendsmap);
+
+      /* put all packages the solver already chose in the map */
+      for (i = 1; i < solv->decisionq.count; i++)
+        if ((p = solv->decisionq.elements[i]) > 0 && solv->decisionq_why.elements[i] == 0)
+         {
+           if (solv->decisionq_reason.elements[solv->decisionmap[p]] == SOLVER_REASON_WEAKDEP)
+             MAPSET(&solv->recommendsmap, p);
+         }
+
+      for (i = 0; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         if (p < 0)
+           continue;
+         s = pool->solvables + p;
+         if (s->recommends)
+           {
+             recp = s->repo->idarraydata + s->recommends;
+             while ((rec = *recp++) != 0)
+               {
+#ifdef ENABLE_COMPLEX_DEPS
+                 if (pool_is_complex_dep(pool, rec))
+                   {
+                     do_complex_recommendations(solv, rec, &solv->recommendsmap, noselected);
+                     continue;
+                   }
+#endif
+                 FOR_PROVIDES(p, pp, rec)
+                   if (solv->decisionmap[p] > 0)
+                     break;
+                 if (p)
+                   {
+                     if (!noselected)
+                       {
+                         FOR_PROVIDES(p, pp, rec)
+                           if (solv->decisionmap[p] > 0)
+                             MAPSET(&solv->recommendsmap, p);
+                       }
+                     continue; /* p != 0: already fulfilled */
+                   }
+                 FOR_PROVIDES(p, pp, rec)
+                   MAPSET(&solv->recommendsmap, p);
+               }
+           }
+       }
+      for (i = 1; i < pool->nsolvables; i++)
+       {
+         if (solv->decisionmap[i] < 0)
+           continue;
+         if (solv->decisionmap[i] > 0 && noselected)
+           continue;
+          if (MAPTST(&obsmap, i))
+           continue;
+         s = pool->solvables + i;
+         if (!MAPTST(&solv->recommendsmap, i))
+           {
+             if (!s->supplements)
+               continue;
+             if (!pool_installable(pool, s))
+               continue;
+             if (!solver_is_supplementing(solv, s))
+               continue;
+           }
+         queue_push(recommendationsq, i);
+       }
+      /* we use MODE_SUGGEST here so that repo prio is ignored */
+      policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
+    }
+
+  /*
+   * find suggested packages
+   */
+
+  if (suggestionsq)
+    {
+      Id sug, *sugp, p, pp;
+
+      queue_empty(suggestionsq);
+      /* create map of all suggests that are still open */
+      solv->recommends_index = -1;
+      MAPZERO(&solv->suggestsmap);
+      for (i = 0; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         if (p < 0)
+           continue;
+         s = pool->solvables + p;
+         if (s->suggests)
+           {
+             sugp = s->repo->idarraydata + s->suggests;
+             while ((sug = *sugp++) != 0)
+               {
+#ifdef ENABLE_COMPLEX_DEPS
+                 if (pool_is_complex_dep(pool, sug))
+                   {
+                     do_complex_recommendations(solv, sug, &solv->suggestsmap, noselected);
+                     continue;
+                   }
+#endif
+                 FOR_PROVIDES(p, pp, sug)
+                   if (solv->decisionmap[p] > 0)
+                     break;
+                 if (p)
+                   {
+                     if (!noselected)
+                       {
+                         FOR_PROVIDES(p, pp, sug)
+                           if (solv->decisionmap[p] > 0)
+                             MAPSET(&solv->suggestsmap, p);
+                       }
+                     continue; /* already fulfilled */
+                   }
+                 FOR_PROVIDES(p, pp, sug)
+                   MAPSET(&solv->suggestsmap, p);
+               }
+           }
+       }
+      for (i = 1; i < pool->nsolvables; i++)
+       {
+         if (solv->decisionmap[i] < 0)
+           continue;
+         if (solv->decisionmap[i] > 0 && noselected)
+           continue;
+          if (MAPTST(&obsmap, i))
+           continue;
+         s = pool->solvables + i;
+         if (!MAPTST(&solv->suggestsmap, i))
+           {
+             if (!s->enhances)
+               continue;
+             if (!pool_installable(pool, s))
+               continue;
+             if (!solver_is_enhancing(solv, s))
+               continue;
+           }
+         queue_push(suggestionsq, i);
+       }
+      policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
+    }
+
+  /* undo removedisabledconflicts */
+  if (redoq.count)
+    undo_removedisabledconflicts(solv, &redoq);
+  queue_free(&redoq);
+
+  /* undo job rule disabling */
+  for (i = 0; i < disabledq.count; i++)
+    solver_enablerule(solv, solv->rules + disabledq.elements[i]);
+  queue_free(&disabledq);
+  map_free(&obsmap);
+}
+
+
+/***********************************************************************/
+/* disk usage computations */
+
+/*-------------------------------------------------------------------
+ *
+ * calculate DU changes
+ */
+
+void
+solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
+{
+  Map installedmap;
+
+  solver_create_state_maps(solv, &installedmap, 0);
+  pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
+  map_free(&installedmap);
+}
+
+
+/*-------------------------------------------------------------------
+ *
+ * calculate changes in install size
+ */
+
+int
+solver_calc_installsizechange(Solver *solv)
+{
+  Map installedmap;
+  int change;
+
+  solver_create_state_maps(solv, &installedmap, 0);
+  change = pool_calc_installsizechange(solv->pool, &installedmap);
+  map_free(&installedmap);
+  return change;
+}
+
+void
+solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
+{
+  pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
+}
+
+/*-------------------------------------------------------------------
+ *
+ * decision introspection
+ */
+
+int
+solver_get_decisionlevel(Solver *solv, Id p)
+{
+  return solv->decisionmap[p];
+}
+
+void
+solver_get_decisionqueue(Solver *solv, Queue *decisionq)
+{
+  queue_free(decisionq);
+  queue_init_clone(decisionq, &solv->decisionq);
+}
+
+int
+solver_get_lastdecisionblocklevel(Solver *solv)
+{
+  Id p;
+  if (solv->decisionq.count == 0)
+    return 0;
+  p = solv->decisionq.elements[solv->decisionq.count - 1];
+  if (p < 0)
+    p = -p;
+  return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
+}
+
+void
+solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
+{
+  Id p;
+  int i;
+
+  queue_empty(decisionq);
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p < 0)
+       p = -p;
+      if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
+        break;
+    }
+  if (i == solv->decisionq.count)
+    return;
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p < 0)
+       p = -p;
+      if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
+        queue_push(decisionq, p);
+      else
+        break;
+    }
+}
+
+int
+solver_describe_decision(Solver *solv, Id p, Id *infop)
+{
+  int i;
+  Id pp, why;
+
+  if (infop)
+    *infop = 0;
+  if (!solv->decisionmap[p])
+    return SOLVER_REASON_UNRELATED;
+  pp = solv->decisionmap[p] < 0 ? -p : p;
+  for (i = 0; i < solv->decisionq.count; i++)
+    if (solv->decisionq.elements[i] == pp)
+      break;
+  if (i == solv->decisionq.count)      /* just in case... */
+    return SOLVER_REASON_UNRELATED;
+  why = solv->decisionq_why.elements[i];
+  if (infop)
+    *infop = why > 0 ? why : -why;
+  if (why > 0)
+    return SOLVER_REASON_UNIT_RULE;
+  i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
+  return solv->decisionq_reason.elements[i];
+}
+
+
+void
+solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
+{
+  Pool *pool = solv->pool;
+  int i;
+  int level = solv->decisionmap[p];
+  int decisionno;
+  Solvable *s;
+
+  queue_empty(whyq);
+  if (level < 0)
+    return;    /* huh? */
+  for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
+    if (solv->decisionq.elements[decisionno] == p)
+      break;
+  if (decisionno == solv->decisionq.count)
+    return;    /* huh? */
+  i = solv->decisionmap[p] >= 0 ? solv->decisionmap[p] : -solv->decisionmap[p];
+  if (solv->decisionq_reason.elements[i] != SOLVER_REASON_WEAKDEP)
+    return;    /* huh? */
+
+  /* 1) list all packages that recommend us */
+  for (i = 1; i < pool->nsolvables; i++)
+    {
+      Id *recp, rec, pp2, p2;
+      if (solv->decisionmap[i] <= 0 || solv->decisionmap[i] >= level)
+       continue;
+      s = pool->solvables + i;
+      if (!s->recommends)
+       continue;
+      if (!solv->addalreadyrecommended && s->repo == solv->installed)
+       continue;
+      recp = s->repo->idarraydata + s->recommends;
+      while ((rec = *recp++) != 0)
+       {
+         int found = 0;
+         FOR_PROVIDES(p2, pp2, rec)
+           {
+             if (p2 == p)
+               found = 1;
+             else
+               {
+                 /* if p2 is already installed, this recommends is ignored */
+                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
+                   break;
+               }
+           }
+         if (!p2 && found)
+           {
+             queue_push(whyq, SOLVER_REASON_RECOMMENDED);
+             queue_push2(whyq, i, rec);
+           }
+       }
+    }
+  /* 2) list all supplements */
+  s = pool->solvables + p;
+  if (s->supplements && level > 0)
+    {
+      Id *supp, sup, pp2, p2;
+      /* this is a hack. to use solver_dep_fulfilled we temporarily clear
+       * everything above our level in the decisionmap */
+      for (i = decisionno; i < solv->decisionq.count; i++ )
+       {
+         p2 = solv->decisionq.elements[i];
+         if (p2 > 0)
+           solv->decisionmap[p2] = -solv->decisionmap[p2];
+       }
+      supp = s->repo->idarraydata + s->supplements;
+      while ((sup = *supp++) != 0)
+       if (solver_dep_fulfilled(solv, sup))
+         {
+           int found = 0;
+           /* let's see if this is an easy supp */
+           FOR_PROVIDES(p2, pp2, sup)
+             {
+               if (!solv->addalreadyrecommended && solv->installed)
+                 {
+                   if (pool->solvables[p2].repo == solv->installed)
+                     continue;
+                 }
+               if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
+                 {
+                   queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
+                   queue_push2(whyq, p2, sup);
+                   found = 1;
+                 }
+             }
+           if (!found)
+             {
+               /* hard case, just note dependency with no package */
+               queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
+               queue_push2(whyq, 0, sup);
+             }
+         }
+      for (i = decisionno; i < solv->decisionq.count; i++)
+       {
+         p2 = solv->decisionq.elements[i];
+         if (p2 > 0)
+           solv->decisionmap[p2] = -solv->decisionmap[p2];
+       }
+    }
+}
+
+void
+pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
+{
+  Id p, pp;
+  how &= SOLVER_SELECTMASK;
+  queue_empty(pkgs);
+  if (how == SOLVER_SOLVABLE_ALL)
+    {
+      FOR_POOL_SOLVABLES(p)
+        queue_push(pkgs, p);
+    }
+  else if (how == SOLVER_SOLVABLE_REPO)
+    {
+      Repo *repo = pool_id2repo(pool, what);
+      Solvable *s;
+      if (repo)
+       {
+         FOR_REPO_SOLVABLES(repo, p, s)
+           queue_push(pkgs, p);
+       }
+    }
+  else
+    {
+      FOR_JOB_SELECT(p, pp, how, what)
+       queue_push(pkgs, p);
+    }
+}
+
+int
+pool_isemptyupdatejob(Pool *pool, Id how, Id what)
+{
+  Id p, pp, pi, pip;
+  Id select = how & SOLVER_SELECTMASK;
+  if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
+    return 0;
+  if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
+    return 0;
+  if (!pool->installed)
+    return 1;
+  FOR_JOB_SELECT(p, pp, select, what)
+    if (pool->solvables[p].repo == pool->installed)
+      return 0;
+  /* hard work */
+  FOR_JOB_SELECT(p, pp, select, what)
+    {
+      Solvable *s = pool->solvables + p;
+      FOR_PROVIDES(pi, pip, s->name)
+       {
+         Solvable *si = pool->solvables + pi;
+         if (si->repo != pool->installed || si->name != s->name)
+           continue;
+         return 0;
+       }
+      if (s->obsoletes)
+       {
+         Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(pi, pip, obs)
+               {
+                 Solvable *si = pool->solvables + pi;
+                 if (si->repo != pool->installed)
+                   continue;
+                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
+                   continue;
+                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
+                   continue;
+                 return 0;
+               }
+           }
+       }
+    }
+  return 1;
+}
+
+int
+solver_alternatives_count(Solver *solv)
+{
+  Id *elements = solv->branches.elements;
+  int res, count;
+  for (res = 0, count = solv->branches.count; count; res++)
+    count -= elements[count - 2];
+  return res;
+}
+
+int
+solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp)
+{
+  int cnt = solver_alternatives_count(solv);
+  int count = solv->branches.count;
+  Id *elements = solv->branches.elements;
+  if (choices)
+    queue_empty(choices);
+  if (alternative <= 0 || alternative > cnt)
+    return 0;
+  elements += count;
+  for (; cnt > alternative; cnt--)
+    elements -= elements[-2];
+  if (levelp)
+    *levelp = elements[-1];
+  if (fromp)
+    *fromp = elements[-4];
+  if (idp)
+    *idp = elements[-3];
+  if (chosenp)
+    {
+      int i;
+      *chosenp = 0;
+      for (i = elements[-2]; i > 4; i--)
+       {
+         Id p = -elements[-i];
+         if (p > 0 && solv->decisionmap[p] == elements[-1] + 1)
+           {
+             *chosenp = p;
+             break;
+           }
+       }
+    }
+  if (choices)
+    queue_insertn(choices, 0, elements[-2] - 4, elements - elements[-2]);
+  return elements[-4] ? SOLVER_ALTERNATIVE_TYPE_RECOMMENDS : SOLVER_ALTERNATIVE_TYPE_RULE;
+}
+
+const char *
+solver_select2str(Pool *pool, Id select, Id what)
+{
+  const char *s;
+  char *b;
+  select &= SOLVER_SELECTMASK;
+  if (select == SOLVER_SOLVABLE)
+    return pool_solvid2str(pool, what);
+  if (select == SOLVER_SOLVABLE_NAME)
+    return pool_dep2str(pool, what);
+  if (select == SOLVER_SOLVABLE_PROVIDES)
+    {
+      s = pool_dep2str(pool, what);
+      b = pool_alloctmpspace(pool, 11 + strlen(s));
+      sprintf(b, "providing %s", s);
+      return b;
+    }
+  if (select == SOLVER_SOLVABLE_ONE_OF)
+    {
+      Id p;
+      b = 0;
+      while ((p = pool->whatprovidesdata[what++]) != 0)
+       {
+         s = pool_solvid2str(pool, p);
+         if (b)
+           b = pool_tmpappend(pool, b, ", ", s);
+         else
+           b = pool_tmpjoin(pool, s, 0, 0);
+         pool_freetmpspace(pool, s);
+       }
+      return b ? b : "nothing";
+    }
+  if (select == SOLVER_SOLVABLE_REPO)
+    {
+      b = pool_alloctmpspace(pool, 20);
+      sprintf(b, "repo #%d", what);
+      return b;
+    }
+  if (select == SOLVER_SOLVABLE_ALL)
+    return "all packages";
+  return "unknown job select";
+}
+
+const char *
+pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
+{
+  Id select = how & SOLVER_SELECTMASK;
+  const char *strstart = 0, *strend = 0;
+  char *s;
+  int o;
+
+  switch (how & SOLVER_JOBMASK)
+    {
+    case SOLVER_NOOP:
+      return "do nothing";
+    case SOLVER_INSTALL:
+      if (select == SOLVER_SOLVABLE && pool->installed && pool->solvables[what].repo == pool->installed)
+       strstart = "keep ", strend = " installed";
+      else if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_NAME)
+       strstart = "install ";
+      else if (select == SOLVER_SOLVABLE_PROVIDES)
+       strstart = "install a package ";
+      else
+       strstart = "install one of ";
+      break;
+    case SOLVER_ERASE:
+      if (select == SOLVER_SOLVABLE && !(pool->installed && pool->solvables[what].repo == pool->installed))
+       strstart = "keep ", strend = " uninstalled";
+      else if (select == SOLVER_SOLVABLE_PROVIDES)
+       strstart = "deinstall all packages ";
+      else
+       strstart = "deinstall ";
+      break;
+    case SOLVER_UPDATE:
+      strstart = "update ";
+      break;
+    case SOLVER_WEAKENDEPS:
+      strstart = "weaken deps of ";
+      break;
+    case SOLVER_MULTIVERSION:
+      strstart = "multi version ";
+      break;
+    case SOLVER_LOCK:
+      strstart = "lock ";
+      break;
+    case SOLVER_DISTUPGRADE:
+      strstart = "dist upgrade ";
+      break;
+    case SOLVER_VERIFY:
+      strstart = "verify ";
+      break;
+    case SOLVER_DROP_ORPHANED:
+      strstart = "deinstall ", strend = " if orphaned";
+      break;
+    case SOLVER_USERINSTALLED:
+      strstart = "regard ", strend = " as userinstalled";
+      break;
+    case SOLVER_ALLOWUNINSTALL:
+      strstart = "allow deinstallation of ";
+      break;
+    case SOLVER_FAVOR:
+      strstart = "favor ";
+      break;
+    case SOLVER_DISFAVOR:
+      strstart = "disfavor ";
+      break;
+    default:
+      strstart = "unknown job ";
+      break;
+    }
+  s = pool_tmpjoin(pool, strstart, solver_select2str(pool, select, what), strend);
+  how &= flagmask;
+  if ((how & ~(SOLVER_SELECTMASK|SOLVER_JOBMASK)) == 0)
+    return s;
+  o = strlen(s);
+  s = pool_tmpappend(pool, s, " ", 0);
+  if (how & SOLVER_WEAK)
+    s = pool_tmpappend(pool, s, ",weak", 0);
+  if (how & SOLVER_ESSENTIAL)
+    s = pool_tmpappend(pool, s, ",essential", 0);
+  if (how & SOLVER_CLEANDEPS)
+    s = pool_tmpappend(pool, s, ",cleandeps", 0);
+  if (how & SOLVER_ORUPDATE)
+    s = pool_tmpappend(pool, s, ",orupdate", 0);
+  if (how & SOLVER_FORCEBEST)
+    s = pool_tmpappend(pool, s, ",forcebest", 0);
+  if (how & SOLVER_TARGETED)
+    s = pool_tmpappend(pool, s, ",targeted", 0);
+  if (how & SOLVER_SETEV)
+    s = pool_tmpappend(pool, s, ",setev", 0);
+  if (how & SOLVER_SETEVR)
+    s = pool_tmpappend(pool, s, ",setevr", 0);
+  if (how & SOLVER_SETARCH)
+    s = pool_tmpappend(pool, s, ",setarch", 0);
+  if (how & SOLVER_SETVENDOR)
+    s = pool_tmpappend(pool, s, ",setvendor", 0);
+  if (how & SOLVER_SETREPO)
+    s = pool_tmpappend(pool, s, ",setrepo", 0);
+  if (how & SOLVER_SETNAME)
+    s = pool_tmpappend(pool, s, ",setname", 0);
+  if (how & SOLVER_NOAUTOSET)
+    s = pool_tmpappend(pool, s, ",noautoset", 0);
+  if (s[o + 1] != ',')
+    s = pool_tmpappend(pool, s, ",?", 0);
+  s[o + 1] = '[';
+  return pool_tmpappend(pool, s, "]", 0);
+}
+
+const char *
+solver_alternative2str(Solver *solv, int type, Id id, Id from)
+{
+  Pool *pool = solv->pool;
+  if (type == SOLVER_ALTERNATIVE_TYPE_RECOMMENDS)
+    {
+      const char *s = pool_dep2str(pool, id);
+      return pool_tmpappend(pool, s, ", recommended by ", pool_solvid2str(pool, from));
+    }
+  if (type == SOLVER_ALTERNATIVE_TYPE_RULE)
+    {
+      int rtype;
+      Id depfrom, depto, dep;
+      char buf[64];
+      if (solver_ruleclass(solv, id) == SOLVER_RULE_CHOICE)
+       id = solver_rule2pkgrule(solv, id);
+      rtype = solver_ruleinfo(solv, id, &depfrom, &depto, &dep);
+      if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
+       {
+         if ((depto & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_PROVIDES)
+           return pool_dep2str(pool, dep);
+         return solver_select2str(pool, depto & SOLVER_SELECTMASK, dep);
+       }
+      if (rtype == SOLVER_RULE_PKG_REQUIRES)
+       {
+         const char *s = pool_dep2str(pool, dep);
+         return pool_tmpappend(pool, s, ", required by ", pool_solvid2str(pool, depfrom));
+       }
+      sprintf(buf, "Rule #%d", id);
+      return pool_tmpjoin(pool, buf, 0, 0);
+    }
+  return "unknown alternative type";
+}
+
diff --git a/libsolv-0.7.2/src/solver.h b/libsolv-0.7.2/src/solver.h
new file mode 100644 (file)
index 0000000..6fc2e9f
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solver.h
+ *
+ */
+
+#ifndef LIBSOLV_SOLVER_H
+#define LIBSOLV_SOLVER_H
+
+#include "pooltypes.h"
+#include "pool.h"
+#include "repo.h"
+#include "queue.h"
+#include "bitmap.h"
+#include "transaction.h"
+#include "rules.h"
+#include "problems.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct s_Solver {
+  Pool *pool;                          /* back pointer to pool */
+  Queue job;                           /* copy of the job we're solving */
+
+  int (*solution_callback)(struct s_Solver *solv, void *data);
+  void *solution_callback_data;
+
+  int pooljobcnt;                      /* number of pooljob entries in job queue */
+
+#ifdef LIBSOLV_INTERNAL
+  Repo *installed;                     /* copy of pool->installed */
+
+  /* list of rules, ordered
+   * pkg rules first, then features, updates, jobs, learnt
+   * see start/end offsets below
+   */
+  Rule *rules;                         /* all rules */
+  Id nrules;                           /* [Offset] index of the last rule */
+  Id lastpkgrule;                      /* last package rule we added */
+
+  Queue ruleassertions;                        /* Queue of all assertion rules */
+
+  /* start/end offset for rule 'areas' */
+
+  Id pkgrules_end;                      /* [Offset] dep rules end */
+
+  Id featurerules;                     /* feature rules start/end */
+  Id featurerules_end;
+
+  Id updaterules;                      /* policy rules, e.g. keep packages installed or update. All literals > 0 */
+  Id updaterules_end;
+
+  Id jobrules;                         /* user rules */
+  Id jobrules_end;
+
+  Id infarchrules;                     /* inferior arch rules */
+  Id infarchrules_end;
+
+  Id duprules;                         /* dist upgrade rules */
+  Id duprules_end;
+
+  Id bestrules;                                /* rules from SOLVER_FORCEBEST */
+  Id bestrules_up;                     /* update rule part starts here*/
+  Id bestrules_end;
+  Id *bestrules_pkg;
+
+  Id yumobsrules;                      /* rules from yum obsoletes handling */
+  Id yumobsrules_end;
+  Id *yumobsrules_info;                        /* the dependency for each rule */
+
+  Id choicerules;                      /* choice rules (always weak) */
+  Id choicerules_end;
+  Id *choicerules_ref;
+
+  Id learntrules;                      /* learnt rules, (end == nrules) */
+
+  Map noupdate;                                /* don't try to update these
+                                           installed solvables */
+  Map multiversion;                    /* ignore obsoletes for these (multiinstall) */
+
+  Map updatemap;                       /* bring these installed packages to the newest version */
+  int updatemap_all;                   /* bring all packages to the newest version */
+
+  Map bestupdatemap;                   /* create best rule for those packages */
+  int bestupdatemap_all;               /* bring all packages to the newest version */
+
+  Map fixmap;                          /* fix these packages */
+  int fixmap_all;                      /* fix all packages */
+
+  Queue weakruleq;                     /* index into 'rules' for weak ones */
+  Map weakrulemap;                     /* map rule# to '1' for weak rules, 1..learntrules */
+
+  Id *watches;                         /* Array of rule offsets
+                                        * watches has nsolvables*2 entries and is addressed from the middle
+                                        * middle-solvable : decision to conflict, offset point to linked-list of rules
+                                        * middle+solvable : decision to install: offset point to linked-list of rules
+                                        */
+
+  Queue ruletojob;                      /* index into job queue: jobs for which a rule exits */
+
+  /* our decisions: */
+  Queue decisionq;                      /* >0:install, <0:remove/conflict */
+  Queue decisionq_why;                 /* index of rule, Offset into rules */
+  Queue decisionq_reason;              /* reason for decision, indexed by level */
+
+  Id *decisionmap;                     /* map for all available solvables,
+                                        * = 0: undecided
+                                        * > 0: level of decision when installed,
+                                        * < 0: level of decision when conflict */
+
+  /* learnt rule history */
+  Queue learnt_why;
+  Queue learnt_pool;
+
+  Queue branches;
+  int propagate_index;                  /* index into decisionq for non-propagated decisions */
+
+  Queue problems;                       /* list of lists of conflicting rules, < 0 for job rules */
+  Queue solutions;                     /* refined problem storage space */
+
+  Queue orphaned;                      /* orphaned packages (to be removed?) */
+
+  int stats_learned;                   /* statistic */
+  int stats_unsolvable;                        /* statistic */
+
+  Map recommendsmap;                   /* recommended packages from decisionmap */
+  Map suggestsmap;                     /* suggested packages from decisionmap */
+  int recommends_index;                        /* recommendsmap/suggestsmap is created up to this level */
+  Queue *recommendscplxq;
+  Queue *suggestscplxq;
+
+  Id *obsoletes;                       /* obsoletes for each installed solvable */
+  Id *obsoletes_data;                  /* data area for obsoletes */
+  Id *specialupdaters;                 /* updaters for packages with a limited update rule */
+
+  /*-------------------------------------------------------------------------------------------------------------
+   * Solver configuration
+   *-------------------------------------------------------------------------------------------------------------*/
+
+  int allowdowngrade;                  /* allow to downgrade installed solvable */
+  int allownamechange;                 /* allow to change name of installed solvables */
+  int allowarchchange;                 /* allow to change architecture of installed solvables */
+  int allowvendorchange;               /* allow to change vendor of installed solvables */
+  int allowuninstall;                  /* allow removal of installed solvables */
+  int noupdateprovide;                 /* true: update packages needs not to provide old package */
+  int needupdateprovide;               /* true: update packages must provide old package */
+  int dosplitprovides;                 /* true: consider legacy split provides */
+  int dontinstallrecommended;          /* true: do not install recommended packages */
+  int addalreadyrecommended;           /* true: also install recommended packages that were already recommended by the installed packages */
+  int dontshowinstalledrecommended;    /* true: do not show recommended packages that are already installed */
+
+  int noinfarchcheck;                  /* true: do not forbid inferior architectures */
+  int keepexplicitobsoletes;           /* true: honor obsoletes during multiinstall */
+  int bestobeypolicy;                  /* true: stay in policy with the best rules */
+  int noautotarget;                    /* true: do not assume targeted for up/dup jobs that contain no installed solvable */
+  int focus_installed;                 /* true: resolve update rules first */
+  int focus_best;                      /* true: resolve job dependencies first */
+  int do_yum_obsoletes;                        /* true: add special yumobs rules */
+  int urpmreorder;                     /* true: do special urpm package reordering */
+  int strongrecommends;                        /* true: create weak rules for recommends */
+  int install_also_updates;            /* true: do not prune install job rules to installed packages */
+  int only_namespace_recommended;      /* true: only install packages recommended by namespace */
+
+  int process_orphans;                 /* true: do special orphan processing */
+  Map dupmap;                          /* dup to those packages */
+  Map dupinvolvedmap;                  /* packages involved in dup process */
+  int dupinvolvedmap_all;              /* all packages are involved */
+  int dup_allowdowngrade;              /* dup mode: allow to downgrade installed solvable */
+  int dup_allownamechange;             /* dup mode: allow to change name of installed solvable */
+  int dup_allowarchchange;             /* dup mode: allow to change architecture of installed solvables */
+  int dup_allowvendorchange;           /* dup mode: allow to change vendor of installed solvables */
+
+  Map droporphanedmap;                 /* packages to drop in dup mode */
+  int droporphanedmap_all;
+
+  Map cleandepsmap;                    /* try to drop these packages as of cleandeps erases */
+
+  Queue *ruleinfoq;                    /* tmp space for solver_ruleinfo() */
+
+  Queue *cleandeps_updatepkgs;         /* packages we update in cleandeps mode */
+  Queue *cleandeps_mistakes;           /* mistakes we made */
+
+  Queue *update_targets;               /* update to specific packages */
+
+  Queue *installsuppdepq;              /* deps from the install namespace provides hack */
+
+  Queue addedmap_deduceq;              /* deduce addedmap from pkg rules */
+  Id *instbuddy;                       /* buddies of installed packages */
+  int keep_orphans;                    /* how to treat orphans */
+  int break_orphans;                   /* how to treat orphans */
+  Queue *brokenorphanrules;            /* broken rules of orphaned packages */
+
+  Map allowuninstallmap;               /* ok to uninstall those */
+  int allowuninstall_all;
+
+  Queue *favorq;
+  Map favormap;                                /* favored / disfavored packages */
+  Map isdisfavormap;
+
+  int installedpos;                    /* for resolve_installed */
+  int do_extra_reordering;             /* reorder for future installed packages */
+
+  Queue *recommendsruleq;              /* pkg rules comming from recommends */
+#endif /* LIBSOLV_INTERNAL */
+};
+
+typedef struct s_Solver Solver;
+
+/*
+ * queue commands
+ */
+
+#define SOLVER_SOLVABLE                        0x01
+#define SOLVER_SOLVABLE_NAME           0x02
+#define SOLVER_SOLVABLE_PROVIDES       0x03
+#define SOLVER_SOLVABLE_ONE_OF         0x04
+#define SOLVER_SOLVABLE_REPO           0x05
+#define SOLVER_SOLVABLE_ALL            0x06
+
+#define SOLVER_SELECTMASK              0xff
+
+#define SOLVER_NOOP                    0x0000
+#define SOLVER_INSTALL                 0x0100
+#define SOLVER_ERASE                   0x0200
+#define SOLVER_UPDATE                  0x0300
+#define SOLVER_WEAKENDEPS                      0x0400
+#define SOLVER_MULTIVERSION            0x0500
+#define SOLVER_LOCK                    0x0600
+#define SOLVER_DISTUPGRADE             0x0700
+#define SOLVER_VERIFY                  0x0800
+#define SOLVER_DROP_ORPHANED           0x0900
+#define SOLVER_USERINSTALLED           0x0a00
+#define SOLVER_ALLOWUNINSTALL          0x0b00
+#define SOLVER_FAVOR                   0x0c00
+#define SOLVER_DISFAVOR                        0x0d00
+
+#define SOLVER_JOBMASK                 0xff00
+
+#define SOLVER_WEAK                    0x010000
+#define SOLVER_ESSENTIAL               0x020000
+#define SOLVER_CLEANDEPS                0x040000
+/* ORUPDATE makes SOLVER_INSTALL not prune to installed
+ * packages, thus updating installed packages */
+#define SOLVER_ORUPDATE                        0x080000
+/* FORCEBEST makes the solver insist on best packages, so
+ * you will get problem reported if the best package is
+ * not installable. This can be used with INSTALL, UPDATE
+ * and DISTUPGRADE */
+#define SOLVER_FORCEBEST               0x100000
+/* TARGETED is used in up/dup jobs to make the solver
+ * treat the specified selection as target packages.
+ * It is automatically assumed if the selection does not
+ * contain an "installed" package unless the
+ * NO_AUTOTARGET solver flag is set */
+#define SOLVER_TARGETED                        0x200000
+/* This (SOLVER_INSTALL) job was automatically added
+ * and thus does not the add to the userinstalled packages */
+#define SOLVER_NOTBYUSER               0x400000
+
+#define SOLVER_SETEV                   0x01000000
+#define SOLVER_SETEVR                  0x02000000
+#define SOLVER_SETARCH                 0x04000000
+#define SOLVER_SETVENDOR               0x08000000
+#define SOLVER_SETREPO                 0x10000000
+#define SOLVER_NOAUTOSET               0x20000000
+#define SOLVER_SETNAME                 0x40000000
+
+#define SOLVER_SETMASK                 0x7f000000
+
+/* legacy */
+#define SOLVER_NOOBSOLETES             SOLVER_MULTIVERSION
+
+#define SOLVER_REASON_UNRELATED                0
+#define SOLVER_REASON_UNIT_RULE                1
+#define SOLVER_REASON_KEEP_INSTALLED   2
+#define SOLVER_REASON_RESOLVE_JOB      3
+#define SOLVER_REASON_UPDATE_INSTALLED 4
+#define SOLVER_REASON_CLEANDEPS_ERASE  5
+#define SOLVER_REASON_RESOLVE          6
+#define SOLVER_REASON_WEAKDEP          7
+#define SOLVER_REASON_RESOLVE_ORPHAN   8
+
+#define SOLVER_REASON_RECOMMENDED      16
+#define SOLVER_REASON_SUPPLEMENTED     17
+
+
+#define SOLVER_FLAG_ALLOW_DOWNGRADE            1
+#define SOLVER_FLAG_ALLOW_ARCHCHANGE           2
+#define SOLVER_FLAG_ALLOW_VENDORCHANGE         3
+#define SOLVER_FLAG_ALLOW_UNINSTALL            4
+#define SOLVER_FLAG_NO_UPDATEPROVIDE           5
+#define SOLVER_FLAG_SPLITPROVIDES              6
+#define SOLVER_FLAG_IGNORE_RECOMMENDED         7
+#define SOLVER_FLAG_ADD_ALREADY_RECOMMENDED    8
+#define SOLVER_FLAG_NO_INFARCHCHECK            9
+#define SOLVER_FLAG_ALLOW_NAMECHANGE           10
+#define SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES    11
+#define SOLVER_FLAG_BEST_OBEY_POLICY           12
+#define SOLVER_FLAG_NO_AUTOTARGET              13
+#define SOLVER_FLAG_DUP_ALLOW_DOWNGRADE                14
+#define SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE       15
+#define SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE     16
+#define SOLVER_FLAG_DUP_ALLOW_NAMECHANGE       17
+#define SOLVER_FLAG_KEEP_ORPHANS               18
+#define SOLVER_FLAG_BREAK_ORPHANS              19
+#define SOLVER_FLAG_FOCUS_INSTALLED            20
+#define SOLVER_FLAG_YUM_OBSOLETES              21
+#define SOLVER_FLAG_NEED_UPDATEPROVIDE         22
+#define SOLVER_FLAG_URPM_REORDER               23
+#define SOLVER_FLAG_FOCUS_BEST                 24
+#define SOLVER_FLAG_STRONG_RECOMMENDS          25
+#define SOLVER_FLAG_INSTALL_ALSO_UPDATES       26
+#define SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED 27
+
+#define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead of ids */
+#define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
+#define GET_USERINSTALLED_NAMEARCH             (1 << 2)        /* package/arch tuples instead of ids */
+
+#define SOLVER_ALTERNATIVE_TYPE_RULE           1
+#define SOLVER_ALTERNATIVE_TYPE_RECOMMENDS     2
+#define SOLVER_ALTERNATIVE_TYPE_SUGGESTS       3
+
+extern Solver *solver_create(Pool *pool);
+extern void solver_free(Solver *solv);
+extern int  solver_solve(Solver *solv, Queue *job);
+extern Transaction *solver_create_transaction(Solver *solv);
+extern int solver_set_flag(Solver *solv, int flag, int value);
+extern int solver_get_flag(Solver *solv, int flag);
+
+extern int  solver_get_decisionlevel(Solver *solv, Id p);
+extern void solver_get_decisionqueue(Solver *solv, Queue *decisionq);
+extern int  solver_get_lastdecisionblocklevel(Solver *solv);
+extern void solver_get_decisionblock(Solver *solv, int level, Queue *decisionq);
+
+extern void solver_get_orphaned(Solver *solv, Queue *orphanedq);
+extern void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected);
+extern void solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered);
+extern void solver_get_userinstalled(Solver *solv, Queue *q, int flags);
+extern void pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags);
+extern void solver_get_cleandeps(Solver *solv, Queue *cleandepsq);
+
+extern int  solver_describe_decision(Solver *solv, Id p, Id *infop);
+extern void solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq);
+
+extern int solver_alternatives_count(Solver *solv);
+extern int solver_get_alternative(Solver *solv, Id alternative, Id *idp, Id *fromp, Id *chosenp, Queue *choices, int *levelp);
+
+extern void solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap);
+extern void solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap);   /* obsolete */
+extern void solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap);
+
+extern void solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps);
+extern int solver_calc_installsizechange(Solver *solv);
+
+extern void pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what);
+extern int  pool_isemptyupdatejob(Pool *pool, Id how, Id what);
+
+extern const char *solver_select2str(Pool *pool, Id select, Id what);
+extern const char *pool_job2str(Pool *pool, Id how, Id what, Id flagmask);
+extern const char *solver_alternative2str(Solver *solv, int type, Id id, Id from);
+
+
+/* iterate over all literals of a rule */
+#define FOR_RULELITERALS(l, pp, r)                             \
+    for (pp = r->d < 0 ? -r->d - 1 : r->d,                     \
+         l = r->p; l; l = (pp <= 0 ? (pp-- ? 0 : r->w2) :      \
+         pool->whatprovidesdata[pp++]))
+
+
+
+
+/* XXX: this currently doesn't work correctly for SOLVER_SOLVABLE_REPO and
+   SOLVER_SOLVABLE_ALL */
+
+/* iterate over all packages selected by a job */
+#define FOR_JOB_SELECT(p, pp, select, what)                                    \
+    if (select == SOLVER_SOLVABLE_REPO || select == SOLVER_SOLVABLE_ALL)       \
+       p = pp = 0;                                                             \
+    else for (pp = (select == SOLVER_SOLVABLE ? 0 :                            \
+               select == SOLVER_SOLVABLE_ONE_OF ? what :                       \
+               pool_whatprovides(pool, what)),                                 \
+         p = (select == SOLVER_SOLVABLE ? what : pool->whatprovidesdata[pp++]); \
+                                        p ; p = pool->whatprovidesdata[pp++])  \
+      if (select == SOLVER_SOLVABLE_NAME &&                                    \
+                       pool_match_nevr(pool, pool->solvables + p, what) == 0)  \
+       continue;                                                               \
+      else
+
+/* weird suse stuff */
+extern void solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_SOLVER_H */
diff --git a/libsolv-0.7.2/src/solver_private.h b/libsolv-0.7.2/src/solver_private.h
new file mode 100644 (file)
index 0000000..406b304
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2011, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solver_private.h - private functions
+ *
+ */
+
+#ifndef LIBSOLV_SOLVER_PRIVATE_H
+#define LIBSOLV_SOLVER_PRIVATE_H
+
+extern void solver_run_sat(Solver *solv, int disablerules, int doweak);
+extern void solver_reset(Solver *solv);
+
+extern int solver_splitprovides(Solver *solv, Id dep, Map *m);
+extern int solver_dep_possible_slow(Solver *solv, Id dep, Map *m);
+extern int solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd);
+extern int solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s);
+extern void solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m);
+extern int solver_is_namespace_dep_slow(Solver *solv, Reldep *rd);
+
+extern void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded);
+extern int solver_check_cleandeps_mistakes(Solver *solv);
+
+
+#define ISSIMPLEDEP(pool, dep) (!ISRELDEP(dep) || GETRELDEP(pool, dep)->flags < 8)
+
+static inline int
+solver_dep_possible(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (!ISSIMPLEDEP(pool, dep))
+    return solver_dep_possible_slow(solv, dep, m);
+  FOR_PROVIDES(p, pp, dep)
+    {  
+      if (MAPTST(m, p))
+        return 1;
+    }
+  return 0;
+}
+
+static inline int
+solver_dep_fulfilled(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR)
+       return solver_dep_fulfilled_cplx(solv, rd);
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+        return solver_splitprovides(solv, rd->evr, 0);
+    }
+  FOR_PROVIDES(p, pp, dep)
+    {
+      if (solv->decisionmap[p] > 0)
+        return 1;
+    }
+  return 0;
+}
+
+static inline int
+solver_is_supplementing(Solver *solv, Solvable *s)
+{
+  Id sup, *supp;
+  if (!s->supplements)
+    return 0;
+  supp = s->repo->idarraydata + s->supplements;
+  while ((sup = *supp++) != 0)
+    if (solver_dep_fulfilled(solv, sup))
+      return 1;
+  return 0;
+}
+
+static inline int
+solver_is_enhancing(Solver *solv, Solvable *s)
+{
+  Id enh, *enhp;
+  if (!s->enhances)
+    return 0;
+  enhp = s->repo->idarraydata + s->enhances;
+  while ((enh = *enhp++) != 0)
+    if (solver_dep_fulfilled(solv, enh))
+      return 1;
+  return 0;
+}
+
+static inline int
+solver_is_namespace_dep(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Reldep *rd;
+  if (!ISRELDEP(dep))
+    return 0;
+  rd = GETRELDEP(pool, dep);
+  if (rd->flags == REL_NAMESPACE)
+    return 1;
+  if (ISRELDEP(rd->name))
+    return solver_is_namespace_dep_slow(solv, rd);
+  if (ISRELDEP(rd->evr))
+    return solver_is_namespace_dep_slow(solv, GETRELDEP(pool, rd->evr));
+  return 0;
+}
+
+#endif /* LIBSOLV_SOLVER_PRIVATE_H */
diff --git a/libsolv-0.7.2/src/solver_util.c b/libsolv-0.7.2/src/solver_util.c
new file mode 100644 (file)
index 0000000..fb17bf4
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solver_util.c
+ *
+ * Dependency solver helper functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "util.h"
+
+
+/*-------------------------------------------------------------------
+ * check if a installed package p is being updated
+ */
+static int
+solver_is_updating(Solver *solv, Id p)
+{
+  /* check if the update rule is true */
+  Pool *pool = solv->pool;
+  Rule *r;
+  Id l, pp;
+  if (solv->decisionmap[p] >= 0)
+    return 0;  /* old package stayed */
+  r = solv->rules + solv->updaterules + (p - solv->installed->start);
+  FOR_RULELITERALS(l, pp, r)
+    if (l > 0 && l != p && solv->decisionmap[l] > 0)
+      return 1;
+  return 0;
+}
+
+/*-------------------------------------------------------------------
+ * handle split provides
+ *
+ * a splitprovides dep looks like
+ *     namespace:splitprovides(pkg REL_WITH path)
+ * and is only true if pkg is installed and contains the specified path.
+ * we also make sure that pkg is selected for an update, otherwise the
+ * update would always be forced onto the user.
+ * Map m is the map used when called from dep_possible.
+ */
+int
+solver_splitprovides(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  Reldep *rd;
+  Solvable *s;
+
+  if (!solv->dosplitprovides || !solv->installed)
+    return 0;
+  if (!ISRELDEP(dep))
+    return 0;
+  rd = GETRELDEP(pool, dep);
+  if (rd->flags != REL_WITH)
+    return 0;
+  /*
+   * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
+   * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
+   * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
+   * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
+   * we filter the package name further down anyway).
+   */
+  if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
+    pp = pool_searchlazywhatprovidesq(pool, rd->evr);
+  else
+    pp = pool_whatprovides(pool, dep);
+  while ((p = pool->whatprovidesdata[pp++]) != 0)
+    {
+      /* here we have packages that provide the correct name and contain the path,
+       * now do extra filtering */
+      s = pool->solvables + p;
+      if (s->repo != solv->installed || s->name != rd->name)
+       continue;
+      /* check if the package is updated. if m is set, we're called from dep_possible */
+      if (m || solver_is_updating(solv, p))
+       return 1;
+    }
+  return 0;
+}
+
+int
+solver_dep_possible_slow(Solver *solv, Id dep, Map *m)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags >= 8)
+         {
+          if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
+            return 1;
+          if (rd->flags == REL_AND)
+            {
+              if (!solver_dep_possible_slow(solv, rd->name, m))
+                return 0;
+              return solver_dep_possible_slow(solv, rd->evr, m);
+            }
+          if (rd->flags == REL_OR)
+            {
+              if (solver_dep_possible_slow(solv, rd->name, m))
+                return 1;
+              return solver_dep_possible_slow(solv, rd->evr, m);
+            }
+          if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+            return solver_splitprovides(solv, rd->evr, m);
+        }
+    }
+  FOR_PROVIDES(p, pp, dep)
+    {
+      if (MAPTST(m, p))
+        return 1;
+    }
+  return 0;
+}
+
+int
+solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
+{
+  Pool *pool = solv->pool;
+  if (rd->flags == REL_COND)
+    {
+      if (ISRELDEP(rd->evr))
+       {
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
+           {
+             if (solver_dep_fulfilled(solv, rd2->name))
+               return solver_dep_fulfilled(solv, rd->name);
+             return solver_dep_fulfilled(solv, rd2->evr);
+           }
+       }
+      if (solver_dep_fulfilled(solv, rd->name))
+       return 1;
+      return !solver_dep_fulfilled(solv, rd->evr);
+    }
+  if (rd->flags == REL_UNLESS)
+    {
+      if (ISRELDEP(rd->evr))
+       {
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
+           {
+             if (!solver_dep_fulfilled(solv, rd2->name))
+               return solver_dep_fulfilled(solv, rd->name);
+             return solver_dep_fulfilled(solv, rd2->evr);
+           }
+       }
+      if (!solver_dep_fulfilled(solv, rd->name))
+       return 0;
+      return !solver_dep_fulfilled(solv, rd->evr);
+    }
+  if (rd->flags == REL_AND)
+    {
+      if (!solver_dep_fulfilled(solv, rd->name))
+       return 0;
+      return solver_dep_fulfilled(solv, rd->evr);
+    }
+  if (rd->flags == REL_OR)
+    {
+      if (solver_dep_fulfilled(solv, rd->name))
+       return 1;
+      return solver_dep_fulfilled(solv, rd->evr);
+    }
+  return 0;
+}
+
+static int
+solver_dep_fulfilled_complex_func(Solver *solv, Reldep *rd, int (*dep_fullfilled)(Solver *, Id))
+{
+  Pool *pool = solv->pool;
+  int r1, r2;
+  if (rd->flags == REL_COND)
+    {
+      if (ISRELDEP(rd->evr))
+       {
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
+           {
+             r1 = dep_fullfilled(solv, rd2->name);
+             if (r1)
+               {
+                 r2 = dep_fullfilled(solv, rd->name);
+                 return r2 && r1 == 2 ? 2 : r2;
+               }
+             return dep_fullfilled(solv, rd2->evr);
+           }
+       }
+      r1 = dep_fullfilled(solv, rd->name);
+      r2 = !dep_fullfilled(solv, rd->evr);
+      if (!r1 && !r2)
+       return 0;
+      return r1 == 2 ? 2 : 1;
+    }
+  if (rd->flags == REL_UNLESS)
+    {
+      if (ISRELDEP(rd->evr))
+       {
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
+           {
+             r1 = dep_fullfilled(solv, rd2->name);
+             if (r1)
+               {
+                 r2 = dep_fullfilled(solv, rd2->evr);
+                 return r2 && r1 == 2 ? 2 : r2;
+               }
+             return dep_fullfilled(solv, rd->name);
+           }
+       }
+      /* A AND NOT(B) */
+      r1 = dep_fullfilled(solv, rd->name);
+      r2 = !dep_fullfilled(solv, rd->evr);
+      if (!r1 || !r2)
+       return 0;
+      return r1 == 2 ? 2 : 1;
+    }
+  if (rd->flags == REL_AND)
+    {
+      r1 = dep_fullfilled(solv, rd->name);
+      if (!r1)
+       return 0;
+      r2 = dep_fullfilled(solv, rd->evr);
+      if (!r2)
+       return 0;
+      return r1 == 2 || r2 == 2 ? 2 : 1;
+    }
+  if (rd->flags == REL_OR)
+    {
+      r1 = dep_fullfilled(solv, rd->name);
+      r2 = dep_fullfilled(solv, rd->evr);
+      if (!r1 && !r2)
+       return 0;
+      return r1 == 2 || r2 == 2 ? 2 : 1;
+    }
+  return 0;
+}
+
+/* mirrors solver_dep_fulfilled, but returns 2 if a new package
+ * was involved */
+static int
+solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  int r;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR)
+       return solver_dep_fulfilled_complex_func(solv, rd, solver_dep_fulfilled_alreadyinstalled);
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+        return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
+      if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
+       {
+         Queue *q = solv->installsuppdepq;
+         int i;
+         for (i = 0; i < q->count; i++)
+           if (q->elements[i] == dep || q->elements[i] == rd->name)
+             return 2;
+       }
+    }
+  r = 0;
+  FOR_PROVIDES(p, pp, dep)
+    if (solv->decisionmap[p] > 0)
+      {
+       Solvable *s = pool->solvables + p;
+       if (s->repo && s->repo != solv->installed)
+         return 2;
+        r = 1;
+      }
+  return r;
+}
+
+static int
+solver_dep_fulfilled_namespace(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  int r = 1;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR)
+       return solver_dep_fulfilled_complex_func(solv, rd, solver_dep_fulfilled_namespace);
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+        return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
+      if (rd->flags == REL_NAMESPACE)
+       r = 2;
+    }
+  FOR_PROVIDES(p, pp, dep)
+    if (solv->decisionmap[p] > 0)
+      return r;
+  return 0;
+}
+
+int
+solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
+{
+  Id sup, *supp;
+  supp = s->repo->idarraydata + s->supplements;
+  while ((sup = *supp++) != 0)
+    {
+      if (!solv->addalreadyrecommended && solver_dep_fulfilled_alreadyinstalled(solv, sup) != 2)
+       continue;
+      if (solv->only_namespace_recommended && solver_dep_fulfilled_namespace(solv, sup) != 2)
+       continue;
+      return 1;
+    }
+  return 0;
+}
+
+int
+solver_is_namespace_dep_slow(Solver *solv, Reldep *rd)
+{
+  Pool *pool = solv->pool;
+  for (;;)
+    {
+      if (rd->flags == REL_NAMESPACE)
+       return 1;
+      if (ISRELDEP(rd->name) && solver_is_namespace_dep_slow(solv, GETRELDEP(pool, rd->name)))
+       return 1;
+      if (!ISRELDEP(rd->evr))
+       return 0;
+      rd = GETRELDEP(pool, rd->evr);
+    }
+}
+
+/*
+ * add all installed packages that package p obsoletes to Queue q.
+ * Package p is not installed. Also, we know that if
+ * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
+ * Entries may get added multiple times.
+ */
+static void
+solver_add_obsoleted(Solver *solv, Id p, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id p2, pp2;
+  Solvable *s = pool->solvables + p;
+  Id obs, *obsp;
+  Id lastp2 = 0;
+
+  if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
+    {
+      FOR_PROVIDES(p2, pp2, s->name)
+        {
+          Solvable *ps = pool->solvables + p2;
+          if (ps->repo != installed)
+            continue;
+          if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
+            continue;
+          if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+            continue;
+          queue_push(q, p2);
+          lastp2 = p2;
+        }
+    }
+  if (!s->obsoletes)
+    return;
+  obsp = s->repo->idarraydata + s->obsoletes;
+  while ((obs = *obsp++) != 0)
+    FOR_PROVIDES(p2, pp2, obs)
+      {
+        Solvable *ps = pool->solvables + p2;
+        if (ps->repo != installed)
+          continue;
+        if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+          continue;
+        if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+          continue;
+        if (p2 == lastp2)
+          continue;
+        queue_push(q, p2);
+        lastp2 = p2;
+      }
+}
+
+/*
+ * Call solver_add_obsoleted and intersect the result with the
+ * elements in Queue q starting at qstart.
+ * Assumes that it's the first call if qstart == q->count.
+ * May use auxillary map m for the intersection process, all
+ * elements of q starting at qstart must have their bit cleared.
+ * (This is also true after the function returns.)
+ * (See solver_add_obsoleted for limitations of the package p)
+ */
+void
+solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m)
+{
+  int i, j;
+  int qcount = q->count;
+
+  solver_add_obsoleted(solv, p, q);
+  if (qcount == qstart)
+    return;     /* first call */
+  if (qcount == q->count)
+    j = qstart;
+  else if (qcount == qstart + 1)
+    {
+      /* easy if there's just one element */
+      j = qstart;
+      for (i = qcount; i < q->count; i++)
+        if (q->elements[i] == q->elements[qstart])
+          {
+            j++;        /* keep the element */
+            break;
+          }
+    }
+  else if (!m || (!m->size && q->count - qstart <= 8))
+    {
+      /* faster than a map most of the time */
+      int k;
+      for (i = j = qstart; i < qcount; i++)
+        {
+          Id ip = q->elements[i];
+          for (k = qcount; k < q->count; k++)
+            if (q->elements[k] == ip)
+              {
+                q->elements[j++] = ip;
+                break;
+              }
+        }
+    }
+  else
+    {
+      /* for the really pathologic cases we use the map */
+      Repo *installed = solv->installed;
+      if (!m->size)
+        map_init(m, installed->end - installed->start);
+      for (i = qcount; i < q->count; i++)
+        MAPSET(m, q->elements[i] - installed->start);
+      for (i = j = qstart; i < qcount; i++)
+        if (MAPTST(m, q->elements[i] - installed->start))
+          {
+            MAPCLR(m, q->elements[i] - installed->start);
+            q->elements[j++] = q->elements[i];
+          }
+    }
+  queue_truncate(q, j);
+}
+
diff --git a/libsolv-0.7.2/src/solverdebug.c b/libsolv-0.7.2/src/solverdebug.c
new file mode 100644 (file)
index 0000000..bb74ef6
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solverdebug.c
+ *
+ * debug functions for the SAT solver
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "solverdebug.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "util.h"
+#include "evr.h"
+#include "policy.h"
+
+
+void
+solver_printruleelement(Solver *solv, int type, Rule *r, Id v)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  if (v < 0)
+    {
+      s = pool->solvables + -v;
+      POOL_DEBUG(type, "    !%s [%d]", pool_solvable2str(pool, s), -v);
+    }
+  else
+    {
+      s = pool->solvables + v;
+      POOL_DEBUG(type, "    %s [%d]", pool_solvable2str(pool, s), v);
+    }
+  if (pool->installed && s->repo == pool->installed)
+    POOL_DEBUG(type, "I");
+  if (r)
+    {
+      if (r->w1 == v)
+       POOL_DEBUG(type, " (w1)");
+      if (r->w2 == v)
+       POOL_DEBUG(type, " (w2)");
+    }
+  if (solv->decisionmap[s - pool->solvables] > 0)
+    POOL_DEBUG(type, " Install.level%d", solv->decisionmap[s - pool->solvables]);
+  if (solv->decisionmap[s - pool->solvables] < 0)
+    POOL_DEBUG(type, " Conflict.level%d", -solv->decisionmap[s - pool->solvables]);
+  POOL_DEBUG(type, "\n");
+}
+
+
+/*
+ * print rule
+ */
+
+void
+solver_printrule(Solver *solv, int type, Rule *r)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id d, v;
+
+  if (r >= solv->rules && r < solv->rules + solv->nrules)   /* r is a solver rule */
+    POOL_DEBUG(type, "Rule #%d:", (int)(r - solv->rules));
+  else
+    POOL_DEBUG(type, "Rule:");                /* r is any rule */
+  if (r->d < 0)
+    POOL_DEBUG(type, " (disabled)");
+  POOL_DEBUG(type, "\n");
+  d = r->d < 0 ? -r->d - 1 : r->d;
+  for (i = 0; ; i++)
+    {
+      if (i == 0)
+         /* print direct literal */
+       v = r->p;
+      else if (!d)
+       {
+         if (i == 2)
+           break;
+         /* binary rule --> print w2 as second literal */
+         v = r->w2;
+       }
+      else
+         /* every other which is in d */
+       v = solv->pool->whatprovidesdata[d + i - 1];
+      if (v == ID_NULL)
+       break;
+      solver_printruleelement(solv, type, r, v);
+    }
+  POOL_DEBUG(type, "    next rules: %d %d\n", r->n1, r->n2);
+}
+
+void
+solver_printruleclass(Solver *solv, int type, Rule *r)
+{
+  Pool *pool = solv->pool;
+  Id p = r - solv->rules;
+  assert(p >= 0);
+  if (p < solv->learntrules)
+    if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, p))
+      POOL_DEBUG(type, "WEAK ");
+  if (solv->learntrules && p >= solv->learntrules)
+    POOL_DEBUG(type, "LEARNT ");
+  else if (p >= solv->bestrules && p < solv->bestrules_end)
+    POOL_DEBUG(type, "BEST ");
+  else if (p >= solv->choicerules && p < solv->choicerules_end)
+    POOL_DEBUG(type, "CHOICE ");
+  else if (p >= solv->infarchrules && p < solv->infarchrules_end)
+    POOL_DEBUG(type, "INFARCH ");
+  else if (p >= solv->duprules && p < solv->duprules_end)
+    POOL_DEBUG(type, "DUP ");
+  else if (p >= solv->jobrules && p < solv->jobrules_end)
+    POOL_DEBUG(type, "JOB ");
+  else if (p >= solv->updaterules && p < solv->updaterules_end)
+    POOL_DEBUG(type, "UPDATE ");
+  else if (p >= solv->featurerules && p < solv->featurerules_end)
+    POOL_DEBUG(type, "FEATURE ");
+  else if (p >= solv->yumobsrules && p < solv->yumobsrules_end)
+    POOL_DEBUG(type, "YUMOBS ");
+  solver_printrule(solv, type, r);
+}
+
+void
+solver_printproblem(Solver *solv, Id v)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Rule *r;
+  Id *jp;
+
+  if (v > 0)
+    solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, solv->rules + v);
+  else
+    {
+      v = -(v + 1);
+      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "JOB %d\n", v);
+      jp = solv->ruletojob.elements;
+      for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+       if (*jp == v)
+         {
+           POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "- ");
+           solver_printrule(solv, SOLV_DEBUG_SOLUTIONS, r);
+         }
+      POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "ENDJOB\n");
+    }
+}
+
+void
+solver_printwatches(Solver *solv, int type)
+{
+  Pool *pool = solv->pool;
+  int counter;
+
+  POOL_DEBUG(type, "Watches: \n");
+  for (counter = -(pool->nsolvables - 1); counter < pool->nsolvables; counter++)
+    POOL_DEBUG(type, "    solvable [%d] -- rule [%d]\n", counter, solv->watches[counter + pool->nsolvables]);
+}
+
+void
+solver_printdecisionq(Solver *solv, int type)
+{
+  Pool *pool = solv->pool;
+  int i;
+  Id p, why;
+
+  POOL_DEBUG(type, "Decisions:\n");
+  for (i = 0; i < solv->decisionq.count; i++)
+    {
+      p = solv->decisionq.elements[i];
+      if (p > 0)
+        POOL_DEBUG(type, "%d %d install  %s, ", i, solv->decisionmap[p], pool_solvid2str(pool, p));
+      else
+        POOL_DEBUG(type, "%d %d conflict %s, ", i, -solv->decisionmap[-p], pool_solvid2str(pool, -p));
+      why = solv->decisionq_why.elements[i];
+      if (why > 0)
+       {
+         POOL_DEBUG(type, "forced by ");
+         solver_printruleclass(solv, type, solv->rules + why);
+       }
+      else if (why < 0)
+       {
+         POOL_DEBUG(type, "chosen from ");
+         solver_printruleclass(solv, type, solv->rules - why);
+       }
+      else
+        POOL_DEBUG(type, "picked for some unknown reason.\n");
+    }
+}
+
+/*
+ * printdecisions
+ */
+
+void
+solver_printdecisions(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Transaction *trans = solver_create_transaction(solv);
+  Id p, type;
+  int i, j;
+  Solvable *s;
+  Queue iq;
+  Queue recommendations;
+  Queue suggestions;
+  Queue orphaned;
+
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "transaction:\n");
+
+  queue_init(&iq);
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      p = trans->steps.elements[i];
+      s = pool->solvables + p;
+      type = transaction_type(trans, p, SOLVER_TRANSACTION_SHOW_ACTIVE|SOLVER_TRANSACTION_SHOW_ALL|SOLVER_TRANSACTION_SHOW_OBSOLETES|SOLVER_TRANSACTION_SHOW_MULTIINSTALL);
+      switch(type)
+        {
+       case SOLVER_TRANSACTION_MULTIINSTALL:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  multi install %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_MULTIREINSTALL:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  multi reinstall %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_INSTALL:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  install   %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_REINSTALL:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  reinstall %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_DOWNGRADE:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  downgrade %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_CHANGE:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  change    %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_UPGRADE:
+       case SOLVER_TRANSACTION_OBSOLETES:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  upgrade   %s", pool_solvable2str(pool, s));
+         break;
+       case SOLVER_TRANSACTION_ERASE:
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "  erase     %s", pool_solvable2str(pool, s));
+         break;
+       default:
+         break;
+        }
+      switch(type)
+        {
+       case SOLVER_TRANSACTION_INSTALL:
+       case SOLVER_TRANSACTION_ERASE:
+       case SOLVER_TRANSACTION_MULTIINSTALL:
+       case SOLVER_TRANSACTION_MULTIREINSTALL:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+         break;
+       case SOLVER_TRANSACTION_REINSTALL:
+       case SOLVER_TRANSACTION_DOWNGRADE:
+       case SOLVER_TRANSACTION_CHANGE:
+       case SOLVER_TRANSACTION_UPGRADE:
+       case SOLVER_TRANSACTION_OBSOLETES:
+         transaction_all_obs_pkgs(trans, p, &iq);
+         if (iq.count)
+           {
+             POOL_DEBUG(SOLV_DEBUG_RESULT, "  (obsoletes");
+             for (j = 0; j < iq.count; j++)
+               POOL_DEBUG(SOLV_DEBUG_RESULT, " %s", pool_solvid2str(pool, iq.elements[j]));
+             POOL_DEBUG(SOLV_DEBUG_RESULT, ")");
+           }
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+         break;
+       default:
+         break;
+       }
+    }
+  queue_free(&iq);
+
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+
+  queue_init(&recommendations);
+  queue_init(&suggestions);
+  queue_init(&orphaned);
+  solver_get_recommendations(solv, &recommendations, &suggestions, 0);
+  solver_get_orphaned(solv, &orphaned);
+  if (recommendations.count)
+    {
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "recommended packages:\n");
+      for (i = 0; i < recommendations.count; i++)
+       {
+         s = pool->solvables + recommendations.elements[i];
+          if (solv->decisionmap[recommendations.elements[i]] > 0)
+           {
+             if (installed && s->repo == installed)
+               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (installed)\n", pool_solvable2str(pool, s));
+             else
+               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (selected)\n", pool_solvable2str(pool, s));
+           }
+          else
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s\n", pool_solvable2str(pool, s));
+       }
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+    }
+
+  if (suggestions.count)
+    {
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "suggested packages:\n");
+      for (i = 0; i < suggestions.count; i++)
+       {
+         s = pool->solvables + suggestions.elements[i];
+          if (solv->decisionmap[suggestions.elements[i]] > 0)
+           {
+             if (installed && s->repo == installed)
+               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (installed)\n", pool_solvable2str(pool, s));
+             else
+               POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (selected)\n", pool_solvable2str(pool, s));
+           }
+         else
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s\n", pool_solvable2str(pool, s));
+       }
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+    }
+  if (orphaned.count)
+    {
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "orphaned packages:\n");
+      for (i = 0; i < orphaned.count; i++)
+       {
+         s = pool->solvables + orphaned.elements[i];
+          if (solv->decisionmap[solv->orphaned.elements[i]] > 0)
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (kept)\n", pool_solvable2str(pool, s));
+         else
+           POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s (erased)\n", pool_solvable2str(pool, s));
+       }
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+    }
+  queue_free(&recommendations);
+  queue_free(&suggestions);
+  queue_free(&orphaned);
+  transaction_free(trans);
+}
+
+static inline
+const char *id2strnone(Pool *pool, Id id)
+{
+  return !id || id == 1 ? "(none)" : pool_id2str(pool, id);
+}
+
+void
+transaction_print(Transaction *trans)
+{
+  Pool *pool = trans->pool;
+  Queue classes, pkgs;
+  int i, j, mode, l, linel;
+  char line[76];
+  const char *n;
+
+  queue_init(&classes);
+  queue_init(&pkgs);
+  mode = SOLVER_TRANSACTION_SHOW_OBSOLETES | SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE;
+  transaction_classify(trans, mode, &classes);
+  for (i = 0; i < classes.count; i += 4)
+    {
+      Id class = classes.elements[i];
+      Id cnt = classes.elements[i + 1];
+      switch(class)
+       {
+       case SOLVER_TRANSACTION_ERASE:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d erased packages:\n", cnt);
+         break;
+       case SOLVER_TRANSACTION_INSTALL:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d installed packages:\n", cnt);
+         break;
+       case SOLVER_TRANSACTION_REINSTALLED:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d reinstalled packages:\n", cnt);
+         break;
+       case SOLVER_TRANSACTION_DOWNGRADED:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d downgraded packages:\n", cnt);
+         break;
+       case SOLVER_TRANSACTION_CHANGED:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d changed packages:\n", cnt);
+         break;
+       case SOLVER_TRANSACTION_UPGRADED:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d upgraded packages:\n", cnt);
+         break;
+       case SOLVER_TRANSACTION_VENDORCHANGE:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d vendor changes from '%s' to '%s':\n", cnt, id2strnone(pool, classes.elements[i + 2]), id2strnone(pool, classes.elements[i + 3]));
+         break;
+       case SOLVER_TRANSACTION_ARCHCHANGE:
+         POOL_DEBUG(SOLV_DEBUG_RESULT, "%d arch changes from %s to %s:\n", cnt, pool_id2str(pool, classes.elements[i + 2]), pool_id2str(pool, classes.elements[i + 3]));
+         break;
+       default:
+         class = SOLVER_TRANSACTION_IGNORE;
+         break;
+       }
+      if (class == SOLVER_TRANSACTION_IGNORE)
+       continue;
+      transaction_classify_pkgs(trans, mode, class, classes.elements[i + 2], classes.elements[i + 3], &pkgs);
+      *line = 0;
+      linel = 0;
+      for (j = 0; j < pkgs.count; j++)
+       {
+         Id p = pkgs.elements[j];
+         Solvable *s = pool->solvables + p;
+         Solvable *s2;
+
+         switch(class)
+           {
+           case SOLVER_TRANSACTION_DOWNGRADED:
+           case SOLVER_TRANSACTION_UPGRADED:
+             s2 = pool->solvables + transaction_obs_pkg(trans, p);
+             POOL_DEBUG(SOLV_DEBUG_RESULT, "  - %s -> %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2));
+             break;
+           case SOLVER_TRANSACTION_VENDORCHANGE:
+           case SOLVER_TRANSACTION_ARCHCHANGE:
+             n = pool_id2str(pool, s->name);
+             l = strlen(n);
+             if (l + linel > sizeof(line) - 3)
+               {
+                 if (*line)
+                   POOL_DEBUG(SOLV_DEBUG_RESULT, "    %s\n", line);
+                 *line = 0;
+                 linel = 0;
+               }
+             if (l + linel > sizeof(line) - 3)
+               POOL_DEBUG(SOLV_DEBUG_RESULT, "    %s\n", n);
+             else
+               {
+                 if (*line)
+                   {
+                     strcpy(line + linel, ", ");
+                     linel += 2;
+                   }
+                 strcpy(line + linel, n);
+                 linel += l;
+               }
+             break;
+           default:
+             POOL_DEBUG(SOLV_DEBUG_RESULT, "  - %s\n", pool_solvable2str(pool, s));
+             break;
+           }
+       }
+      if (*line)
+       POOL_DEBUG(SOLV_DEBUG_RESULT, "    %s\n", line);
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+    }
+  queue_free(&classes);
+  queue_free(&pkgs);
+}
+
+void
+solver_printproblemruleinfo(Solver *solv, Id probr)
+{
+  Pool *pool = solv->pool;
+  Id dep, source, target;
+  SolverRuleinfo type = solver_ruleinfo(solv, probr, &source, &target, &dep);
+
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "%s\n", solver_problemruleinfo2str(solv, type, source, target, dep));
+}
+
+void
+solver_printprobleminfo(Solver *solv, Id problem)
+{
+  solver_printproblemruleinfo(solv, solver_findproblemrule(solv, problem));
+}
+
+void
+solver_printcompleteprobleminfo(Solver *solv, Id problem)
+{
+  Queue q;
+  Id probr;
+  int i, nobad = 0;
+
+  queue_init(&q);
+  solver_findallproblemrules(solv, problem, &q);
+  for (i = 0; i < q.count; i++)
+    {
+      probr = q.elements[i];
+      if (!(probr >= solv->updaterules && probr < solv->updaterules_end) && !(probr >= solv->jobrules && probr < solv->jobrules_end))
+       {
+         nobad = 1;
+         break;
+       }
+    }
+  for (i = 0; i < q.count; i++)
+    {
+      probr = q.elements[i];
+      if (nobad && ((probr >= solv->updaterules && probr < solv->updaterules_end) || (probr >= solv->jobrules && probr < solv->jobrules_end)))
+       continue;
+      solver_printproblemruleinfo(solv, probr);
+    }
+  queue_free(&q);
+}
+
+static int illegals[] = {
+  POLICY_ILLEGAL_DOWNGRADE,
+  POLICY_ILLEGAL_NAMECHANGE,
+  POLICY_ILLEGAL_ARCHCHANGE,
+  POLICY_ILLEGAL_VENDORCHANGE,
+  0
+};
+
+void
+solver_printsolution(Solver *solv, Id problem, Id solution)
+{
+  Pool *pool = solv->pool;
+  Id p, rp, element;
+
+  element = 0;
+  while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
+    {
+      if (p > 0 && rp > 0)
+       {
+         /* for replacements we want to know why it was illegal */
+         Solvable *s = pool->solvables + p, *rs = pool->solvables + rp;
+         int illegal = policy_is_illegal(solv, s, rs, 0);
+         if (illegal)
+           {
+             int i;
+             for (i = 0; illegals[i]; i++)
+               if ((illegal & illegals[i]) != 0)
+                 {
+                   POOL_DEBUG(SOLV_DEBUG_RESULT, "  - allow %s\n", policy_illegal2str(solv, illegals[i], s, rs));
+                   illegal ^= illegals[i];
+                 }
+             if (!illegal)
+               continue;
+           }
+       }
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "  - %s\n", solver_solutionelement2str(solv, p, rp));
+    }
+}
+
+void
+solver_printallsolutions(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  int pcnt;
+  Id problem, solution;
+
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "Encountered problems! Here are the solutions:\n\n");
+  pcnt = 0;
+  problem = 0;
+  while ((problem = solver_next_problem(solv, problem)) != 0)
+    {
+      pcnt++;
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "Problem %d:\n", pcnt);
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "====================================\n");
+#if 1
+      solver_printprobleminfo(solv, problem);
+#else
+      solver_printcompleteprobleminfo(solv, problem);
+#endif
+      POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+      solution = 0;
+      while ((solution = solver_next_solution(solv, problem, solution)) != 0)
+        {
+         solver_printsolution(solv, problem, solution);
+          POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+        }
+    }
+}
+
diff --git a/libsolv-0.7.2/src/solverdebug.h b/libsolv-0.7.2/src/solverdebug.h
new file mode 100644 (file)
index 0000000..b6923b4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solverdebug.h
+ *
+ */
+
+#ifndef LIBSOLV_SOLVERDEBUG_H
+#define LIBSOLV_SOLVERDEBUG_H
+
+#include "pooltypes.h"
+#include "pool.h"
+#include "solver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void solver_printruleelement(Solver *solv, int type, Rule *r, Id v);
+extern void solver_printrule(Solver *solv, int type, Rule *r);
+extern void solver_printruleclass(Solver *solv, int type, Rule *r);
+extern void solver_printproblem(Solver *solv, Id v);
+extern void solver_printwatches(Solver *solv, int type);
+extern void solver_printdecisionq(Solver *solv, int type);
+extern void solver_printdecisions(Solver *solv);
+extern void solver_printproblemruleinfo(Solver *solv, Id rule);
+extern void solver_printprobleminfo(Solver *solv, Id problem);
+extern void solver_printcompleteprobleminfo(Solver *solv, Id problem);
+extern void solver_printsolution(Solver *solv, Id problem, Id solution);
+extern void solver_printallsolutions(Solver *solv);
+
+extern void transaction_print(Transaction *trans);
+
+/* weird suse stuff */
+extern void solver_printtrivial(Solver *solv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_SOLVERDEBUG_H */
+
diff --git a/libsolv-0.7.2/src/solvversion.c b/libsolv-0.7.2/src/solvversion.c
new file mode 100644 (file)
index 0000000..d66e195
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include "solvversion.h"
+
+const char solv_version[] = LIBSOLV_VERSION_STRING;
+int solv_version_major = LIBSOLV_VERSION_MAJOR;
+int solv_version_minor = LIBSOLV_VERSION_MINOR;
+int solv_version_patch = LIBSOLV_VERSION_PATCH;
diff --git a/libsolv-0.7.2/src/solvversion.h.in b/libsolv-0.7.2/src/solvversion.h.in
new file mode 100644 (file)
index 0000000..4caba47
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solvversion.h
+ * 
+ */
+
+#ifndef LIBSOLV_SOLVVERSION_H
+#define LIBSOLV_SOLVVERSION_H
+
+#define LIBSOLV_VERSION_STRING "@VERSION@"
+#define LIBSOLV_VERSION_MAJOR @LIBSOLV_MAJOR@
+#define LIBSOLV_VERSION_MINOR @LIBSOLV_MINOR@
+#define LIBSOLV_VERSION_PATCH @LIBSOLV_PATCH@
+#define LIBSOLV_VERSION (LIBSOLV_VERSION_MAJOR * 10000 + LIBSOLV_VERSION_MINOR * 100 + LIBSOLV_VERSION_PATCH)
+
+extern const char solv_version[];
+extern int solv_version_major;
+extern int solv_version_minor;
+extern int solv_version_patch;
+
+#cmakedefine LIBSOLV_FEATURE_LINKED_PKGS
+#cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS
+#cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS
+
+#cmakedefine LIBSOLVEXT_FEATURE_RPMPKG
+#cmakedefine LIBSOLVEXT_FEATURE_RPMDB
+#cmakedefine LIBSOLVEXT_FEATURE_RPMDB_BYRPMHEADER
+#cmakedefine LIBSOLVEXT_FEATURE_PUBKEY
+#cmakedefine LIBSOLVEXT_FEATURE_RPMMD
+#cmakedefine LIBSOLVEXT_FEATURE_SUSEREPO
+#cmakedefine LIBSOLVEXT_FEATURE_COMPS
+#cmakedefine LIBSOLVEXT_FEATURE_HELIXREPO
+#cmakedefine LIBSOLVEXT_FEATURE_DEBIAN
+#cmakedefine LIBSOLVEXT_FEATURE_ARCHREPO
+#cmakedefine LIBSOLVEXT_FEATURE_HAIKU
+#cmakedefine LIBSOLVEXT_FEATURE_APPDATA
+#cmakedefine LIBSOLVEXT_FEATURE_ZLIB_COMPRESSION
+#cmakedefine LIBSOLVEXT_FEATURE_LZMA_COMPRESSION
+#cmakedefine LIBSOLVEXT_FEATURE_BZIP2_COMPRESSION
+#cmakedefine LIBSOLVEXT_FEATURE_ZSTD_COMPRESSION
+
+/* see tools/common_write.c for toolversion history */
+#define LIBSOLV_TOOLVERSION "1.1"
+
+#endif
diff --git a/libsolv-0.7.2/src/strpool.c b/libsolv-0.7.2/src/strpool.c
new file mode 100644 (file)
index 0000000..b4a09a5
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <string.h>
+#include "util.h"
+#include "strpool.h"
+
+#define STRING_BLOCK      2047
+#define STRINGSPACE_BLOCK 65535
+
+void
+stringpool_init(Stringpool *ss, const char *strs[])
+{
+  unsigned totalsize = 0;
+  unsigned count;
+
+  memset(ss, 0, sizeof(*ss));
+  /* count number and total size of predefined strings */
+  for (count = 0; strs[count]; count++)
+    totalsize += strlen(strs[count]) + 1;
+
+  /* alloc appropriate space */
+  ss->stringspace = solv_extend_resize(0, totalsize, 1, STRINGSPACE_BLOCK);
+  ss->strings = solv_extend_resize(0, count, sizeof(Offset), STRING_BLOCK);
+
+  /* now copy predefined strings into allocated space */
+  ss->sstrings = 0;
+  for (count = 0; strs[count]; count++)
+    {
+      strcpy(ss->stringspace + ss->sstrings, strs[count]);
+      ss->strings[count] = ss->sstrings;
+      ss->sstrings += strlen(strs[count]) + 1;
+    }
+  ss->nstrings = count;
+}
+
+void
+stringpool_free(Stringpool *ss)
+{
+  solv_free(ss->strings);
+  solv_free(ss->stringspace);
+  solv_free(ss->stringhashtbl);
+}
+
+void
+stringpool_freehash(Stringpool *ss)
+{
+  ss->stringhashtbl = solv_free(ss->stringhashtbl);
+  ss->stringhashmask = 0;
+}
+
+void
+stringpool_init_empty(Stringpool *ss)
+{
+  static const char *emptystrs[] = { "<NULL>", "", 0 };
+  stringpool_init(ss, emptystrs);
+}
+
+void
+stringpool_clone(Stringpool *ss, Stringpool *from)
+{
+  memset(ss, 0, sizeof(*ss));
+  ss->strings = solv_extend_resize(0, from->nstrings, sizeof(Offset), STRING_BLOCK);
+  memcpy(ss->strings, from->strings, from->nstrings * sizeof(Offset));
+  ss->stringspace = solv_extend_resize(0, from->sstrings, 1, STRINGSPACE_BLOCK);
+  memcpy(ss->stringspace, from->stringspace, from->sstrings);
+  ss->nstrings = from->nstrings;
+  ss->sstrings = from->sstrings;
+}
+
+void
+stringpool_resize_hash(Stringpool *ss, int numnew)
+{
+  Hashval h, hh, hashmask;
+  Hashtable hashtbl;
+  int i;
+
+  if (numnew <= 0)
+    return;
+  hashmask = mkmask(ss->nstrings + numnew);
+  if (hashmask <= ss->stringhashmask)
+    return;    /* same as before */
+
+  /* realloc hash table */
+  ss->stringhashmask = hashmask;
+  solv_free(ss->stringhashtbl);
+  ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id));
+  
+  /* rehash all strings into new hashtable */
+  for (i = 1; i < ss->nstrings; i++)
+    {
+      h = strhash(ss->stringspace + ss->strings[i]) & hashmask;
+      hh = HASHCHAIN_START;
+      while (hashtbl[h] != 0)
+       h = HASHCHAIN_NEXT(h, hh, hashmask);
+      hashtbl[h] = i;
+    }
+}
+
+Id
+stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create)
+{
+  Hashval h, hh, hashmask, oldhashmask;
+  Id id;
+  Hashtable hashtbl;
+
+  if (!str)
+    return STRID_NULL;
+  if (!len)
+    return STRID_EMPTY;
+
+  hashmask = oldhashmask = ss->stringhashmask;
+  /* expand hashtable if needed */
+  if ((Hashval)ss->nstrings * 2 > hashmask)
+    {
+      stringpool_resize_hash(ss, STRING_BLOCK);
+      hashmask = ss->stringhashmask;
+    }
+  hashtbl = ss->stringhashtbl;
+
+  /* compute hash and check for match */
+  h = strnhash(str, len) & hashmask;
+  hh = HASHCHAIN_START;
+  while ((id = hashtbl[h]) != 0)
+    {
+      if(!memcmp(ss->stringspace + ss->strings[id], str, len)
+         && ss->stringspace[ss->strings[id] + len] == 0)
+       break;
+      h = HASHCHAIN_NEXT(h, hh, hashmask);
+    }
+  if (id || !create)    /* exit here if string found */
+    return id;
+
+  /* this should be a test for a flag that tells us if the
+   * correct blocking is used, but adding a flag would break
+   * the ABI. So we use the existance of the hash area as
+   * indication instead */
+  if (!oldhashmask)
+    {
+      ss->stringspace = solv_extend_resize(ss->stringspace, ss->sstrings + len + 1, 1, STRINGSPACE_BLOCK);
+      ss->strings = solv_extend_resize(ss->strings, ss->nstrings + 1, sizeof(Offset), STRING_BLOCK);
+    }
+
+  /* generate next id and save in table */
+  id = ss->nstrings++;
+  hashtbl[h] = id;
+
+  ss->strings = solv_extend(ss->strings, id, 1, sizeof(Offset), STRING_BLOCK);
+  ss->strings[id] = ss->sstrings;      /* we will append to the end */
+
+  /* append string to stringspace */
+  ss->stringspace = solv_extend(ss->stringspace, ss->sstrings, len + 1, 1, STRINGSPACE_BLOCK);
+  memcpy(ss->stringspace + ss->sstrings, str, len);
+  ss->stringspace[ss->sstrings + len] = 0;
+  ss->sstrings += len + 1;
+  return id;
+}
+
+Id
+stringpool_str2id(Stringpool *ss, const char *str, int create)
+{
+  if (!str)
+    return STRID_NULL;
+  if (!*str)
+    return STRID_EMPTY;
+  return stringpool_strn2id(ss, str, (unsigned int)strlen(str), create);
+}
+
+void
+stringpool_shrink(Stringpool *ss)
+{
+  ss->stringspace = solv_extend_resize(ss->stringspace, ss->sstrings, 1, STRINGSPACE_BLOCK);
+  ss->strings = solv_extend_resize(ss->strings, ss->nstrings, sizeof(Offset), STRING_BLOCK);
+}
diff --git a/libsolv-0.7.2/src/strpool.h b/libsolv-0.7.2/src/strpool.h
new file mode 100644 (file)
index 0000000..fd13bdb
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+#ifndef LIBSOLV_STRINGPOOL_H
+#define LIBSOLV_STRINGPOOL_H
+
+#include "pooltypes.h"
+#include "hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define STRID_NULL  0
+#define STRID_EMPTY 1
+
+struct s_Stringpool
+{
+  Offset *strings;            /* table of offsets into stringspace, indexed by Id: Id -> Offset */
+  int nstrings;               /* number of ids in strings table */
+  char *stringspace;          /* space for all unique strings: stringspace + Offset = string */
+  Offset sstrings;            /* size of used stringspace */
+
+  Hashtable stringhashtbl;    /* hash table: (string ->) Hash -> Id */
+  Hashval stringhashmask;     /* modulo value for hash table (size of table - 1) */
+};
+
+void stringpool_init(Stringpool *ss, const char *strs[]);
+void stringpool_init_empty(Stringpool *ss);
+void stringpool_clone(Stringpool *ss, Stringpool *from);
+void stringpool_free(Stringpool *ss);
+void stringpool_freehash(Stringpool *ss);
+void stringpool_resize_hash(Stringpool *ss, int numnew);
+
+Id stringpool_str2id(Stringpool *ss, const char *str, int create);
+Id stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create);
+
+void stringpool_shrink(Stringpool *ss);
+
+
+static inline const char *
+stringpool_id2str(Stringpool *ss, Id id)
+{
+  return ss->stringspace + ss->strings[id];
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsolv-0.7.2/src/suse.c b/libsolv-0.7.2/src/suse.c
new file mode 100644 (file)
index 0000000..9537a33
--- /dev/null
@@ -0,0 +1,747 @@
+/*
+ * Copyright (c) 2016, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* weird SUSE stuff. better not use it for your projects. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolvendor.h"
+#include "util.h"
+
+Offset
+repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
+{
+  Pool *pool = repo->pool;
+  Id id, idp, idl;
+  char buf[1024], *p, *dep;
+  int i, l;
+
+  if (provides)
+    {
+      for (i = provides; repo->idarraydata[i]; i++)
+       {
+         id = repo->idarraydata[i];
+         if (ISRELDEP(id))
+           continue;
+         dep = (char *)pool_id2str(pool, id);
+         if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
+           {
+             idp = 0;
+             strcpy(buf + 2, dep);
+             dep = buf + 2 + 7;
+             if ((p = strchr(dep, ':')) != 0 && p != dep)
+               {
+                 *p++ = 0;
+                 idp = pool_str2id(pool, dep, 1);
+                 dep = p;
+               }
+             id = 0;
+             while ((p = strchr(dep, ';')) != 0)
+               {
+                 if (p == dep)
+                   {
+                     dep = p + 1;
+                     continue;
+                   }
+                 *p++ = 0;
+                 idl = pool_str2id(pool, dep, 1);
+                 idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
+                 if (id)
+                   id = pool_rel2id(pool, id, idl, REL_OR, 1);
+                 else
+                   id = idl;
+                 dep = p;
+               }
+             if (dep[0] && dep[1])
+               {
+                 for (p = dep; *p && *p != ')'; p++)
+                   ;
+                 *p = 0;
+                 idl = pool_str2id(pool, dep, 1);
+                 idl = pool_rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
+                 if (id)
+                   id = pool_rel2id(pool, id, idl, REL_OR, 1);
+                 else
+                   id = idl;
+               }
+             if (idp)
+               id = pool_rel2id(pool, idp, id, REL_AND, 1);
+             if (id)
+               supplements = repo_addid_dep(repo, supplements, id, 0);
+           }
+         else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
+           {
+             strcpy(buf, dep);
+             p = buf + (p - dep);
+             *p++ = 0;
+             idp = pool_str2id(pool, buf, 1);
+             /* strip trailing slashes */
+             l = strlen(p);
+             while (l > 1 && p[l - 1] == '/')
+               p[--l] = 0;
+             id = pool_str2id(pool, p, 1);
+             id = pool_rel2id(pool, idp, id, REL_WITH, 1);
+             id = pool_rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
+             supplements = repo_addid_dep(repo, supplements, id, 0);
+           }
+       }
+    }
+  if (supplements)
+    {
+      for (i = supplements; repo->idarraydata[i]; i++)
+       {
+         id = repo->idarraydata[i];
+         if (ISRELDEP(id))
+           continue;
+         dep = (char *)pool_id2str(pool, id);
+         if (!strncmp(dep, "system:modalias(", 16))
+           dep += 7;
+         if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
+           {
+             strcpy(buf, dep);
+             p = strchr(buf + 9, ':');
+             if (p && p != buf + 9 && strchr(p + 1, ':'))
+               {
+                 *p++ = 0;
+                 idp = pool_str2id(pool, buf + 9, 1);
+                 p[strlen(p) - 1] = 0;
+                 id = pool_str2id(pool, p, 1);
+                 id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
+                 id = pool_rel2id(pool, idp, id, REL_AND, 1);
+               }
+             else
+               {
+                 p = buf + 9;
+                 p[strlen(p) - 1] = 0;
+                 id = pool_str2id(pool, p, 1);
+                 id = pool_rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
+               }
+             if (id)
+               repo->idarraydata[i] = id;
+           }
+         else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
+           {
+             strcpy(buf, dep);
+             id = 0;
+             dep = buf + 11;
+             while ((p = strchr(dep, ':')) != 0)
+               {
+                 if (p == dep)
+                   {
+                     dep = p + 1;
+                     continue;
+                   }
+                 /* argh, allow pattern: prefix. sigh */
+                 if (p - dep == 7 && !strncmp(dep, "pattern", 7))
+                   {
+                     p = strchr(p + 1, ':');
+                     if (!p)
+                       break;
+                   }
+                 *p++ = 0;
+                 idp = pool_str2id(pool, dep, 1);
+                 if (id)
+                   id = pool_rel2id(pool, id, idp, REL_AND, 1);
+                 else
+                   id = idp;
+                 dep = p;
+               }
+             if (dep[0] && dep[1])
+               {
+                 dep[strlen(dep) - 1] = 0;
+                 idp = pool_str2id(pool, dep, 1);
+                 if (id)
+                   id = pool_rel2id(pool, id, idp, REL_AND, 1);
+                 else
+                   id = idp;
+               }
+             if (id)
+               repo->idarraydata[i] = id;
+           }
+         else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
+           {
+             strcpy(buf, dep + 11);
+             if ((p = strrchr(buf, ')')) != 0)
+               *p = 0;
+             id = pool_str2id(pool, buf, 1);
+             id = pool_rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
+             repo->idarraydata[i] = id;
+           }
+       }
+    }
+  if (freshens && repo->idarraydata[freshens])
+    {
+      Id idsupp = 0, idfresh = 0;
+      if (!supplements || !repo->idarraydata[supplements])
+       return freshens;
+      for (i = supplements; repo->idarraydata[i]; i++)
+        {
+         if (!idsupp)
+           idsupp = repo->idarraydata[i];
+         else
+           idsupp = pool_rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
+        }
+      for (i = freshens; repo->idarraydata[i]; i++)
+        {
+         if (!idfresh)
+           idfresh = repo->idarraydata[i];
+         else
+           idfresh = pool_rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
+        }
+      if (!idsupp)
+        idsupp = idfresh;
+      else
+       idsupp = pool_rel2id(pool, idsupp, idfresh, REL_AND, 1);
+      supplements = repo_addid_dep(repo, 0, idsupp, 0);
+    }
+  return supplements;
+}
+
+Offset
+repo_fix_conflicts(Repo *repo, Offset conflicts)
+{
+  char buf[1024], *dep;
+  Pool *pool = repo->pool;
+  Id id;
+  int i;
+
+  if (!conflicts)
+    return conflicts;
+  for (i = conflicts; repo->idarraydata[i]; i++)
+    {
+      id = repo->idarraydata[i];
+      if (ISRELDEP(id))
+       continue;
+      dep = (char *)pool_id2str(pool, id);
+      if (!strncmp(dep, "otherproviders(", 15) && dep[15] && strlen(dep) < sizeof(buf) - 2)
+       {
+         strcpy(buf, dep + 15);
+         buf[strlen(buf) - 1] = 0;
+         id = pool_str2id(pool, buf, 1);
+         id = pool_rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
+         repo->idarraydata[i] = id;
+       }
+    }
+  return conflicts;
+}
+
+void
+repo_rewrite_suse_deps(Solvable *s, Offset freshens)
+{
+  s->supplements = repo_fix_supplements(s->repo, s->provides, s->supplements, freshens);
+  if (s->conflicts)
+    s->conflicts = repo_fix_conflicts(s->repo, s->conflicts);
+}
+
+/**********************************************************************************/
+
+static inline Id
+dep2name(Pool *pool, Id dep)
+{
+  while (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      dep = rd->name;
+    }
+  return dep;
+}
+
+static int
+providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con)
+{
+  Id p, pp;
+  Solvable *sn = pool->solvables + n;
+
+  FOR_PROVIDES(p, pp, sn->name)
+    {
+      Solvable *s = pool->solvables + p;
+      if (s->name != sn->name || s->arch != sn->arch)
+        continue;
+      if (!MAPTST(installed, p))
+        continue;
+      if (pool_match_nevr(pool, pool->solvables + p, con))
+        continue;
+      return 1;         /* found installed package that doesn't conflict */
+    }
+  return 0;
+}
+
+static inline int
+providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *multiversionmap)
+{
+  Id p, pp;
+  FOR_PROVIDES(p, pp, dep)
+    {
+      if (p == SYSTEMSOLVABLE)
+       return -1;
+      if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
+       continue;
+      if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
+       if (providedbyinstalled_multiversion(pool, installed, p, dep))
+         continue;
+      if (MAPTST(installed, p))
+       return 1;
+    }
+  return 0;
+}
+
+/* xmap:
+ *  1: installed
+ *  2: conflicts with installed
+ *  8: interesting (only true if installed)
+ * 16: undecided
+ */
+
+static int
+providedbyinstalled_multiversion_xmap(Pool *pool, unsigned char *map, Id n, Id con) 
+{
+  Id p, pp;
+  Solvable *sn = pool->solvables + n; 
+
+  FOR_PROVIDES(p, pp, sn->name)
+    {    
+      Solvable *s = pool->solvables + p; 
+      if (s->name != sn->name || s->arch != sn->arch)
+        continue;
+      if ((map[p] & 9) != 9)
+        continue;
+      if (pool_match_nevr(pool, pool->solvables + p, con))
+        continue;
+      return 1;         /* found installed package that doesn't conflict */
+    }    
+  return 0;
+}
+
+
+static inline int
+providedbyinstalled_xmap(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap)
+{
+  Id p, pp;
+  int r = 0; 
+  FOR_PROVIDES(p, pp, dep) 
+    {    
+      if (p == SYSTEMSOLVABLE)
+        return 1;       /* always boring, as never constraining */
+      if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
+        continue;
+      if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
+        if (providedbyinstalled_multiversion_xmap(pool, map, p, dep))
+          continue;
+      if ((map[p] & 9) == 9)
+        return 9;
+      r |= map[p] & 17;
+    }    
+  return r;
+}
+
+/* FIXME: this mirrors policy_illegal_vendorchange */
+static int
+pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
+{
+  Id v1, v2;
+  Id vendormask1, vendormask2;
+
+  if (pool->custom_vendorcheck)
+    return pool->custom_vendorcheck(pool, s1, s2);
+  /* treat a missing vendor as empty string */
+  v1 = s1->vendor ? s1->vendor : ID_EMPTY;
+  v2 = s2->vendor ? s2->vendor : ID_EMPTY;
+  if (v1 == v2)
+    return 0;
+  vendormask1 = pool_vendor2mask(pool, v1);
+  if (!vendormask1)
+    return 1;   /* can't match */
+  vendormask2 = pool_vendor2mask(pool, v2);
+  if ((vendormask1 & vendormask2) != 0)
+    return 0;
+  return 1;     /* no class matches */
+}
+
+/* check if this patch is relevant according to the vendor. To bad that patches
+ * don't have a vendor, so we need to do some careful repo testing. */
+int
+solvable_is_irrelevant_patch(Solvable *s, Map *installedmap)
+{
+  Pool *pool = s->repo->pool;
+  Id con, *conp;
+  int hadpatchpackage = 0;
+
+  if (!s->conflicts)
+    return 0;
+  conp = s->repo->idarraydata + s->conflicts;
+  while ((con = *conp++) != 0)
+    {
+      Reldep *rd;
+      Id p, pp, p2, pp2;
+      if (!ISRELDEP(con))
+        continue;
+      rd = GETRELDEP(pool, con);
+      if (rd->flags != REL_LT)
+        continue;
+      FOR_PROVIDES(p, pp, con)
+        {
+          Solvable *si;
+          if (!MAPTST(installedmap, p))
+            continue;
+          si = pool->solvables + p;
+          if (!pool_match_nevr(pool, si, con))
+            continue;
+          FOR_PROVIDES(p2, pp2, rd->name)
+            {
+              Solvable *s2 = pool->solvables + p2;
+              if (!pool_match_nevr(pool, s2, rd->name))
+                continue;
+              if (pool_match_nevr(pool, s2, con))
+                continue;       /* does not fulfill patch */
+              if (s2->repo == s->repo)
+                {
+                  hadpatchpackage = 1;
+                  /* ok, we have a package from the patch repo that solves the conflict. check vendor */
+                  if (si->vendor == s2->vendor)
+                    return 0;
+                  if (!pool_illegal_vendorchange(pool, si, s2))
+                    return 0;
+                  /* vendor change was illegal, ignore conflict */
+                }
+            }
+        }
+    }
+  /* if we didn't find a patchpackage don't claim that the patch is irrelevant */
+  if (!hadpatchpackage)
+    return 0;
+  return 1;
+}
+
+/*
+ * solvable_trivial_installable_map - answers if a solvable is installable
+ * without any other installs/deinstalls.
+ * The packages considered to be installed are provided via the
+ * installedmap bitmap. A additional "conflictsmap" bitmap providing
+ * information about the conflicts of the installed packages can be
+ * used for extra speed up. Provide a NULL pointer if you do not
+ * have this information.
+ * Both maps can be created with pool_create_state_maps() or
+ * solver_create_state_maps().
+ *
+ * returns:
+ * 1:  solvable is installable without any other package changes
+ * 0:  solvable is not installable
+ * -1: solvable is installable, but doesn't constrain any installed packages
+ */
+int
+solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap)
+{
+  Pool *pool = s->repo->pool;
+  Solvable *s2;
+  Id p, *dp;
+  Id *reqp, req;
+  Id *conp, con;
+  int r, interesting = 0;
+
+  if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
+    return 0;
+  if (s->requires)
+    {
+      reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)
+       {
+         if (req == SOLVABLE_PREREQMARKER)
+           continue;
+          r = providedbyinstalled(pool, installedmap, req, 0, 0);
+         if (!r)
+           return 0;
+         if (r > 0)
+           interesting = 1;
+       }
+    }
+  if (s->conflicts)
+    {
+      int ispatch = 0;
+
+      if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
+       ispatch = 1;
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+       {
+         if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
+           {
+             if (ispatch && solvable_is_irrelevant_patch(s, installedmap))
+               return -1;
+             return 0;
+           }
+         if (!interesting && ISRELDEP(con))
+           {
+              con = dep2name(pool, con);
+             if (providedbyinstalled(pool, installedmap, con, ispatch, multiversionmap))
+               interesting = 1;
+           }
+       }
+      if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap))
+       interesting = 0;
+    }
+  if (!conflictsmap)
+    {
+      int i;
+
+      p = s - pool->solvables;
+      for (i = 1; i < pool->nsolvables; i++)
+       {
+         if (!MAPTST(installedmap, i))
+           continue;
+         s2 = pool->solvables + i;
+         if (!s2->conflicts)
+           continue;
+         conp = s2->repo->idarraydata + s2->conflicts;
+         while ((con = *conp++) != 0)
+           {
+             dp = pool_whatprovides_ptr(pool, con);
+             for (; *dp; dp++)
+               if (*dp == p)
+                 return 0;
+           }
+       }
+     }
+  return interesting ? 1 : -1;
+}
+
+/*
+ * different interface for solvable_trivial_installable_map, where
+ * the information about the installed packages is provided
+ * by a queue.
+ */
+int
+solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap)
+{
+  Pool *pool = s->repo->pool;
+  int i;
+  Id p;
+  Map installedmap;
+  int r;
+
+  map_init(&installedmap, pool->nsolvables);
+  for (i = 0; i < installed->count; i++)
+    {
+      p = installed->elements[i];
+      if (p > 0)               /* makes it work with decisionq */
+       MAPSET(&installedmap, p);
+    }
+  r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
+  map_free(&installedmap);
+  return r;
+}
+
+/*
+ * different interface for solvable_trivial_installable_map, where
+ * the information about the installed packages is provided
+ * by a repo containing the installed solvables.
+ */
+int
+solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *multiversionmap)
+{
+  Pool *pool = s->repo->pool;
+  Id p;
+  Solvable *s2;
+  Map installedmap;
+  int r;
+
+  map_init(&installedmap, pool->nsolvables);
+  FOR_REPO_SOLVABLES(installed, p, s2)
+    MAPSET(&installedmap, p);
+  r = solvable_trivial_installable_map(s, &installedmap, 0, multiversionmap);
+  map_free(&installedmap);
+  return r;
+}
+
+/*
+ * pool_trivial_installable - calculate if a set of solvables is
+ * trivial installable without any other installs/deinstalls of
+ * packages not belonging to the set.
+ *
+ * the state is returned in the result queue:
+ * 1:  solvable is installable without any other package changes
+ * 0:  solvable is not installable
+ * -1: solvable is installable, but doesn't constrain any installed packages
+ */
+
+void
+pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap)
+{
+  int i, r, m, did;
+  Id p, *dp, con, *conp, req, *reqp;
+  unsigned char *map;
+  Solvable *s;
+
+  map = solv_calloc(pool->nsolvables, 1);
+  for (p = 1; p < pool->nsolvables; p++)
+    {
+      if (!MAPTST(installedmap, p))
+       continue;
+      map[p] |= 9;
+      s = pool->solvables + p;
+      if (!s->conflicts)
+       continue;
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+       {
+         dp = pool_whatprovides_ptr(pool, con);
+         for (; *dp; dp++)
+           map[p] |= 2;        /* XXX: self conflict ? */
+       }
+    }
+  for (i = 0; i < pkgs->count; i++)
+    map[pkgs->elements[i]] = 16;
+
+  for (i = 0, did = 0; did < pkgs->count; i++, did++)
+    {
+      if (i == pkgs->count)
+       i = 0;
+      p = pkgs->elements[i];
+      if ((map[p] & 16) == 0)
+       continue;
+      if ((map[p] & 2) != 0)
+       {
+         map[p] = 2;
+         continue;
+       }
+      s = pool->solvables + p;
+      m = 1;
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)
+           {
+             if (req == SOLVABLE_PREREQMARKER)
+               continue;
+             r = providedbyinstalled_xmap(pool, map, req, 0, 0);
+             if (!r)
+               {
+                 /* decided and miss */
+                 map[p] = 2;
+                 did = 0;
+                 break;
+               }
+             if (r == 16)
+               break;  /* undecided */
+             m |= r;   /* 1 | 9 | 17 */
+           }
+         if (req)
+           continue;
+         if ((m & 9) == 9)
+           m = 9;
+       }
+      if (s->conflicts)
+       {
+         int ispatch = 0;      /* see solver.c patch handling */
+
+         if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
+           ispatch = 1;
+         conp = s->repo->idarraydata + s->conflicts;
+         while ((con = *conp++) != 0)
+           {
+             if ((providedbyinstalled_xmap(pool, map, con, ispatch, multiversionmap) & 1) != 0)
+               {
+                 map[p] = 2;
+                 did = 0;
+                 break;
+               }
+             if ((m == 1 || m == 17) && ISRELDEP(con))
+               {
+                 con = dep2name(pool, con);
+                 if ((providedbyinstalled_xmap(pool, map, con, ispatch, multiversionmap) & 1) != 0)
+                   m = 9;
+               }
+           }
+         if (con)
+           continue;   /* found a conflict */
+       }
+      if (m != map[p])
+       {
+         map[p] = m;
+         did = 0;
+       }
+    }
+  queue_free(res);
+  queue_init_clone(res, pkgs);
+  for (i = 0; i < pkgs->count; i++)
+    {
+      m = map[pkgs->elements[i]];
+      if ((m & 9) == 9)
+       r = 1;
+      else if (m & 1)
+       r = -1;
+      else
+       r = 0;
+      res->elements[i] = r;
+    }
+  free(map);
+}
+
+void
+pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
+{
+  pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0);
+}
+
+void
+solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
+{
+  Pool *pool = solv->pool;
+  Map installedmap;
+  int i;
+  pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
+  pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0);
+  for (i = 0; i < res->count; i++) 
+    if (res->elements[i] != -1)
+      {    
+        Solvable *s = pool->solvables + pkgs->elements[i];
+        if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap))
+          res->elements[i] = -1;
+      }    
+  map_free(&installedmap);
+}
+
+void
+solver_printtrivial(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Queue in, out;
+  Id p;
+  const char *n; 
+  Solvable *s; 
+  int i;
+
+  queue_init(&in);
+  for (p = 1, s = pool->solvables + p; p < solv->pool->nsolvables; p++, s++)
+    {   
+      n = pool_id2str(pool, s->name);
+      if (strncmp(n, "patch:", 6) != 0 && strncmp(n, "pattern:", 8) != 0)
+        continue;
+      queue_push(&in, p); 
+    }   
+  if (!in.count)
+    {   
+      queue_free(&in);
+      return;
+    }   
+  queue_init(&out);
+  solver_trivial_installable(solv, &in, &out);
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "trivial installable status:\n");
+  for (i = 0; i < in.count; i++)
+    POOL_DEBUG(SOLV_DEBUG_RESULT, "  %s: %d\n", pool_solvid2str(pool, in.elements[i]), out.elements[i]);
+  POOL_DEBUG(SOLV_DEBUG_RESULT, "\n");
+  queue_free(&in);
+  queue_free(&out);
+}
+
+
diff --git a/libsolv-0.7.2/src/transaction.c b/libsolv-0.7.2/src/transaction.c
new file mode 100644 (file)
index 0000000..4a4189e
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2007-2015, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * transaction.c
+ *
+ * Transaction handling
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include "transaction.h"
+#include "solver.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "evr.h"
+#include "util.h"
+
+static int
+obsq_sortcmp(const void *ap, const void *bp, void *dp)
+{
+  Id a, b, oa, ob;
+  Pool *pool = dp;
+  Solvable *s, *oas, *obs;
+  int r;
+
+  a = ((Id *)ap)[0];
+  oa = ((Id *)ap)[1];
+  b = ((Id *)bp)[0];
+  ob = ((Id *)bp)[1];
+  if (a != b)
+    return a - b;
+  if (oa == ob)
+    return 0;
+  s = pool->solvables + a;
+  oas = pool->solvables + oa;
+  obs = pool->solvables + ob;
+  if (oas->name != obs->name)
+    {
+      /* bring "same name" obsoleters (i.e. upgraders) to front */
+      if (oas->name == s->name)
+        return -1;
+      if (obs->name == s->name)
+        return 1;
+      return strcmp(pool_id2str(pool, oas->name), pool_id2str(pool, obs->name));
+    }
+  r = pool_evrcmp(pool, oas->evr, obs->evr, EVRCMP_COMPARE);
+  if (r)
+    return -r; /* highest version first */
+  if (oas->arch != obs->arch)
+    {
+      /* bring same arch to front */
+      if (oas->arch == s->arch)
+        return -1;
+      if (obs->arch == s->arch)
+        return 1;
+    }
+  return oa - ob;
+}
+
+void
+transaction_all_obs_pkgs(Transaction *trans, Id p, Queue *pkgs)
+{
+  Pool *pool = trans->pool;
+  Solvable *s = pool->solvables + p;
+  Queue *ti = &trans->transaction_info;
+  Id q;
+  int i;
+
+  queue_empty(pkgs);
+  if (p <= 0 || !s->repo)
+    return;
+  if (s->repo == pool->installed)
+    {
+      q = trans->transaction_installed[p - pool->installed->start];
+      if (!q)
+       return;
+      if (q > 0)
+       {
+         /* only a single obsoleting package */
+         queue_push(pkgs, q);
+         return;
+       }
+      /* find which packages obsolete us */
+      for (i = 0; i < ti->count; i += 2)
+       if (ti->elements[i + 1] == p)
+         queue_push2(pkgs, p, ti->elements[i]);
+      /* sort obsoleters */
+      if (pkgs->count > 2)
+       solv_sort(pkgs->elements, pkgs->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
+      for (i = 0; i < pkgs->count; i += 2)
+       pkgs->elements[i / 2] = pkgs->elements[i + 1];
+      queue_truncate(pkgs, pkgs->count / 2);
+    }
+  else
+    {
+      /* find the packages we obsolete */
+      for (i = 0; i < ti->count; i += 2)
+       {
+         if (ti->elements[i] == p)
+           queue_push(pkgs, ti->elements[i + 1]);
+         else if (pkgs->count)
+           break;
+       }
+    }
+}
+
+Id
+transaction_obs_pkg(Transaction *trans, Id p)
+{
+  Pool *pool = trans->pool;
+  Solvable *s = pool->solvables + p;
+  Queue *ti;
+  int i;
+
+  if (p <= 0 || !s->repo)
+    return 0;
+  if (s->repo == pool->installed)
+    {
+      p = trans->transaction_installed[p - pool->installed->start];
+      return p < 0 ? -p : p;
+    }
+  ti = &trans->transaction_info;
+  for (i = 0; i < ti->count; i += 2)
+    if (ti->elements[i] == p)
+      return ti->elements[i + 1];
+  return 0;
+}
+
+
+/*
+ * calculate base type of transaction element
+ */
+
+static Id
+transaction_base_type(Transaction *trans, Id p)
+{
+  Pool *pool = trans->pool;
+  Solvable *s, *s2;
+  int r;
+  Id p2;
+
+  if (!MAPTST(&trans->transactsmap, p))
+    return SOLVER_TRANSACTION_IGNORE;
+  p2 = transaction_obs_pkg(trans, p);
+  if (pool->installed && pool->solvables[p].repo == pool->installed)
+    {
+      /* erase */
+      if (!p2)
+       return SOLVER_TRANSACTION_ERASE;
+      s = pool->solvables + p;
+      s2 = pool->solvables + p2;
+      if (s->name == s2->name)
+       {
+         if (s->evr == s2->evr && solvable_identical(s, s2))
+           return SOLVER_TRANSACTION_REINSTALLED;
+         r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+         if (r < 0)
+           return SOLVER_TRANSACTION_UPGRADED;
+         else if (r > 0)
+           return SOLVER_TRANSACTION_DOWNGRADED;
+         return SOLVER_TRANSACTION_CHANGED;
+       }
+      return SOLVER_TRANSACTION_OBSOLETED;
+    }
+  else
+    {
+      /* install or multiinstall */
+      int multi = trans->multiversionmap.size && MAPTST(&trans->multiversionmap, p);
+      if (multi)
+       {
+         if (p2)
+           {
+             s = pool->solvables + p;
+             s2 = pool->solvables + p2;
+             if (s->name == s2->name && s->arch == s2->arch && s->evr == s2->evr)
+               return SOLVER_TRANSACTION_MULTIREINSTALL;
+           }
+         return SOLVER_TRANSACTION_MULTIINSTALL;
+       }
+      if (!p2)
+       return SOLVER_TRANSACTION_INSTALL;
+      s = pool->solvables + p;
+      s2 = pool->solvables + p2;
+      if (s->name == s2->name)
+       {
+         if (s->evr == s2->evr && solvable_identical(s, s2))
+           return SOLVER_TRANSACTION_REINSTALL;
+         r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE);
+         if (r > 0)
+           return SOLVER_TRANSACTION_UPGRADE;
+         else if (r < 0)
+           return SOLVER_TRANSACTION_DOWNGRADE;
+         else
+           return SOLVER_TRANSACTION_CHANGE;
+       }
+      return SOLVER_TRANSACTION_OBSOLETES;
+    }
+}
+
+/* these packages do not get installed by the package manager */
+static inline int
+is_pseudo_package(Pool *pool, Solvable *s)
+{
+  const char *n = pool_id2str(pool, s->name);
+  if (*n == 'p' && !strncmp(n, "patch:", 6))
+    return 1;
+  if (*n == 'p' && !strncmp(n, "pattern:", 8))
+    return 1;
+  if (*n == 'p' && !strncmp(n, "product:", 8))
+    return 1;
+  if (*n == 'a' && !strncmp(n, "application:", 12))
+    return 1;
+  return 0;
+}
+
+/* these packages will never show up installed */
+static inline int
+is_noinst_pseudo_package(Pool *pool, Solvable *s)
+{
+  const char *n = pool_id2str(pool, s->name);
+  if (!strncmp(n, "patch:", 6))
+    return 1;
+  if (!strncmp(n, "pattern:", 8))
+    {
+#if defined(SUSE) && defined(ENABLE_LINKED_PKGS)
+      /* unlike normal patterns, autopatterns *can* be installed (via the package link),
+         so do not filter them */
+      if (s->provides)
+       {
+         Id prv, *prvp = s->repo->idarraydata + s->provides;
+         while ((prv = *prvp++) != 0)
+           if (ISRELDEP(prv) && !strcmp(pool_id2str(pool, prv), "autopattern()"))
+             return 0;
+       }
+#endif
+      return 1;
+    }
+  return 0;
+}
+
+static int
+obsoleted_by_pseudos_only(Transaction *trans, Id p)
+{
+  Pool *pool = trans->pool;
+  Queue q;
+  Id op;
+  int i;
+
+  op = transaction_obs_pkg(trans, p);
+  if (op && !is_pseudo_package(pool, pool->solvables + op))
+    return 0;
+  queue_init(&q);
+  transaction_all_obs_pkgs(trans, p, &q);
+  for (i = 0; i < q.count; i++)
+    if (!is_pseudo_package(pool, pool->solvables + q.elements[i]))
+      break;
+  i = !q.count || i < q.count ? 0 : 1;
+  queue_free(&q);
+  return i;
+}
+
+/*
+ * return type of transaction element
+ *
+ * filtering is needed if either not all packages are shown
+ * or replaces are not shown, as otherwise parts of the
+ * transaction might not be shown to the user */
+
+Id
+transaction_type(Transaction *trans, Id p, int mode)
+{
+  Pool *pool = trans->pool;
+  Solvable *s = pool->solvables + p;
+  Queue oq, rq;
+  Id type, q;
+  int i, j, ref = 0;
+
+  if (!s->repo)
+    return SOLVER_TRANSACTION_IGNORE;
+
+  /* XXX: SUSE only? */
+  if (!(mode & SOLVER_TRANSACTION_KEEP_PSEUDO) && is_noinst_pseudo_package(pool, s))
+    return SOLVER_TRANSACTION_IGNORE;
+
+  type = transaction_base_type(trans, p);
+
+  if (type == SOLVER_TRANSACTION_IGNORE)
+    return SOLVER_TRANSACTION_IGNORE;  /* not part of the transaction */
+
+  if ((mode & SOLVER_TRANSACTION_RPM_ONLY) != 0)
+    {
+      /* application wants to know what to feed to the package manager */
+      if (!(mode & SOLVER_TRANSACTION_KEEP_PSEUDO) && is_pseudo_package(pool, s))
+       return SOLVER_TRANSACTION_IGNORE;
+      if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL)
+       return type;
+      if (s->repo == pool->installed)
+       {
+         /* check if we're a real package that is obsoleted by pseudos */
+         if (!is_pseudo_package(pool, s) && obsoleted_by_pseudos_only(trans, s - pool->solvables))
+           return SOLVER_TRANSACTION_ERASE;
+         return SOLVER_TRANSACTION_IGNORE;     /* ignore as we're being obsoleted */
+       }
+      if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+       return SOLVER_TRANSACTION_MULTIINSTALL;
+      return SOLVER_TRANSACTION_INSTALL;
+    }
+
+  if ((mode & SOLVER_TRANSACTION_SHOW_MULTIINSTALL) == 0)
+    {
+      /* application wants to make no difference between install
+       * and multiinstall */
+      if (type == SOLVER_TRANSACTION_MULTIINSTALL)
+        type = SOLVER_TRANSACTION_INSTALL;
+      if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+        type = SOLVER_TRANSACTION_REINSTALL;
+    }
+
+  if ((mode & SOLVER_TRANSACTION_CHANGE_IS_REINSTALL) != 0)
+    {
+      /* application wants to make no difference between change
+       * and reinstall */
+      if (type == SOLVER_TRANSACTION_CHANGED)
+       type = SOLVER_TRANSACTION_REINSTALLED;
+      else if (type == SOLVER_TRANSACTION_CHANGE)
+       type = SOLVER_TRANSACTION_REINSTALL;
+    }
+
+  if (type == SOLVER_TRANSACTION_ERASE || type == SOLVER_TRANSACTION_INSTALL || type == SOLVER_TRANSACTION_MULTIINSTALL)
+    return type;
+
+  if (s->repo == pool->installed && (mode & SOLVER_TRANSACTION_SHOW_ACTIVE) == 0)
+    {
+      /* erase element and we're showing the passive side */
+      if (type == SOLVER_TRANSACTION_OBSOLETED && (mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
+       type = SOLVER_TRANSACTION_ERASE;
+      if (type == SOLVER_TRANSACTION_OBSOLETED && (mode & SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE) != 0)
+       type = SOLVER_TRANSACTION_UPGRADED;
+      return type;
+    }
+  if (s->repo != pool->installed && (mode & SOLVER_TRANSACTION_SHOW_ACTIVE) != 0)
+    {
+      /* install element and we're showing the active side */
+      if (type == SOLVER_TRANSACTION_OBSOLETES && (mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
+       type = SOLVER_TRANSACTION_INSTALL;
+      if (type == SOLVER_TRANSACTION_OBSOLETES && (mode & SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE) != 0)
+       type = SOLVER_TRANSACTION_UPGRADE;
+      return type;
+    }
+
+  /* the element doesn't match the show mode */
+
+  /* if we're showing all references, we can ignore this package */
+  if ((mode & (SOLVER_TRANSACTION_SHOW_ALL|SOLVER_TRANSACTION_SHOW_OBSOLETES)) == (SOLVER_TRANSACTION_SHOW_ALL|SOLVER_TRANSACTION_SHOW_OBSOLETES))
+    return SOLVER_TRANSACTION_IGNORE;
+
+  /* we're not showing all refs. check if some other package
+   * references us. If yes, it's safe to ignore this package,
+   * otherwise we need to map the type */
+
+  /* most of the time there's only one reference, so check it first */
+  q = transaction_obs_pkg(trans, p);
+
+  if ((mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
+    {
+      Solvable *sq = pool->solvables + q;
+      if (sq->name != s->name)
+       {
+         /* it's a replace but we're not showing replaces. map type. */
+         if (s->repo == pool->installed)
+           return SOLVER_TRANSACTION_ERASE;
+         else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+           return SOLVER_TRANSACTION_MULTIINSTALL;
+         else
+           return SOLVER_TRANSACTION_INSTALL;
+       }
+    }
+
+  /* if there's a match, p will be shown when q
+   * is processed */
+  if (transaction_obs_pkg(trans, q) == p)
+    return SOLVER_TRANSACTION_IGNORE;
+
+  /* too bad, a miss. check em all */
+  queue_init(&oq);
+  queue_init(&rq);
+  transaction_all_obs_pkgs(trans, p, &oq);
+  for (i = 0; i < oq.count; i++)
+    {
+      q = oq.elements[i];
+      if ((mode & SOLVER_TRANSACTION_SHOW_OBSOLETES) == 0)
+       {
+         Solvable *sq = pool->solvables + q;
+         if (sq->name != s->name)
+           continue;
+       }
+      /* check if we are referenced? */
+      if ((mode & SOLVER_TRANSACTION_SHOW_ALL) != 0)
+       {
+         transaction_all_obs_pkgs(trans, q, &rq);
+         for (j = 0; j < rq.count; j++)
+           if (rq.elements[j] == p)
+             {
+               ref = 1;
+               break;
+             }
+         if (ref)
+           break;
+       }
+      else if (transaction_obs_pkg(trans, q) == p)
+        {
+         ref = 1;
+         break;
+        }
+    }
+  queue_free(&oq);
+  queue_free(&rq);
+
+  if (!ref)
+    {
+      /* we're not referenced. map type */
+      if (s->repo == pool->installed)
+       return SOLVER_TRANSACTION_ERASE;
+      else if (type == SOLVER_TRANSACTION_MULTIREINSTALL)
+       return SOLVER_TRANSACTION_MULTIINSTALL;
+      else
+       return SOLVER_TRANSACTION_INSTALL;
+    }
+  /* there was a ref, so p is shown with some other package */
+  return SOLVER_TRANSACTION_IGNORE;
+}
+
+
+
+static int
+classify_cmp(const void *ap, const void *bp, void *dp)
+{
+  Transaction *trans = dp;
+  Pool *pool = trans->pool;
+  const Id *a = ap;
+  const Id *b = bp;
+  int r;
+
+  r = a[0] - b[0];
+  if (r)
+    return r;
+  r = a[2] - b[2];
+  if (r)
+    return a[2] && b[2] ? strcmp(pool_id2str(pool, a[2]), pool_id2str(pool, b[2])) : r;
+  r = a[3] - b[3];
+  if (r)
+    return a[3] && b[3] ? strcmp(pool_id2str(pool, a[3]), pool_id2str(pool, b[3])) : r;
+  return 0;
+}
+
+static int
+classify_cmp_pkgs(const void *ap, const void *bp, void *dp)
+{
+  Transaction *trans = dp;
+  Pool *pool = trans->pool;
+  Id a = *(Id *)ap;
+  Id b = *(Id *)bp;
+  Solvable *sa, *sb;
+
+  sa = pool->solvables + a;
+  sb = pool->solvables + b;
+  if (sa->name != sb->name)
+    return strcmp(pool_id2str(pool, sa->name), pool_id2str(pool, sb->name));
+  if (sa->evr != sb->evr)
+    {
+      int r = pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE);
+      if (r)
+       return r;
+    }
+  return a - b;
+}
+
+static inline void
+queue_push4(Queue *q, Id id1, Id id2, Id id3, Id id4)
+{
+  queue_push(q, id1);
+  queue_push(q, id2);
+  queue_push(q, id3);
+  queue_push(q, id4);
+}
+
+static inline void
+queue_unshift4(Queue *q, Id id1, Id id2, Id id3, Id id4)
+{
+  queue_unshift(q, id4);
+  queue_unshift(q, id3);
+  queue_unshift(q, id2);
+  queue_unshift(q, id1);
+}
+
+void
+transaction_classify(Transaction *trans, int mode, Queue *classes)
+{
+  Pool *pool = trans->pool;
+  int ntypes[SOLVER_TRANSACTION_MAXTYPE + 1];
+  Solvable *s, *sq;
+  Id v, vq, type, p, q;
+  int i, j;
+
+  queue_empty(classes);
+  memset(ntypes, 0, sizeof(ntypes));
+  /* go through transaction and classify each step */
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      p = trans->steps.elements[i];
+      s = pool->solvables + p;
+      type = transaction_type(trans, p, mode);
+      ntypes[type]++;
+      if (!pool->installed || s->repo != pool->installed)
+       continue;
+      /* don't report vendor/arch changes if we were mapped to erase. */
+      if (type == SOLVER_TRANSACTION_ERASE)
+       continue;
+      /* look at arch/vendor changes */
+      q = transaction_obs_pkg(trans, p);
+      if (!q)
+       continue;
+      sq = pool->solvables + q;
+
+      v = s->arch;
+      vq = sq->arch;
+      if (v != vq)
+       {
+         if ((mode & SOLVER_TRANSACTION_MERGE_ARCHCHANGES) != 0)
+           v = vq = 0;
+         for (j = 0; j < classes->count; j += 4)
+           if (classes->elements[j] == SOLVER_TRANSACTION_ARCHCHANGE && classes->elements[j + 2] == v && classes->elements[j + 3] == vq)
+             break;
+         if (j == classes->count)
+           queue_push4(classes, SOLVER_TRANSACTION_ARCHCHANGE, 1, v, vq);
+         else
+           classes->elements[j + 1]++;
+       }
+
+      v = s->vendor ? s->vendor : 1;
+      vq = sq->vendor ? sq->vendor : 1;
+      if (v != vq)
+       {
+         if ((mode & SOLVER_TRANSACTION_MERGE_VENDORCHANGES) != 0)
+           v = vq = 0;
+         for (j = 0; j < classes->count; j += 4)
+           if (classes->elements[j] == SOLVER_TRANSACTION_VENDORCHANGE && classes->elements[j + 2] == v && classes->elements[j + 3] == vq)
+             break;
+         if (j == classes->count)
+           queue_push4(classes, SOLVER_TRANSACTION_VENDORCHANGE, 1, v, vq);
+         else
+           classes->elements[j + 1]++;
+       }
+    }
+  /* now sort all vendor/arch changes */
+  if (classes->count > 4)
+    solv_sort(classes->elements, classes->count / 4, 4 * sizeof(Id), classify_cmp, trans);
+  /* finally add all classes. put erases last */
+  i = SOLVER_TRANSACTION_ERASE;
+  if (ntypes[i])
+    queue_unshift4(classes, i, ntypes[i], 0, 0);
+  for (i = SOLVER_TRANSACTION_MAXTYPE; i > 0; i--)
+    {
+      if (!ntypes[i])
+       continue;
+      if (i == SOLVER_TRANSACTION_ERASE)
+       continue;
+      queue_unshift4(classes, i, ntypes[i], 0, 0);
+    }
+}
+
+void
+transaction_classify_pkgs(Transaction *trans, int mode, Id class, Id from, Id to, Queue *pkgs)
+{
+  Pool *pool = trans->pool;
+  int i;
+  Id type, p, q;
+  Solvable *s, *sq;
+
+  queue_empty(pkgs);
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      p = trans->steps.elements[i];
+      s = pool->solvables + p;
+      if (class <= SOLVER_TRANSACTION_MAXTYPE)
+       {
+         type = transaction_type(trans, p, mode);
+         if (type == class)
+           queue_push(pkgs, p);
+         continue;
+       }
+      if (!pool->installed || s->repo != pool->installed)
+       continue;
+      q = transaction_obs_pkg(trans, p);
+      if (!q)
+       continue;
+      sq = pool->solvables + q;
+      if (class == SOLVER_TRANSACTION_ARCHCHANGE)
+       {
+         if ((!from && !to) || (s->arch == from && sq->arch == to))
+           queue_push(pkgs, p);
+         continue;
+       }
+      if (class == SOLVER_TRANSACTION_VENDORCHANGE)
+       {
+         Id v = s->vendor ? s->vendor : 1;
+         Id vq = sq->vendor ? sq->vendor : 1;
+         if ((!from && !to) || (v == from && vq == to))
+           queue_push(pkgs, p);
+         continue;
+       }
+    }
+  if (pkgs->count > 1)
+    solv_sort(pkgs->elements, pkgs->count, sizeof(Id), classify_cmp_pkgs, trans);
+}
+
+static void
+create_transaction_info(Transaction *trans, Queue *decisionq)
+{
+  Pool *pool = trans->pool;
+  Queue *ti = &trans->transaction_info;
+  Repo *installed = pool->installed;
+  int i, j, multi;
+  Id p, p2, pp2;
+  Solvable *s, *s2;
+
+  queue_empty(ti);
+  trans->transaction_installed = solv_free(trans->transaction_installed);
+  if (!installed)
+    return;    /* no info needed */
+  for (i = 0; i < decisionq->count; i++)
+    {
+      p = decisionq->elements[i];
+      if (p <= 0 || p == SYSTEMSOLVABLE)
+       continue;
+      s = pool->solvables + p;
+      if (!s->repo || s->repo == installed)
+       continue;
+      multi = trans->multiversionmap.size && MAPTST(&trans->multiversionmap, p);
+      FOR_PROVIDES(p2, pp2, s->name)
+       {
+         if (!MAPTST(&trans->transactsmap, p2))
+           continue;
+         s2 = pool->solvables + p2;
+         if (s2->repo != installed)
+           continue;
+         if (multi && (s->name != s2->name || s->evr != s2->evr || s->arch != s2->arch))
+           continue;
+         if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
+           continue;
+         if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
+           continue;
+         queue_push2(ti, p, p2);
+       }
+      if (s->obsoletes && !multi)
+       {
+         Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p2, pp2, obs)
+               {
+                 if (!MAPTST(&trans->transactsmap, p2))
+                   continue;
+                 s2 = pool->solvables + p2;
+                 if (s2->repo != installed)
+                   continue;
+                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
+                   continue;
+                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+                   continue;
+                 queue_push2(ti, p, p2);
+               }
+           }
+       }
+    }
+  if (ti->count > 2)
+    {
+      /* sort and unify */
+      solv_sort(ti->elements, ti->count / 2, 2 * sizeof(Id), obsq_sortcmp, pool);
+      for (i = j = 2; i < ti->count; i += 2)
+       {
+         if (ti->elements[i] == ti->elements[j - 2] && ti->elements[i + 1] == ti->elements[j - 1])
+           continue;
+         ti->elements[j++] = ti->elements[i];
+         ti->elements[j++] = ti->elements[i + 1];
+       }
+      queue_truncate(ti, j);
+    }
+
+  /* create transaction_installed helper */
+  /*   entry > 0: exactly one obsoleter, entry < 0: multiple obsoleters, -entry is "best" */
+  trans->transaction_installed = solv_calloc(installed->end - installed->start, sizeof(Id));
+  for (i = 0; i < ti->count; i += 2)
+    {
+      j = ti->elements[i + 1] - installed->start;
+      if (!trans->transaction_installed[j])
+       trans->transaction_installed[j] = ti->elements[i];
+      else
+       {
+         /* more than one package obsoletes us. compare to find "best" */
+         Id q[4];
+         if (trans->transaction_installed[j] > 0)
+           trans->transaction_installed[j] = -trans->transaction_installed[j];
+         q[0] = q[2] = ti->elements[i + 1];
+         q[1] = ti->elements[i];
+         q[3] = -trans->transaction_installed[j];
+         if (obsq_sortcmp(q, q + 2, pool) < 0)
+           trans->transaction_installed[j] = -ti->elements[i];
+       }
+    }
+}
+
+/* create a transaction from the decisionq */
+Transaction *
+transaction_create_decisionq(Pool *pool, Queue *decisionq, Map *multiversionmap)
+{
+  Repo *installed = pool->installed;
+  int i, needmulti;
+  Id p;
+  Solvable *s;
+  Transaction *trans;
+
+  trans = transaction_create(pool);
+  if (multiversionmap && !multiversionmap->size)
+    multiversionmap = 0;       /* ignore empty map */
+  queue_empty(&trans->steps);
+  map_init(&trans->transactsmap, pool->nsolvables);
+  needmulti = 0;
+  for (i = 0; i < decisionq->count; i++)
+    {
+      p = decisionq->elements[i];
+      s = pool->solvables + (p > 0 ? p : -p);
+      if (!s->repo)
+       continue;
+      if (installed && s->repo == installed && p < 0)
+       MAPSET(&trans->transactsmap, -p);
+      if (!(installed && s->repo == installed) && p > 0)
+       {
+         MAPSET(&trans->transactsmap, p);
+         if (multiversionmap && MAPTST(multiversionmap, p))
+           needmulti = 1;
+       }
+    }
+  MAPCLR(&trans->transactsmap, SYSTEMSOLVABLE);
+  if (needmulti)
+    map_init_clone(&trans->multiversionmap, multiversionmap);
+
+  create_transaction_info(trans, decisionq);
+
+  if (installed)
+    {
+      FOR_REPO_SOLVABLES(installed, p, s)
+       {
+         if (MAPTST(&trans->transactsmap, p))
+           queue_push(&trans->steps, p);
+       }
+    }
+  for (i = 0; i < decisionq->count; i++)
+    {
+      p = decisionq->elements[i];
+      if (p > 0 && MAPTST(&trans->transactsmap, p))
+        queue_push(&trans->steps, p);
+    }
+  return trans;
+}
+
+int
+transaction_installedresult(Transaction *trans, Queue *installedq)
+{
+  Pool *pool = trans->pool;
+  Repo *installed = pool->installed;
+  Solvable *s;
+  int i, cutoff;
+  Id p;
+
+  queue_empty(installedq);
+  /* first the new installs, than the kept packages */
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      p = trans->steps.elements[i];
+      s = pool->solvables + p;
+      if (installed && s->repo == installed)
+       continue;
+      queue_push(installedq, p);
+    }
+  cutoff = installedq->count;
+  if (installed)
+    {
+      FOR_REPO_SOLVABLES(installed, p, s)
+       if (!MAPTST(&trans->transactsmap, p))
+          queue_push(installedq, p);
+    }
+  return cutoff;
+}
+
+static void
+transaction_make_installedmap(Transaction *trans, Map *installedmap)
+{
+  Pool *pool = trans->pool;
+  Repo *installed = pool->installed;
+  Solvable *s;
+  Id p;
+  int i;
+
+  map_init(installedmap, pool->nsolvables);
+  for (i = 0; i < trans->steps.count; i++)
+    {
+      p = trans->steps.elements[i];
+      s = pool->solvables + p;
+      if (!installed || s->repo != installed)
+        MAPSET(installedmap, p);
+    }
+  if (installed)
+    {
+      FOR_REPO_SOLVABLES(installed, p, s)
+       if (!MAPTST(&trans->transactsmap, p))
+          MAPSET(installedmap, p);
+    }
+}
+
+long long
+transaction_calc_installsizechange(Transaction *trans)
+{
+  Map installedmap;
+  long long change;
+
+  transaction_make_installedmap(trans, &installedmap);
+  change = pool_calc_installsizechange(trans->pool, &installedmap);
+  map_free(&installedmap);
+  return change;
+}
+
+void
+transaction_calc_duchanges(Transaction *trans, DUChanges *mps, int nmps)
+{
+  Map installedmap;
+
+  transaction_make_installedmap(trans, &installedmap);
+  pool_calc_duchanges(trans->pool, &installedmap, mps, nmps);
+  map_free(&installedmap);
+}
+
+Transaction *
+transaction_create(Pool *pool)
+{
+  Transaction *trans = solv_calloc(1, sizeof(*trans));
+  trans->pool = pool;
+  return trans;
+}
+
+Transaction *
+transaction_create_clone(Transaction *srctrans)
+{
+  Transaction *trans = transaction_create(srctrans->pool);
+  queue_init_clone(&trans->steps, &srctrans->steps);
+  queue_init_clone(&trans->transaction_info, &srctrans->transaction_info);
+  if (srctrans->transaction_installed)
+    {
+      Repo *installed = srctrans->pool->installed;
+      trans->transaction_installed = solv_memdup2(srctrans->transaction_installed, installed->end - installed->start, sizeof(Id));
+    }
+  map_init_clone(&trans->transactsmap, &srctrans->transactsmap);
+  map_init_clone(&trans->multiversionmap, &srctrans->multiversionmap);
+  if (srctrans->orderdata)
+    transaction_clone_orderdata(trans, srctrans);
+  return trans;
+}
+
+void
+transaction_free(Transaction *trans)
+{
+  queue_free(&trans->steps);
+  queue_free(&trans->transaction_info);
+  trans->transaction_installed = solv_free(trans->transaction_installed);
+  map_free(&trans->transactsmap);
+  map_free(&trans->multiversionmap);
+  if (trans->orderdata)
+    transaction_free_orderdata(trans);
+  free(trans);
+}
+
diff --git a/libsolv-0.7.2/src/transaction.h b/libsolv-0.7.2/src/transaction.h
new file mode 100644 (file)
index 0000000..5b01354
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * transaction.h
+ *
+ */
+
+#ifndef LIBSOLV_TRANSACTION_H
+#define LIBSOLV_TRANSACTION_H
+
+#include "pooltypes.h"
+#include "queue.h"
+#include "bitmap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct s_Pool;
+struct s_DUChanges;
+struct s_TransactionOrderdata;
+
+typedef struct s_Transaction {
+  struct s_Pool *pool;         /* back pointer to pool */
+
+  Queue steps;                 /* the transaction steps */
+
+#ifdef LIBSOLV_INTERNAL
+  Queue transaction_info;
+  Id *transaction_installed;
+  Map transactsmap;
+  Map multiversionmap;
+
+  struct s_TransactionOrderdata *orderdata;
+#endif
+
+} Transaction;
+
+
+/* step types */
+#define SOLVER_TRANSACTION_IGNORE              0x00
+
+#define SOLVER_TRANSACTION_ERASE               0x10
+#define SOLVER_TRANSACTION_REINSTALLED         0x11
+#define SOLVER_TRANSACTION_DOWNGRADED          0x12
+#define SOLVER_TRANSACTION_CHANGED             0x13
+#define SOLVER_TRANSACTION_UPGRADED            0x14
+#define SOLVER_TRANSACTION_OBSOLETED           0x15
+
+#define SOLVER_TRANSACTION_INSTALL             0x20
+#define SOLVER_TRANSACTION_REINSTALL           0x21
+#define SOLVER_TRANSACTION_DOWNGRADE           0x22
+#define SOLVER_TRANSACTION_CHANGE              0x23
+#define SOLVER_TRANSACTION_UPGRADE             0x24
+#define SOLVER_TRANSACTION_OBSOLETES           0x25
+
+#define SOLVER_TRANSACTION_MULTIINSTALL                0x30
+#define SOLVER_TRANSACTION_MULTIREINSTALL      0x31
+
+#define SOLVER_TRANSACTION_MAXTYPE             0x3f
+
+/* modes */
+#define SOLVER_TRANSACTION_SHOW_ACTIVE         (1 << 0)
+#define SOLVER_TRANSACTION_SHOW_ALL            (1 << 1)
+#define SOLVER_TRANSACTION_SHOW_OBSOLETES      (1 << 2)
+#define SOLVER_TRANSACTION_SHOW_MULTIINSTALL   (1 << 3)
+#define SOLVER_TRANSACTION_CHANGE_IS_REINSTALL (1 << 4)
+#define SOLVER_TRANSACTION_MERGE_VENDORCHANGES (1 << 5)
+#define SOLVER_TRANSACTION_MERGE_ARCHCHANGES   (1 << 6)
+
+#define SOLVER_TRANSACTION_RPM_ONLY            (1 << 7)
+
+#define SOLVER_TRANSACTION_KEEP_PSEUDO         (1 << 8)
+
+#define SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE  (1 << 9)
+
+/* extra classifications */
+#define SOLVER_TRANSACTION_ARCHCHANGE          0x100
+#define SOLVER_TRANSACTION_VENDORCHANGE                0x101
+
+/* order flags */
+#define SOLVER_TRANSACTION_KEEP_ORDERDATA      (1 << 0)
+#define SOLVER_TRANSACTION_KEEP_ORDERCYCLES    (1 << 1)
+
+/* cycle severities */
+#define SOLVER_ORDERCYCLE_HARMLESS             0
+#define SOLVER_ORDERCYCLE_NORMAL               1
+#define SOLVER_ORDERCYCLE_CRITICAL             2
+
+extern Transaction *transaction_create(struct s_Pool *pool);
+extern Transaction *transaction_create_decisionq(struct s_Pool *pool, Queue *decisionq, Map *multiversionmap);
+extern Transaction *transaction_create_clone(Transaction *srctrans);
+extern void transaction_free(Transaction *trans);
+
+/* if p is installed, returns with pkg(s) obsolete p */
+/* if p is not installed, returns with pkg(s) we obsolete */
+extern Id   transaction_obs_pkg(Transaction *trans, Id p);
+extern void transaction_all_obs_pkgs(Transaction *trans, Id p, Queue *pkgs);
+
+/* return step type of a transaction element */
+extern Id   transaction_type(Transaction *trans, Id p, int mode);
+
+/* return sorted collection of all step types */
+/* classify_pkgs can be used to return all packages of a type */
+extern void transaction_classify(Transaction *trans, int mode, Queue *classes);
+extern void transaction_classify_pkgs(Transaction *trans, int mode, Id type, Id from, Id to, Queue *pkgs);
+
+/* return all packages that will be installed after the transaction is run*/
+/* The new packages are put at the head of the queue, the number of new
+   packages is returned */
+extern int transaction_installedresult(Transaction *trans, Queue *installedq);
+
+long long transaction_calc_installsizechange(Transaction *trans);
+void transaction_calc_duchanges(Transaction *trans, struct s_DUChanges *mps, int nmps);
+
+
+
+/* order a transaction */
+extern void transaction_order(Transaction *trans, int flags);
+
+/* roll your own order funcion:
+ * add pkgs free for installation to queue choices after chosen was
+ * installed. start with chosen = 0
+ * needs an ordered transaction created with SOLVER_TRANSACTION_KEEP_ORDERDATA */
+extern int  transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices);
+/* add obsoleted packages into transaction steps */
+extern void transaction_add_obsoleted(Transaction *trans);
+
+/* debug function, report problems found in the order */
+extern void transaction_check_order(Transaction *trans);
+
+/* order cycle introspection */
+extern void transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity);
+extern int transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q);
+
+extern void transaction_free_orderdata(Transaction *trans);
+extern void transaction_clone_orderdata(Transaction *trans, Transaction *srctrans);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsolv-0.7.2/src/userinstalled.c b/libsolv-0.7.2/src/userinstalled.c
new file mode 100644 (file)
index 0000000..0efcdd7
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2017, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* Functions that help getting/setting userinstalled packages. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "poolarch.h"
+#include "linkedpkg.h"
+
+static int
+get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
+{
+  return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
+}
+
+static int
+get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  int r;
+  r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
+  if (r)
+    return r;
+  return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
+}
+
+static void
+get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
+{
+  Id lastp = -1, lasta = -1;
+  int i, j;
+  if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
+    return;
+  if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+    solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
+  else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+    solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
+  else
+    solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
+  if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+    {
+      for (i = j = 0; i < q->count; i += 2)
+       if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
+         {
+           q->elements[j++] = lastp = q->elements[i];
+           q->elements[j++] = lasta = q->elements[i + 1];
+         }
+    }
+  else
+    {
+      for (i = j = 0; i < q->count; i++)
+       if (q->elements[i] != lastp)
+         q->elements[j++] = lastp = q->elements[i];
+    }
+  queue_truncate(q, j);
+}
+
+static void
+namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
+{
+  int i;
+  if (!pool->installed)
+    return;
+  for (i = 0; i < q->count; i += 2)
+    {
+      Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
+      FOR_PROVIDES(p, pp, name)
+       {
+         Solvable *s = pool->solvables + p;
+         if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
+           continue;
+         if (job)
+           queue_push(qout, job);
+         queue_push(qout, p);
+       }
+    }
+}
+
+void
+solver_get_userinstalled(Solver *solv, Queue *q, int flags)
+{
+  Pool *pool = solv->pool;
+  Id p, p2, pp;
+  Solvable *s;
+  Repo *installed = solv->installed;
+  int i, j;
+  Map userinstalled;
+  
+  map_init(&userinstalled, 0);
+  queue_empty(q);
+  /* first process jobs */
+  for (i = 0; i < solv->job.count; i += 2)
+    {
+      Id how = solv->job.elements[i];
+      Id what, select;
+      if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+       {
+         if (!userinstalled.size)
+           map_grow(&userinstalled, installed->end - installed->start);
+         what = solv->job.elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+           {
+             FOR_REPO_SOLVABLES(installed, p, s)
+               MAPSET(&userinstalled, p - installed->start);
+           }
+         FOR_JOB_SELECT(p, pp, select, what)
+           if (pool->solvables[p].repo == installed)
+             MAPSET(&userinstalled, p - installed->start);
+         continue;
+       }
+      if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
+       continue;
+      if ((how & SOLVER_NOTBYUSER) != 0)
+       continue;
+      what = solv->job.elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
+      FOR_JOB_SELECT(p, pp, select, what)
+        if (solv->decisionmap[p] > 0)
+         {
+           queue_push(q, p);
+#ifdef ENABLE_LINKED_PKGS
+           if (has_package_link(pool, pool->solvables + p))
+             {
+               int j;
+               Queue lq;
+               queue_init(&lq);
+               find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
+               for (j = 0; j < lq.count; j++)
+                 if (solv->decisionmap[lq.elements[j]] > 0)
+                   queue_push(q, lq.elements[j]);
+             }
+#endif
+         }
+    }
+  /* now process updates of userinstalled packages */
+  if (installed && userinstalled.size)
+    {
+      for (i = 1; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         if (p <= 0)
+           continue;
+         s = pool->solvables + p;
+         if (!s->repo)
+           continue;
+         if (s->repo == installed)
+           {
+             if (MAPTST(&userinstalled, p - installed->start))
+               queue_push(q, p);
+             continue;
+           }
+         /* new package, check if we replace a userinstalled one */
+         FOR_PROVIDES(p2, pp, s->name)
+           {
+             Solvable *ps = pool->solvables + p2;
+             if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+               continue;
+             if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+               continue;
+             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             queue_push(q, p);
+             break;
+           }
+         if (!p2 && s->repo != installed && s->obsoletes)
+           {
+             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+             while ((obs = *obsp++) != 0)
+               {
+                 FOR_PROVIDES(p2, pp, obs)
+                   {
+                     Solvable *ps = pool->solvables + p2;
+                     if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+                       continue;
+                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+                       continue;
+                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) 
+                       continue;
+                     queue_push(q, p); 
+                     break;
+                   }
+                 if (p2)
+                   break;
+               }
+           }
+       }
+    }
+  map_free(&userinstalled);
+
+  /* convert to desired output format */
+  if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+    {
+      int qcount = q->count;
+      queue_insertn(q, 0, qcount, 0);
+      for (i = j = 0; i < qcount; i++)
+       {
+         s = pool->solvables + q->elements[i + qcount];
+         q->elements[j++] = s->name;
+         q->elements[j++] = s->arch;
+       }
+    }
+  else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+    {
+      for (i = 0; i < q->count; i++)
+       {
+         s = pool->solvables + q->elements[i];
+         q->elements[i] = s->name;
+       }
+    }
+  /* sort and unify */
+  get_userinstalled_sort_uniq(pool, q, flags);
+
+  /* invert if asked for */
+  if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+    {
+      /* first generate queue with all installed packages */
+      Queue invq;
+      queue_init(&invq);
+      for (i = 1; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         if (p <= 0)
+           continue;
+         s = pool->solvables + p;
+         if (!s->repo)
+           continue;
+         if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+           queue_push2(&invq, s->name, s->arch);
+         else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+           queue_push(&invq, s->name);
+         else
+           queue_push(&invq, p);
+       }
+      /* push q on invq, just in case... */
+      queue_insertn(&invq, invq.count, q->count, q->elements);
+      get_userinstalled_sort_uniq(pool, &invq, flags);
+      /* subtract queues (easy as they are sorted and invq is a superset of q) */
+      if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+       {
+         if (q->count)
+           {
+             for (i = j = 0; i < invq.count; i += 2)
+               if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
+                 {
+                   invq.elements[i] = invq.elements[i + 1] = 0;
+                   j += 2;
+                   if (j >= q->count)
+                     break;
+                 }
+             queue_empty(q);
+           }
+         for (i = 0; i < invq.count; i += 2)
+           if (invq.elements[i])
+             queue_push2(q, invq.elements[i], invq.elements[i + 1]);
+       }
+      else
+       {
+         if (q->count)
+           {
+             for (i = j = 0; i < invq.count; i++)
+               if (invq.elements[i] == q->elements[j])
+                 {
+                   invq.elements[i] = 0;
+                   if (++j >= q->count)
+                     break;
+                 }
+             queue_empty(q);
+           }
+         for (i = 0; i < invq.count; i++)
+           if (invq.elements[i])
+             queue_push(q, invq.elements[i]);
+       }
+      queue_free(&invq);
+    }
+}
+
+void
+pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
+{
+  int i;
+
+  if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+    {
+      Queue invq;
+      Id p, lastid;
+      Solvable *s;
+      int bad;
+      if (!pool->installed)
+       return;
+      queue_init(&invq);
+      if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+       flags &= ~GET_USERINSTALLED_NAMES;      /* just in case */
+      FOR_REPO_SOLVABLES(pool->installed, p, s)
+       queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
+      if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+       {
+         /* for namearch we convert to packages */
+         namearch2solvables(pool, q, &invq, 0);
+         get_userinstalled_sort_uniq(pool, &invq, flags);
+         namearch2solvables(pool, q, &invq, 0);
+         flags = 0;
+       }
+      else
+       {
+         queue_insertn(&invq, invq.count, q->count, q->elements);
+         get_userinstalled_sort_uniq(pool, &invq, flags);
+         /* now the fun part, add q again, sort, and remove all dups */
+         queue_insertn(&invq, invq.count, q->count, q->elements);
+       }
+      if (invq.count > 1)
+       {
+         if ((flags & GET_USERINSTALLED_NAMES) != 0)
+           solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
+         else
+           solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
+       }
+      lastid = -1;
+      bad = 1;
+      for (i = 0; i < invq.count; i++)
+       {
+         if (invq.elements[i] == lastid)
+           {
+             bad = 1;
+             continue;
+           }
+         if (!bad)
+           queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+         bad = 0;
+         lastid = invq.elements[i];
+       }
+      if (!bad)
+       queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+      queue_free(&invq);
+    }
+  else
+    {
+      if (flags & GET_USERINSTALLED_NAMEARCH)
+       namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
+      else
+       {
+         for (i = 0; i < q->count; i++)
+           queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
+       }
+    }
+}
+
diff --git a/libsolv-0.7.2/src/util.c b/libsolv-0.7.2/src/util.c
new file mode 100644 (file)
index 0000000..65c8629
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "util.h"
+
+void
+solv_oom(size_t num, size_t len)
+{
+  if (num)
+    fprintf(stderr, "Out of memory allocating %zu*%zu bytes!\n", num, len);
+  else
+    fprintf(stderr, "Out of memory allocating %zu bytes!\n", len);
+  abort();
+  exit(1);
+}
+
+void *
+solv_malloc(size_t len)
+{
+  void *r = malloc(len ? len : 1);
+  if (!r)
+    solv_oom(0, len);
+  return r;
+}
+
+void *
+solv_malloc2(size_t num, size_t len)
+{
+  if (len && (num * len) / len != num)
+    solv_oom(num, len);
+  return solv_malloc(num * len);
+}
+
+void *
+solv_realloc(void *old, size_t len)
+{
+  if (old == 0)
+    old = malloc(len ? len : 1);
+  else
+    old = realloc(old, len ? len : 1);
+  if (!old)
+    solv_oom(0, len);
+  return old;
+}
+
+void *
+solv_realloc2(void *old, size_t num, size_t len)
+{
+  if (len && (num * len) / len != num)
+    solv_oom(num, len);
+  return solv_realloc(old, num * len);
+}
+
+void *
+solv_calloc(size_t num, size_t len)
+{
+  void *r;
+  if (num == 0 || len == 0)
+    r = malloc(1);
+  else
+    r = calloc(num, len);
+  if (!r)
+    solv_oom(num, len);
+  return r;
+}
+
+/* this was solv_realloc2(old, len, size), but we now overshoot
+ * for huge len sizes */
+void *
+solv_extend_realloc(void *old, size_t len, size_t size, size_t block)
+{
+  size_t xblock = (block + 1) << 5;
+  len = (len + block) & ~block;
+  if (len >= xblock && xblock)
+    {
+      xblock <<= 1;
+      while (len >= xblock && xblock)
+       xblock <<= 1;
+      if (xblock)
+       {
+         size_t nlen;
+          xblock = (xblock >> 5) - 1;
+         nlen = (len + xblock) & ~xblock;
+         if (nlen > len)
+           len = nlen;
+       }
+    }
+  return solv_realloc2(old, len, size);
+}
+
+void *
+solv_free(void *mem)
+{
+  if (mem)
+    free(mem);
+  return 0;
+}
+
+char *
+solv_strdup(const char *s)
+{
+  char *r;
+  if (!s)
+    return 0;
+  r = strdup(s);
+  if (!r)
+    solv_oom(0, strlen(s));
+  return r;
+}
+
+unsigned int
+solv_timems(unsigned int subtract)
+{
+  struct timeval tv;
+  unsigned int r;
+
+  if (gettimeofday(&tv, 0))
+    return 0;
+  r = (((unsigned int)tv.tv_sec >> 16) * 1000) << 16;
+  r += ((unsigned int)tv.tv_sec & 0xffff) * 1000;
+  r += (unsigned int)tv.tv_usec / 1000;
+  return r - subtract;
+}
+
+/* bsd's qsort_r has different arguments, so we define our
+   own version in case we need to do some clever mapping
+
+   see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html
+ */
+#if (defined(__GLIBC__) || defined(__NEWLIB__)) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R))
+
+void
+solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
+{
+# if defined(HAVE_QSORT_R)
+  qsort_r(base, nmemb, size, compar, compard);
+# else
+  /* backported for SLE10-SP2 */
+  __qsort_r(base, nmemb, size, compar, compard);
+# endif
+
+}
+
+#elif defined(HAVE_QSORT_R) /* not glibc, but has qsort_r() */
+
+struct solv_sort_data {
+  int (*compar)(const void *, const void *, void *);
+  void *compard;
+};
+
+static int
+solv_sort_helper(void *compard, const void *a, const void *b)
+{
+  struct solv_sort_data *d = compard;
+  return (*d->compar)(a, b, d->compard);
+}
+
+void
+solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
+{
+  struct solv_sort_data d;
+  d.compar = compar;
+  d.compard = compard;
+  qsort_r(base, nmemb, size, &d, solv_sort_helper);
+}
+
+#else /* not glibc and no qsort_r() */
+/* use own version of qsort if none available */
+#include "qsort_r.c"
+#endif
+
+char *
+solv_dupjoin(const char *str1, const char *str2, const char *str3)
+{
+  int l1, l2, l3;
+  char *s, *str;
+  l1 = str1 ? strlen(str1) : 0;
+  l2 = str2 ? strlen(str2) : 0;
+  l3 = str3 ? strlen(str3) : 0;
+  s = str = solv_malloc(l1 + l2 + l3 + 1);
+  if (l1)
+    {
+      strcpy(s, str1);
+      s += l1;
+    }
+  if (l2)
+    {
+      strcpy(s, str2);
+      s += l2;
+    }
+  if (l3)
+    {
+      strcpy(s, str3);
+      s += l3;
+    }
+  *s = 0;
+  return str;
+}
+
+char *
+solv_dupappend(const char *str1, const char *str2, const char *str3)
+{
+  char *str = solv_dupjoin(str1, str2, str3);
+  solv_free((void *)str1);
+  return str;
+}
+
+int
+solv_hex2bin(const char **strp, unsigned char *buf, int bufl)
+{
+  const char *str = *strp;
+  int i;
+
+  for (i = 0; i < bufl; i++)
+    {
+      int c = *str;
+      int d;
+      if (c >= '0' && c <= '9')
+        d = c - '0';
+      else if (c >= 'a' && c <= 'f')
+        d = c - ('a' - 10);
+      else if (c >= 'A' && c <= 'F')
+        d = c - ('A' - 10);
+      else
+       break;
+      c = str[1];
+      d <<= 4;
+      if (c >= '0' && c <= '9')
+        d |= c - '0';
+      else if (c >= 'a' && c <= 'f')
+        d |= c - ('a' - 10);
+      else if (c >= 'A' && c <= 'F')
+        d |= c - ('A' - 10);
+      else
+       break;
+      buf[i] = d;
+      str += 2;
+    }
+  *strp = str;
+  return i;
+}
+
+char *
+solv_bin2hex(const unsigned char *buf, int l, char *str)
+{
+  int i;
+  for (i = 0; i < l; i++, buf++)
+    {
+      int c = *buf >> 4;
+      *str++ = c < 10 ? c + '0' : c + ('a' - 10);
+      c = *buf & 15;
+      *str++ = c < 10 ? c + '0' : c + ('a' - 10);
+    }
+  *str = 0;
+  return str;
+}
+
+size_t
+solv_validutf8(const char *buf)
+{
+  const unsigned char *p;
+  int x;
+
+  for (p = (const unsigned char *)buf; (x = *p) != 0; p++)
+    {
+      if (x < 0x80)
+       continue;
+      if (x < 0xc0)
+       break;
+      if (x < 0xe0)
+       {
+         /* one byte to follow */
+         if ((p[1] & 0xc0) != 0x80)
+           break;
+         if ((x & 0x1e) == 0)
+           break;      /* not minimal */
+         p += 1;
+         continue;
+       }
+      if (x < 0xf0)
+       {
+         /* two bytes to follow */
+         if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)
+           break;
+         if ((x & 0x0f) == 0 && (p[1] & 0x20) == 0)
+           break;      /* not minimal */
+         if (x == 0xed && (p[1] & 0x20) != 0)
+           break;      /* d800-dfff surrogate */
+         if (x == 0xef && p[1] == 0xbf && (p[2] == 0xbe || p[2] == 0xbf))
+           break;      /* fffe or ffff */
+         p += 2;
+         continue;
+       }
+      if (x < 0xf8)
+       {
+         /* three bytes to follow */
+         if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)
+           break;
+         if ((x & 0x07) == 0 && (p[1] & 0x30) == 0)
+           break;      /* not minimal */
+         if ((x & 0x07) > 4 || ((x & 0x07) == 4 && (p[1] & 0x30) != 0))
+           break;      /* above 0x10ffff */
+         p += 3;
+         continue;
+       }
+      break;   /* maybe valid utf8, but above 0x10ffff */
+    }
+  return (const char *)p - buf;
+}
+
+char *
+solv_latin1toutf8(const char *buf)
+{
+  int l = 1;
+  const char *p;
+  char *r, *rp;
+
+  for (p = buf; *p; p++)
+    if ((*(const unsigned char *)p & 128) != 0)
+      l++;
+  r = rp = solv_malloc(p - buf + l);
+  for (p = buf; *p; p++)
+    {
+      if ((*(const unsigned char *)p & 128) != 0)
+       {
+         *rp++ = *(const unsigned char *)p & 64 ? 0xc3 : 0xc2;
+         *rp++ = *p & 0xbf;
+       }
+      else
+        *rp++ = *p;
+    }
+  *rp = 0;
+  return r;
+}
+
+char *
+solv_replacebadutf8(const char *buf, int replchar)
+{
+  size_t l, nl;
+  const char *p;
+  char *r = 0, *rp = 0;
+  int repllen, replin;
+
+  if (replchar < 0 || replchar > 0x10ffff)
+    replchar = 0xfffd;
+  if (!replchar)
+    repllen = replin = 0;
+  else if (replchar < 0x80)
+    {
+      repllen = 1;
+      replin = (replchar & 0x40) | 0x80;
+    }
+  else if (replchar < 0x800)
+    {
+      repllen = 2;
+      replin = 0x40;
+    }
+  else if (replchar < 0x10000)
+    {
+      repllen = 3;
+      replin = 0x60;
+    }
+  else
+    {
+      repllen = 4;
+      replin = 0x70;
+    }
+  for (;;)
+    {
+      for (p = buf, nl = 0; *p; )
+       {
+         l = solv_validutf8(p);
+         if (rp && l)
+           {
+             memcpy(rp, p, l);
+             rp += l;
+           }
+         nl += l;
+         p += l;
+         if (!*p)
+           break;
+         /* found a bad char, replace with replchar */
+         if (rp && replchar)
+           {
+             switch (repllen)
+               {
+               case 4:
+                 *rp++ = (replchar >> 18 & 0x3f) | 0x80;
+               case 3:
+                 *rp++ = (replchar >> 12 & 0x3f) | 0x80;
+               case 2:
+                 *rp++ = (replchar >> 6  & 0x3f) | 0x80;
+               default:
+                 *rp++ = (replchar       & 0x3f) | 0x80;
+               }
+             rp[-repllen] ^= replin;
+           }
+         nl += repllen;
+         p++;
+         while ((*(const unsigned char *)p & 0xc0) == 0x80)
+           p++;
+       }
+      if (rp)
+       break;
+      r = rp = solv_malloc(nl + 1);
+    }
+  *rp = 0;
+  return r;
+}
+
diff --git a/libsolv-0.7.2/src/util.h b/libsolv-0.7.2/src/util.h
new file mode 100644 (file)
index 0000000..5f7a93a
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * util.h
+ *
+ */
+
+#ifndef LIBSOLV_UTIL_H
+#define LIBSOLV_UTIL_H
+
+#include <stddef.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * malloc
+ * exits with error message on error
+ */
+extern void *solv_malloc(size_t);
+extern void *solv_malloc2(size_t, size_t);
+extern void *solv_calloc(size_t, size_t);
+extern void *solv_realloc(void *, size_t);
+extern void *solv_realloc2(void *, size_t, size_t);
+extern void *solv_extend_realloc(void *, size_t, size_t, size_t);
+extern void *solv_free(void *);
+extern char *solv_strdup(const char *);
+extern void solv_oom(size_t, size_t);
+extern unsigned int solv_timems(unsigned int subtract);
+extern void solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard);
+extern char *solv_dupjoin(const char *str1, const char *str2, const char *str3);
+extern char *solv_dupappend(const char *str1, const char *str2, const char *str3);
+extern int solv_hex2bin(const char **strp, unsigned char *buf, int bufl);
+extern char *solv_bin2hex(const unsigned char *buf, int l, char *str);
+extern size_t solv_validutf8(const char *buf);
+extern char *solv_latin1toutf8(const char *buf);
+extern char *solv_replacebadutf8(const char *buf, int replchar);
+
+
+static inline void *solv_extend(void *buf, size_t len, size_t nmemb, size_t size, size_t block)
+{
+  if (nmemb == 1)
+    {
+      if ((len & block) == 0)
+       buf = solv_extend_realloc(buf, len + 1, size, block);
+    }
+  else
+    {
+      if (((len - 1) | block) != ((len + nmemb - 1) | block))
+       buf = solv_extend_realloc(buf, len + nmemb, size, block);
+    }
+  return buf;
+}
+
+/**
+ * extend an array by reallocation and zero's the new section
+ * buf old pointer
+ * len current size
+ * nmbemb number of elements to add
+ * size size of each element
+ * block block size used to allocate the elements
+ */
+static inline void *solv_zextend(void *buf, size_t len, size_t nmemb, size_t size, size_t block)
+{
+  buf = solv_extend(buf, len, nmemb, size, block);
+  memset((char *)buf + len * size, 0, nmemb * size);
+  return buf;
+}
+
+static inline void *solv_extend_resize(void *buf, size_t len, size_t size, size_t block)
+{
+  if (len)
+    buf = solv_extend_realloc(buf, len, size, block);
+  return buf;
+}
+
+static inline void *solv_calloc_block(size_t len, size_t size, size_t block)
+{
+  void *buf;
+  if (!len)
+    return 0;
+  buf = solv_extend_realloc((void *)0, len, size, block);
+  memset(buf, 0, ((len + block) & ~block) * size);
+  return buf;
+}
+
+static inline void *solv_memdup(void *buf, size_t len)
+{
+  void *newbuf;
+  if (!buf)
+    return 0;
+  newbuf = solv_malloc(len);
+  if (len)
+    memcpy(newbuf, buf, len);
+  return newbuf;
+}
+
+static inline void *solv_memdup2(void *buf, size_t num, size_t len)
+{
+  void *newbuf;
+  if (!buf)
+    return 0;
+  newbuf = solv_malloc2(num, len);
+  if (num)
+    memcpy(newbuf, buf, num * len);
+  return newbuf;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSOLV_UTIL_H */
diff --git a/libsolv-0.7.2/test/CMakeLists.txt b/libsolv-0.7.2/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..92a5e7a
--- /dev/null
@@ -0,0 +1,11 @@
+FOREACH(tcdir testcases libsolv-zypptestcases)
+    IF(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}")
+        FILE(GLOB dirs "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}/[_a-zA-Z0-9]*")
+        FOREACH(dir ${dirs})
+           IF(IS_DIRECTORY ${dir})
+               FILE(RELATIVE_PATH myname "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}" ${dir})
+               ADD_TEST(${myname} ${CMAKE_CURRENT_SOURCE_DIR}/runtestcases ${CMAKE_BINARY_DIR}/tools/testsolv ${dir})
+           ENDIF(IS_DIRECTORY ${dir})
+        ENDFOREACH(dir)
+    ENDIF(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${tcdir}")
+ENDFOREACH(tcdir)
diff --git a/libsolv-0.7.2/test/runtestcases b/libsolv-0.7.2/test/runtestcases
new file mode 100755 (executable)
index 0000000..3d73663
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+cmd=$1
+dir=$2
+
+if test -z "$cmd" -o -z "$dir"; then
+  echo "Usage: runtestcases <cmd> <dir>";
+  exit 1
+fi
+
+ex=0
+for tc in $(find $dir -name \*.t) ; do
+  $cmd $tc >/dev/null
+  tex=$?
+  tcn="${tc#$dir/} .................................................."
+  tcn="${tcn:0:50}"
+  if test "$tex" -eq 0 ; then
+    echo "$tcn   Passed"
+  elif test "$tex" -eq 77 ; then
+    echo "$tcn   Skipped"
+  else
+    echo "$tcn***Failed"
+    ex=1
+  fi
+done
+exit $ex
diff --git a/libsolv-0.7.2/test/testcases/allowuninstall/conflict.t b/libsolv-0.7.2/test/testcases/allowuninstall/conflict.t
new file mode 100644 (file)
index 0000000..a66d322
--- /dev/null
@@ -0,0 +1,14 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 noarch
+#>=Con: b
+repo available 0 testtags <inline>
+#>=Pkg: b 1 1 noarch
+
+system x86_64 rpm system
+solverflags allowuninstall
+disable pkg a-1-1.noarch@system
+job install name b
+result transaction,problems <inline>
+#>problem a658cbaf info package a-1-1.noarch conflicts with b provided by b-1-1.noarch
+#>problem a658cbaf solution 567aa15d erase a-1-1.noarch@system
+#>problem a658cbaf solution e98e1a37 deljob install name b
diff --git a/libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t b/libsolv-0.7.2/test/testcases/allowuninstall/forcebest.t
new file mode 100644 (file)
index 0000000..38ade6f
--- /dev/null
@@ -0,0 +1,19 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 noarch
+#>=Req: b = 1-1
+#>=Pkg: b 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 noarch
+#>=Req: b = 2-1
+#>=Pkg: b 2 1 noarch
+
+system x86_64 rpm system
+disable pkg b-1-1.noarch@system
+disable pkg b-2-1.noarch@available
+job allowuninstall pkg a-1-1.noarch@system
+job allowuninstall pkg b-1-1.noarch@system
+job update name a [forcebest]
+result transaction,problems <inline>
+#>problem e6d3911d info nothing provides b = 2-1 needed by a-2-1.noarch
+#>problem e6d3911d solution 0011b04f allow a-1-1.noarch@system
+#>problem e6d3911d solution 44d189a0 erase a-1-1.noarch@system
diff --git a/libsolv-0.7.2/test/testcases/choose/default.t b/libsolv-0.7.2/test/testcases/choose/default.t
new file mode 100644 (file)
index 0000000..bb5b9f4
--- /dev/null
@@ -0,0 +1,13 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Req: Y
+#>=Pkg: B 1 1 noarch
+#>=Prv: Y
+#>=Pkg: A 1 1 noarch
+#>=Prv: Y
+system i686 rpm system
+job install name X
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install X-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/choose/enhanced.t b/libsolv-0.7.2/test/testcases/choose/enhanced.t
new file mode 100644 (file)
index 0000000..da6cfd5
--- /dev/null
@@ -0,0 +1,14 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Req: Y
+#>=Pkg: B 1 1 noarch
+#>=Prv: Y
+#>=Enh: X
+#>=Pkg: A 1 1 noarch
+#>=Prv: Y
+system i686 rpm system
+job install name X
+result transaction,problems <inline>
+#>install B-1-1.noarch@test
+#>install X-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/choose/oldversion.t b/libsolv-0.7.2/test/testcases/choose/oldversion.t
new file mode 100644 (file)
index 0000000..d83e2b6
--- /dev/null
@@ -0,0 +1,16 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Req: Y
+#>=Pkg: B 1 1 noarch
+#>=Prv: Y
+#>=Pkg: C 1 1 noarch
+#>=Prv: Y
+#>=Pkg: A 1 1 noarch
+#>=Prv: Y
+#>=Pkg: A 2 1 noarch
+system i686 rpm system
+job install name X
+result transaction,problems <inline>
+#>install B-1-1.noarch@test
+#>install X-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/choose/suggested.t b/libsolv-0.7.2/test/testcases/choose/suggested.t
new file mode 100644 (file)
index 0000000..cad4742
--- /dev/null
@@ -0,0 +1,14 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Req: Y
+#>=Sug: B
+#>=Pkg: B 1 1 noarch
+#>=Prv: Y
+#>=Pkg: A 1 1 noarch
+#>=Prv: Y
+system i686 rpm system
+job install name X
+result transaction,problems <inline>
+#>install B-1-1.noarch@test
+#>install X-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/choose/versioned.t b/libsolv-0.7.2/test/testcases/choose/versioned.t
new file mode 100644 (file)
index 0000000..d5089c8
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Req: Y
+#>=Pkg: B 1 1 noarch
+#>=Prv: Y = 2
+#>=Pkg: C 1 1 noarch
+#>=Prv: Y = 1.1
+#>=Pkg: A 1 1 noarch
+#>=Prv: Y = 1
+system i686 rpm system
+job install name X
+result transaction,problems <inline>
+#>install B-1-1.noarch@test
+#>install X-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/choose/versioned2.t b/libsolv-0.7.2/test/testcases/choose/versioned2.t
new file mode 100644 (file)
index 0000000..99c5712
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Req: Y
+#>=Pkg: B 1 1 noarch
+#>=Prv: Y < 2
+#>=Pkg: C 1 1 noarch
+#>=Prv: Y <= 2
+#>=Pkg: A 1 1 noarch
+#>=Prv: Y = 1
+system i686 rpm system
+job install name X
+result transaction,problems <inline>
+#>install C-1-1.noarch@test
+#>install X-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_dup.t b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_dup.t
new file mode 100644 (file)
index 0000000..afebcc4
--- /dev/null
@@ -0,0 +1,45 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Req: B1
+#>=Pkg: B1 1 1 noarch
+repo test 0 testtags <inline>
+#>=Pkg: A 1 2 noarch
+#>=Req: B1
+#>=Pkg: A 2 1 noarch
+#>=Req: B2 = 1
+#>=Pkg: B1 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+system i686 rpm system
+
+# check untargeted
+job distupgrade name A [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
+
+# check targeted
+nextjob
+job distupgrade name A = 2 [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
+
+# check targeted to 1-2
+nextjob
+job distupgrade name A = 1-2 [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>upgrade A-1-1.noarch@system A-1-2.noarch@test
+
+# check all packages
+nextjob
+job distupgrade all packages [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
+
diff --git a/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_in.t b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_in.t
new file mode 100644 (file)
index 0000000..e77a7f7
--- /dev/null
@@ -0,0 +1,16 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Req: B1
+#>=Pkg: B1 1 1 noarch
+repo test 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Req: B2 = 1
+#>=Pkg: B1 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+system i686 rpm system
+job install name A = 2 [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_up.t b/libsolv-0.7.2/test/testcases/cleandeps/cleandeps_up.t
new file mode 100644 (file)
index 0000000..5560a28
--- /dev/null
@@ -0,0 +1,50 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Req: B1
+#>=Pkg: B1 1 1 noarch
+#>=Pkg: C 1 1 noarch
+#>=Rec: D
+#>=Pkg: D 1 1 noarch
+repo test 0 testtags <inline>
+#>=Pkg: A 1 2 noarch
+#>=Req: B1
+#>=Pkg: A 2 1 noarch
+#>=Req: B2 = 1
+#>=Pkg: B1 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Pkg: C 1 1 noarch
+#>=Rec: D
+system i686 rpm system
+
+# check untargeted
+job update name A [cleandeps]
+job update name C [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
+
+# check targeted
+nextjob
+job update name A = 2 [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
+
+# check targeted to 1-2
+nextjob
+job update name A = 1-2 [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>upgrade A-1-1.noarch@system A-1-2.noarch@test
+
+# check all packages
+nextjob
+job update all packages [cleandeps]
+result transaction,problems,cleandeps <inline>
+#>cleandeps B1-1-1.noarch@system
+#>erase B1-1-1.noarch@system
+#>install B2-1-1.noarch@test
+#>upgrade A-1-1.noarch@system A-2-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/cleandeps/mistake.t b/libsolv-0.7.2/test/testcases/cleandeps/mistake.t
new file mode 100644 (file)
index 0000000..48099a8
--- /dev/null
@@ -0,0 +1,14 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Req: B
+#>=Pkg: B 2 1 noarch
+repo test 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Req: B = 1-1
+#>=Pkg: B 1 1 noarch
+system unset deb system
+job install name A = 2-1 [cleandeps]
+result transaction,problems <inline>
+#>problem b5abcb9c info package A-2-1.noarch requires B = 1-1, but none of the providers can be installed
+#>problem b5abcb9c solution 3b3a37c0 deljob install name A = 2-1 [cleandeps]
+#>problem b5abcb9c solution 3c170283 replace B-2-1.noarch@system B-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/and.t b/libsolv-0.7.2/test/testcases/cplxdeps/and.t
new file mode 100644 (file)
index 0000000..d4ef47e
--- /dev/null
@@ -0,0 +1,39 @@
+feature complex_deps
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 x86_64
+#>=Prv: A
+#>=Pkg: A2 1 1 x86_64
+#>=Prv: A
+#>=Pkg: B1 1 1 x86_64
+#>=Prv: B
+#>=Pkg: B2 1 1 x86_64
+#>=Prv: B
+#>=Pkg: X 1 1 x86_64
+#>=Req: A & B
+#>=Pkg: Y 1 1 x86_64
+#>=Con: A & B
+job install name X
+result rules <inline>
+#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d  X-1-1.x86_64@available
+#>rule pkg 8d94817282778a96505d2865a9b6c417  B1-1-1.x86_64@available
+#>rule pkg 8d94817282778a96505d2865a9b6c417  B2-1-1.x86_64@available
+#>rule pkg 8d94817282778a96505d2865a9b6c417 -X-1-1.x86_64@available
+#>rule pkg 9294f4d070a449a787a945d757c853ac  A1-1-1.x86_64@available
+#>rule pkg 9294f4d070a449a787a945d757c853ac  A2-1-1.x86_64@available
+#>rule pkg 9294f4d070a449a787a945d757c853ac -X-1-1.x86_64@available
+nextjob
+job install name Y
+result rules <inline>
+#>rule job 181d7955b2179c4ffdffedf0198f4807  Y-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -A1-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -B2-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -Y-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -A2-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -B2-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -Y-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -A1-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -B1-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -Y-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -A2-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -B1-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -Y-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/andor.t b/libsolv-0.7.2/test/testcases/cplxdeps/andor.t
new file mode 100644 (file)
index 0000000..f60745d
--- /dev/null
@@ -0,0 +1,73 @@
+feature complex_deps
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 x86_64
+#>=Prv: A
+#>=Pkg: A2 1 1 x86_64
+#>=Prv: A
+#>=Pkg: B1 1 1 x86_64
+#>=Prv: B
+#>=Pkg: B2 1 1 x86_64
+#>=Prv: B
+#>=Pkg: C1 1 1 x86_64
+#>=Prv: C
+#>=Pkg: C2 1 1 x86_64
+#>=Prv: C
+#>=Pkg: D1 1 1 x86_64
+#>=Prv: D
+#>=Pkg: D2 1 1 x86_64
+#>=Prv: D
+#>=Pkg: X 1 1 x86_64
+#>=Req: (A & B) | (C & D)
+#>=Pkg: Y 1 1 x86_64
+#>=Con: (A & B) | (C & D)
+job install name X
+result rules <inline>
+#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d  X-1-1.x86_64@available
+#>rule pkg 500f33fd32c5be8fb62896b334f580e7  B1-1-1.x86_64@available
+#>rule pkg 500f33fd32c5be8fb62896b334f580e7  B2-1-1.x86_64@available
+#>rule pkg 500f33fd32c5be8fb62896b334f580e7  D1-1-1.x86_64@available
+#>rule pkg 500f33fd32c5be8fb62896b334f580e7  D2-1-1.x86_64@available
+#>rule pkg 500f33fd32c5be8fb62896b334f580e7 -X-1-1.x86_64@available
+#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1  A1-1-1.x86_64@available
+#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1  A2-1-1.x86_64@available
+#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1  D1-1-1.x86_64@available
+#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1  D2-1-1.x86_64@available
+#>rule pkg 551b370e0a9430e9fcb2608b73b2d6f1 -X-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  B1-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  B2-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  C1-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  C2-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a -X-1-1.x86_64@available
+#>rule pkg e524681ade2cf622db027a5d989023c4  A1-1-1.x86_64@available
+#>rule pkg e524681ade2cf622db027a5d989023c4  A2-1-1.x86_64@available
+#>rule pkg e524681ade2cf622db027a5d989023c4  C1-1-1.x86_64@available
+#>rule pkg e524681ade2cf622db027a5d989023c4  C2-1-1.x86_64@available
+#>rule pkg e524681ade2cf622db027a5d989023c4 -X-1-1.x86_64@available
+nextjob
+job install name Y
+result rules <inline>
+#>rule job 181d7955b2179c4ffdffedf0198f4807  Y-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -A1-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -B2-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -Y-1-1.x86_64@available
+#>rule pkg 57f43a628a3173b517f444966e291dcc -C2-1-1.x86_64@available
+#>rule pkg 57f43a628a3173b517f444966e291dcc -D2-1-1.x86_64@available
+#>rule pkg 57f43a628a3173b517f444966e291dcc -Y-1-1.x86_64@available
+#>rule pkg 61248d82dae65a4a486fc7321a4e50ac -C2-1-1.x86_64@available
+#>rule pkg 61248d82dae65a4a486fc7321a4e50ac -D1-1-1.x86_64@available
+#>rule pkg 61248d82dae65a4a486fc7321a4e50ac -Y-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -A2-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -B2-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -Y-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -A1-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -B1-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -Y-1-1.x86_64@available
+#>rule pkg 919596a70a75b1cdd73c596397bf70e7 -C1-1-1.x86_64@available
+#>rule pkg 919596a70a75b1cdd73c596397bf70e7 -D2-1-1.x86_64@available
+#>rule pkg 919596a70a75b1cdd73c596397bf70e7 -Y-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -A2-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -B1-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -Y-1-1.x86_64@available
+#>rule pkg da2fe506ceca44a0c6eafab14af37505 -C1-1-1.x86_64@available
+#>rule pkg da2fe506ceca44a0c6eafab14af37505 -D1-1-1.x86_64@available
+#>rule pkg da2fe506ceca44a0c6eafab14af37505 -Y-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/if.t b/libsolv-0.7.2/test/testcases/cplxdeps/if.t
new file mode 100644 (file)
index 0000000..7e3dead
--- /dev/null
@@ -0,0 +1,36 @@
+feature complex_deps
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 x86_64
+#>=Prv: A
+#>=Pkg: A2 1 1 x86_64
+#>=Prv: A
+#>=Pkg: B1 1 1 x86_64
+#>=Prv: B
+#>=Pkg: B2 1 1 x86_64
+#>=Prv: B
+#>=Pkg: X 1 1 x86_64
+#>=Req: A <IF> B
+#>=Pkg: Y 1 1 x86_64
+#>=Con: A <IF> B
+job install name X
+result rules <inline>
+#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d  X-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761  A1-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761  A2-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -B1-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -X-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776  A1-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776  A2-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -B2-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -X-1-1.x86_64@available
+nextjob
+job install name Y
+result rules <inline>
+#>rule job 181d7955b2179c4ffdffedf0198f4807  Y-1-1.x86_64@available
+#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -A1-1-1.x86_64@available
+#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -Y-1-1.x86_64@available
+#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -A2-1-1.x86_64@available
+#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -Y-1-1.x86_64@available
+#>rule pkg 88a787532b7e170c57d67c5123982b0d  B1-1-1.x86_64@available
+#>rule pkg 88a787532b7e170c57d67c5123982b0d  B2-1-1.x86_64@available
+#>rule pkg 88a787532b7e170c57d67c5123982b0d -Y-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t b/libsolv-0.7.2/test/testcases/cplxdeps/ifelse.t
new file mode 100644 (file)
index 0000000..ef5bab9
--- /dev/null
@@ -0,0 +1,70 @@
+feature complex_deps
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 x86_64
+#>=Prv: A
+#>=Pkg: A2 1 1 x86_64
+#>=Prv: A
+#>=Pkg: B1 1 1 x86_64
+#>=Prv: B
+#>=Pkg: B2 1 1 x86_64
+#>=Prv: B
+#>=Pkg: C1 1 1 x86_64
+#>=Prv: C
+#>=Pkg: C2 1 1 x86_64
+#>=Prv: C
+#>=Pkg: X 1 1 x86_64
+#>=Req: A <IF> (B <ELSE> C)
+#>=Pkg: Y 1 1 x86_64
+#>=Con: A <IF> (B <ELSE> C)
+job install name X
+result rules <inline>
+#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d  X-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761  A1-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761  A2-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -B1-1-1.x86_64@available
+#>rule pkg 2c561cfd067b5ec806fd5c4fcd2ac761 -X-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776  A1-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776  A2-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -B2-1-1.x86_64@available
+#>rule pkg 72c9298b01fec76aae2722e2cdfdc776 -X-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  B1-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  B2-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  C1-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a  C2-1-1.x86_64@available
+#>rule pkg dee60af94c8ea49c9f99362dcb65806a -X-1-1.x86_64@available
+nextjob
+job install name Y
+result rules <inline>
+#>rule job 181d7955b2179c4ffdffedf0198f4807  Y-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -A1-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -B2-1-1.x86_64@available
+#>rule pkg 05a449a52d4792a0b847f482f5d7b509 -Y-1-1.x86_64@available
+#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -A1-1-1.x86_64@available
+#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -C1-1-1.x86_64@available
+#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -Y-1-1.x86_64@available
+#>rule pkg 46a6ab5f0c299f23867d74570cc179b8  B1-1-1.x86_64@available
+#>rule pkg 46a6ab5f0c299f23867d74570cc179b8  B2-1-1.x86_64@available
+#>rule pkg 46a6ab5f0c299f23867d74570cc179b8 -C1-1-1.x86_64@available
+#>rule pkg 46a6ab5f0c299f23867d74570cc179b8 -Y-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -A2-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -B2-1-1.x86_64@available
+#>rule pkg 85eac3dcd30bb5f51ad50b6644455822 -Y-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -A1-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -B1-1-1.x86_64@available
+#>rule pkg 8611a3d851adbd063a5d34a3ad4804e6 -Y-1-1.x86_64@available
+#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -A2-1-1.x86_64@available
+#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -C1-1-1.x86_64@available
+#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -Y-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -A2-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -B1-1-1.x86_64@available
+#>rule pkg ba6ba0db8d7421f83f7df6cc4df6df7d -Y-1-1.x86_64@available
+#>rule pkg c3f6b37277eb48011d0e68c11323ea3e  B1-1-1.x86_64@available
+#>rule pkg c3f6b37277eb48011d0e68c11323ea3e  B2-1-1.x86_64@available
+#>rule pkg c3f6b37277eb48011d0e68c11323ea3e -C2-1-1.x86_64@available
+#>rule pkg c3f6b37277eb48011d0e68c11323ea3e -Y-1-1.x86_64@available
+#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -A2-1-1.x86_64@available
+#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -C2-1-1.x86_64@available
+#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -Y-1-1.x86_64@available
+#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -A1-1-1.x86_64@available
+#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -C2-1-1.x86_64@available
+#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -Y-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/or.t b/libsolv-0.7.2/test/testcases/cplxdeps/or.t
new file mode 100644 (file)
index 0000000..7446799
--- /dev/null
@@ -0,0 +1,34 @@
+feature complex_deps
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 x86_64
+#>=Prv: A
+#>=Pkg: A2 1 1 x86_64
+#>=Prv: A
+#>=Pkg: B1 1 1 x86_64
+#>=Prv: B
+#>=Pkg: B2 1 1 x86_64
+#>=Prv: B
+#>=Pkg: X 1 1 x86_64
+#>=Req: A | B
+#>=Pkg: Y 1 1 x86_64
+#>=Con: A | B
+job install name X
+result rules <inline>
+#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d  X-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  A1-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  A2-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  B1-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  B2-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 -X-1-1.x86_64@available
+nextjob
+job install name Y
+result rules <inline>
+#>rule job 181d7955b2179c4ffdffedf0198f4807  Y-1-1.x86_64@available
+#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -A1-1-1.x86_64@available
+#>rule pkg 0fd77d3093bfb9bc85606ae155bee7e0 -Y-1-1.x86_64@available
+#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -A2-1-1.x86_64@available
+#>rule pkg 45e18ba2f65a39574c1f4b1c77b565ec -Y-1-1.x86_64@available
+#>rule pkg 69d83d7a676b6a65f79a6fc5bcf2ca6e -B1-1-1.x86_64@available
+#>rule pkg 69d83d7a676b6a65f79a6fc5bcf2ca6e -Y-1-1.x86_64@available
+#>rule pkg d6e57752cc50ab9fc0a218fda6dbf172 -B2-1-1.x86_64@available
+#>rule pkg d6e57752cc50ab9fc0a218fda6dbf172 -Y-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/cplxdeps/orand.t b/libsolv-0.7.2/test/testcases/cplxdeps/orand.t
new file mode 100644 (file)
index 0000000..8a5108a
--- /dev/null
@@ -0,0 +1,87 @@
+feature complex_deps
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 x86_64
+#>=Prv: A
+#>=Pkg: A2 1 1 x86_64
+#>=Prv: A
+#>=Pkg: B1 1 1 x86_64
+#>=Prv: B
+#>=Pkg: B2 1 1 x86_64
+#>=Prv: B
+#>=Pkg: C1 1 1 x86_64
+#>=Prv: C
+#>=Pkg: C2 1 1 x86_64
+#>=Prv: C
+#>=Pkg: D1 1 1 x86_64
+#>=Prv: D
+#>=Pkg: D2 1 1 x86_64
+#>=Prv: D
+#>=Pkg: X 1 1 x86_64
+#>=Req: (A | B) & (C | D)
+#>=Pkg: Y 1 1 x86_64
+#>=Con: (A | B) & (C | D)
+job install name X
+result rules <inline>
+#>rule job 3986285ed3e7fa05cb3367ca1e7f0d3d  X-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  A1-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  A2-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  B1-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1  B2-1-1.x86_64@available
+#>rule pkg 7d7fb2231997a6ba15d2c7c1d11d4ff1 -X-1-1.x86_64@available
+#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc  C1-1-1.x86_64@available
+#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc  C2-1-1.x86_64@available
+#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc  D1-1-1.x86_64@available
+#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc  D2-1-1.x86_64@available
+#>rule pkg cb5c72eeb44f643493f3df3e7e62f9dc -X-1-1.x86_64@available
+nextjob
+job install name Y
+result rules <inline>
+#>rule job 181d7955b2179c4ffdffedf0198f4807  Y-1-1.x86_64@available
+#>rule pkg 16cbba917580ca34f91961a74cfd07c2 -B1-1-1.x86_64@available
+#>rule pkg 16cbba917580ca34f91961a74cfd07c2 -D1-1-1.x86_64@available
+#>rule pkg 16cbba917580ca34f91961a74cfd07c2 -Y-1-1.x86_64@available
+#>rule pkg 1db9a5695f062c299dbb815adf4f2374 -A1-1-1.x86_64@available
+#>rule pkg 1db9a5695f062c299dbb815adf4f2374 -D2-1-1.x86_64@available
+#>rule pkg 1db9a5695f062c299dbb815adf4f2374 -Y-1-1.x86_64@available
+#>rule pkg 22f3f4d055f6daaeb6f5622907a9206f -A2-1-1.x86_64@available
+#>rule pkg 22f3f4d055f6daaeb6f5622907a9206f -D1-1-1.x86_64@available
+#>rule pkg 22f3f4d055f6daaeb6f5622907a9206f -Y-1-1.x86_64@available
+#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -A1-1-1.x86_64@available
+#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -C1-1-1.x86_64@available
+#>rule pkg 2823a39a3d1ae2f7d45ca97e97f5bf8e -Y-1-1.x86_64@available
+#>rule pkg 33a12cadfd9dd12dc60a3e250ae9f92a -B2-1-1.x86_64@available
+#>rule pkg 33a12cadfd9dd12dc60a3e250ae9f92a -C2-1-1.x86_64@available
+#>rule pkg 33a12cadfd9dd12dc60a3e250ae9f92a -Y-1-1.x86_64@available
+#>rule pkg 48a9e473b42b382f7cf46ac33e98ba76 -B2-1-1.x86_64@available
+#>rule pkg 48a9e473b42b382f7cf46ac33e98ba76 -C1-1-1.x86_64@available
+#>rule pkg 48a9e473b42b382f7cf46ac33e98ba76 -Y-1-1.x86_64@available
+#>rule pkg 714e9978244eb65bc57b7c4fac5a0430 -B1-1-1.x86_64@available
+#>rule pkg 714e9978244eb65bc57b7c4fac5a0430 -C1-1-1.x86_64@available
+#>rule pkg 714e9978244eb65bc57b7c4fac5a0430 -Y-1-1.x86_64@available
+#>rule pkg 86df5aaf92e5ea31f8efedf442fd431e -B1-1-1.x86_64@available
+#>rule pkg 86df5aaf92e5ea31f8efedf442fd431e -C2-1-1.x86_64@available
+#>rule pkg 86df5aaf92e5ea31f8efedf442fd431e -Y-1-1.x86_64@available
+#>rule pkg 87928b09a90963097188f62d00bfb3d9 -B2-1-1.x86_64@available
+#>rule pkg 87928b09a90963097188f62d00bfb3d9 -D1-1-1.x86_64@available
+#>rule pkg 87928b09a90963097188f62d00bfb3d9 -Y-1-1.x86_64@available
+#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -A2-1-1.x86_64@available
+#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -C1-1-1.x86_64@available
+#>rule pkg 92d66d3ad45eaa7d443a05245c9a0eaf -Y-1-1.x86_64@available
+#>rule pkg b5f410efacf9eb0b2b725e3e7b7d6e93 -B1-1-1.x86_64@available
+#>rule pkg b5f410efacf9eb0b2b725e3e7b7d6e93 -D2-1-1.x86_64@available
+#>rule pkg b5f410efacf9eb0b2b725e3e7b7d6e93 -Y-1-1.x86_64@available
+#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -A2-1-1.x86_64@available
+#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -C2-1-1.x86_64@available
+#>rule pkg c450fe9f8321047ee2cd1e6fc9f34df6 -Y-1-1.x86_64@available
+#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -A1-1-1.x86_64@available
+#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -C2-1-1.x86_64@available
+#>rule pkg da9eb4921698e87f788a89bd25cf75b8 -Y-1-1.x86_64@available
+#>rule pkg dfd799532ba714fd139acf879992c2de -A2-1-1.x86_64@available
+#>rule pkg dfd799532ba714fd139acf879992c2de -D2-1-1.x86_64@available
+#>rule pkg dfd799532ba714fd139acf879992c2de -Y-1-1.x86_64@available
+#>rule pkg eab097949c9719f1e7e196241c6ec0f4 -B2-1-1.x86_64@available
+#>rule pkg eab097949c9719f1e7e196241c6ec0f4 -D2-1-1.x86_64@available
+#>rule pkg eab097949c9719f1e7e196241c6ec0f4 -Y-1-1.x86_64@available
+#>rule pkg ede76598bf66f6be0b1fa3439c97a71b -A1-1-1.x86_64@available
+#>rule pkg ede76598bf66f6be0b1fa3439c97a71b -D1-1-1.x86_64@available
+#>rule pkg ede76598bf66f6be0b1fa3439c97a71b -Y-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_allowuninstall.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_allowuninstall.t
new file mode 100644 (file)
index 0000000..86a8af9
--- /dev/null
@@ -0,0 +1,13 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+#>=Pkg: b 2 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 i586
+#>=Con: b = 1-1
+#>=Pkg: b 1 1 i586
+system i686 * system
+solverflags !dupallowarchchange allowuninstall
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase b-2-1.i686@system
+#>upgrade a-1-1.i686@system a-2-1.i586@available
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion1.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion1.t
new file mode 100644 (file)
index 0000000..326de7a
--- /dev/null
@@ -0,0 +1,91 @@
+# test dup with multiversion packages
+#
+# part 1: simple update
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 i686
+system i686 * system
+
+job multiversion name a
+job distupgrade all packages
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+nextjob
+
+job multiversion name a
+job distupgrade repo available
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+### same with keeporphans
+
+nextjob
+
+solverflags keeporphans
+job multiversion name a
+job distupgrade all packages
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+nextjob
+
+solverflags keeporphans
+job multiversion name a
+job distupgrade repo available
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+### same with allowuninstall
+
+nextjob
+
+solverflags allowuninstall
+job multiversion name a
+job distupgrade all packages
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+nextjob
+
+solverflags allowuninstall
+job multiversion name a
+job distupgrade repo available
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+### same with allowuninstall and keeporphans
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job multiversion name a
+job distupgrade all packages
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job multiversion name a
+job distupgrade repo available
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+
+
+
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion2.t
new file mode 100644 (file)
index 0000000..6708896
--- /dev/null
@@ -0,0 +1,109 @@
+# test dup with multiversion packages
+# same as with dup_multiversion1, but we can't keep the orphan
+
+#
+# part 1: simple update
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+#>=Pkg: b 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 i686
+#>=Pkg: b 2 1 i686
+#>=Con: a = 1-1
+system i686 * system
+
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>install a-2-1.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+nextjob
+
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>install a-2-1.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with keeporphans, this will result in problems as we cannot keep the orphan
+
+nextjob
+
+solverflags keeporphans
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+#>problem 4d4de423 info package b-2-1.i686 conflicts with a = 1-1 provided by a-1-1.i686
+#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
+#>problem 4d4de423 solution 2cf4745c replace a-1-1.i686@system a-2-1.i686@available
+#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
+#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
+
+nextjob
+
+solverflags keeporphans
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>install a-2-1.i686@available
+#>problem 4d4de423 info package b-2-1.i686 conflicts with a = 1-1 provided by a-1-1.i686
+#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
+#>problem 4d4de423 solution 2cf4745c replace a-1-1.i686@system a-2-1.i686@available
+#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
+#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
+
+### same with allowuninstall
+
+nextjob
+
+solverflags allowuninstall
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>install a-2-1.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+nextjob
+
+solverflags allowuninstall
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>install a-2-1.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with allowuninstall and keeporphans
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job multiversion name a
+job distupgrade all packages
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>install a-2-1.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job multiversion name a
+job distupgrade repo available
+# a-1-1 is treated as orphaned and stays behind
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>install a-2-1.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_multiversion3.t
new file mode 100644 (file)
index 0000000..97eb20f
--- /dev/null
@@ -0,0 +1,89 @@
+# test dup with multiversion packages where we cannot install the
+# target. Should give problems except for allowuninstall.
+#
+# part 1: simple update
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 i686
+#>=Req: c
+system i686 * system
+
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>problem fc3d647e info nothing provides c needed by a-2-1.i686
+#>problem fc3d647e solution 179b72ed allow a-1-1.i686@system
+#>problem fc3d647e solution e5fc66c9 erase a-1-1.i686@system
+
+nextjob
+
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>problem fc3d647e info nothing provides c needed by a-2-1.i686
+#>problem fc3d647e solution 179b72ed allow a-1-1.i686@system
+#>problem fc3d647e solution e5fc66c9 erase a-1-1.i686@system
+
+### same with keeporphans
+
+nextjob
+
+solverflags keeporphans
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>problem 771581fd info nothing provides c needed by a-2-1.i686
+#>problem 771581fd solution 179b72ed allow a-1-1.i686@system
+#>problem 771581fd solution 2cf4745c erase a-1-1.i686@system
+
+nextjob
+
+solverflags keeporphans
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>problem 771581fd info nothing provides c needed by a-2-1.i686
+#>problem 771581fd solution 179b72ed allow a-1-1.i686@system
+#>problem 771581fd solution 2cf4745c erase a-1-1.i686@system
+
+### same with allowuninstall
+
+nextjob
+
+solverflags allowuninstall
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+
+
+nextjob
+
+solverflags allowuninstall
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+
+
+### same with allowuninstall and keeporphans
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job multiversion name a
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job multiversion name a
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+
+
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_noarchchange.t
new file mode 100644 (file)
index 0000000..8231561
--- /dev/null
@@ -0,0 +1,16 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+#>=Pkg: b 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 i586
+#>=Pkg: b 2 1 i586
+#>=Pkg: b 2 1 i686
+system i686 * system
+solverflags !dupallowarchchange
+job distupgrade all packages
+result transaction,problems <inline>
+#>problem 7724e627 info problem with installed package a-1-1.i686
+#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system
+#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-2-1.i586@available
+#>upgrade a-1-1.i686@system a-2-1.i586@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan1.t
new file mode 100644 (file)
index 0000000..3c4976a
--- /dev/null
@@ -0,0 +1,78 @@
+# test dup with orphaned packages
+#
+# part 1: simple update
+#
+# dup should leave orphaned a installed
+#
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+#>=Pkg: b 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: b 2 1 i686
+system i686 * system
+
+job distupgrade all packages
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+nextjob
+
+job distupgrade repo available
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with keeporphans
+
+nextjob
+
+solverflags keeporphans
+job distupgrade all packages
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+nextjob
+
+solverflags keeporphans
+job distupgrade repo available
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with allowuninstall
+
+nextjob
+
+solverflags allowuninstall
+job distupgrade all packages
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+nextjob
+
+solverflags allowuninstall
+job distupgrade repo available
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with allowuninstall and keeporphans
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job distupgrade all packages
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job distupgrade repo available
+result transaction,problems <inline>
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan2.t
new file mode 100644 (file)
index 0000000..f4e746e
--- /dev/null
@@ -0,0 +1,98 @@
+# test dup with orphaned packages
+#
+# part 2: update conflicts with the orphan
+#
+# dup should leave orphaned a installed
+# for "distupgrade repo available", a is not involved
+# in the dup and thus not considered orphan.
+#
+
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+#>=Pkg: b 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: b 2 1 i686
+#>=Con: a
+system i686 * system
+
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+nextjob
+
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>problem 4d4de423 info package b-2-1.i686 conflicts with a provided by a-1-1.i686
+#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
+#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
+#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+### keeporphans
+
+nextjob
+
+solverflags keeporphans
+job distupgrade all packages
+result transaction,problems <inline>
+#>problem 4d4de423 info package b-2-1.i686 conflicts with a provided by a-1-1.i686
+#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
+#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
+#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
+
+nextjob
+
+solverflags keeporphans
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>problem 4d4de423 info package b-2-1.i686 conflicts with a provided by a-1-1.i686
+#>problem 4d4de423 solution 2cf4745c erase a-1-1.i686@system
+#>problem 4d4de423 solution 5a433aff allow b-1-1.i686@system
+#>problem 4d4de423 solution ce4305f2 erase b-1-1.i686@system
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with allowuninstall
+
+nextjob
+
+solverflags allowuninstall
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+nextjob
+
+solverflags allowuninstall
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase b-1-1.i686@system
+
+
+### same with allowuninstall and keeporphans
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job distupgrade all packages
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+nextjob
+
+solverflags allowuninstall keeporphans
+job distupgrade repo available
+result transaction,problems <inline>
+#>erase a-1-1.i686@system
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+
diff --git a/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t b/libsolv-0.7.2/test/testcases/distupgrade/dup_orphan3.t
new file mode 100644 (file)
index 0000000..361649a
--- /dev/null
@@ -0,0 +1,98 @@
+# test dup with orphaned packages
+#
+# part 3: a is not really an orphan, but cannot be downgraded
+#
+
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 i686
+#>=Pkg: b 1 1 i686
+repo available 0 testtags <inline>
+#>=Pkg: a 1 0 i686
+#>=Pkg: b 2 1 i686
+system i686 * system
+
+solverflags !dupallowdowngrade
+job distupgrade all packages
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+#>problem 7724e627 info problem with installed package a-1-1.i686
+#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system
+#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available
+
+nextjob
+
+solverflags !dupallowdowngrade
+job distupgrade repo available
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+#>problem 7724e627 info problem with installed package a-1-1.i686
+#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system
+#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available
+
+### keeporphans
+
+nextjob
+
+solverflags !dupallowdowngrade keeporphans
+job distupgrade all packages
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+#>problem 7724e627 info problem with installed package a-1-1.i686
+#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system
+#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available
+
+nextjob
+
+solverflags !dupallowdowngrade keeporphans
+job distupgrade repo available
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+#>problem 7724e627 info problem with installed package a-1-1.i686
+#>problem 7724e627 solution 25ae2253 allow a-1-1.i686@system
+#>problem 7724e627 solution 2cf4745c replace a-1-1.i686@system a-1-0.i686@available
+
+### same with allowuninstall
+
+nextjob
+
+solverflags !dupallowdowngrade allowuninstall
+job distupgrade all packages
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+nextjob
+
+solverflags !dupallowdowngrade allowuninstall
+job distupgrade repo available
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+### same with allowuninstall and keeporphans
+
+nextjob
+
+solverflags !dupallowdowngrade allowuninstall keeporphans
+job distupgrade all packages
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+nextjob
+
+solverflags !dupallowdowngrade allowuninstall keeporphans
+job distupgrade repo available
+result transaction,problems <inline>
+#>downgrade a-1-1.i686@system a-1-0.i686@available
+#>upgrade b-1-1.i686@system b-2-1.i686@available
+
+
+
diff --git a/libsolv-0.7.2/test/testcases/evrcmp/caret.t b/libsolv-0.7.2/test/testcases/evrcmp/caret.t
new file mode 100644 (file)
index 0000000..d0c3a07
--- /dev/null
@@ -0,0 +1,74 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A1 1.0 0
+#>=Pkg: A2 1.0^ 0
+system i686 rpm system
+
+evrcmp 1.0~rc1 1.0~rc1
+evrcmp 1.0~rc1 1.0
+evrcmp 1.0 1.0~rc1
+evrcmp 1.0~rc1 1.0~rc2
+evrcmp 1.0~rc2 1.0~rc1
+evrcmp 1.0~rc1~git123 1.0~rc1~git123
+evrcmp 1.0~rc1~git123 1.0~rc1
+evrcmp 1.0~rc1 1.0~rc1~git123
+
+evrcmp 1.0^ 1.0^
+evrcmp 1.0^ 1.0
+evrcmp 1.0 1.0^
+evrcmp 1.0^git1 1.0^git1
+evrcmp 1.0^git1 1.0
+evrcmp 1.0 1.0^git1
+evrcmp 1.0^git1 1.0^git2
+evrcmp 1.0^git2 1.0^git1
+evrcmp 1.0^git1 1.01
+evrcmp 1.01 1.0^git1
+evrcmp 1.0^20160101 1.0^20160101
+evrcmp 1.0^20160101 1.0.1
+evrcmp 1.0.1 1.0^20160101
+evrcmp 1.0^20160101^git1 1.0^20160101^git1
+evrcmp 1.0^20160102 1.0^20160101^git1
+evrcmp 1.0^20160101^git1 1.0^20160102
+
+evrcmp 1.0~rc1^git1 1.0~rc1^git1
+evrcmp 1.0~rc1^git1 1.0~rc1
+evrcmp 1.0~rc1 1.0~rc1^git1
+evrcmp 1.0^git1~pre 1.0^git1~pre
+evrcmp 1.0^git1 1.0^git1~pre
+evrcmp 1.0^git1~pre 1.0^git1
+evrcmp 1.0^1 1.0~1
+evrcmp 1.0~1 1.0^1
+
+result jobs <inline>
+#>job noop provides 1.0~rc1 = 1.0~rc1
+#>job noop provides 1.0~rc1 < 1.0
+#>job noop provides 1.0 > 1.0~rc1
+#>job noop provides 1.0~rc1 < 1.0~rc2
+#>job noop provides 1.0~rc2 > 1.0~rc1
+#>job noop provides 1.0~rc1~git123 = 1.0~rc1~git123
+#>job noop provides 1.0~rc1~git123 < 1.0~rc1
+#>job noop provides 1.0~rc1 > 1.0~rc1~git123
+#>job noop provides 1.0^ = 1.0^
+#>job noop provides 1.0^ > 1.0
+#>job noop provides 1.0 < 1.0^
+#>job noop provides 1.0^git1 = 1.0^git1
+#>job noop provides 1.0^git1 > 1.0
+#>job noop provides 1.0 < 1.0^git1
+#>job noop provides 1.0^git1 < 1.0^git2
+#>job noop provides 1.0^git2 > 1.0^git1
+#>job noop provides 1.0^git1 < 1.01
+#>job noop provides 1.01 > 1.0^git1
+#>job noop provides 1.0^20160101 = 1.0^20160101
+#>job noop provides 1.0^20160101 < 1.0.1
+#>job noop provides 1.0.1 > 1.0^20160101
+#>job noop provides 1.0^20160101^git1 = 1.0^20160101^git1
+#>job noop provides 1.0^20160102 > 1.0^20160101^git1
+#>job noop provides 1.0^20160101^git1 < 1.0^20160102
+#>job noop provides 1.0~rc1^git1 = 1.0~rc1^git1
+#>job noop provides 1.0~rc1^git1 > 1.0~rc1
+#>job noop provides 1.0~rc1 < 1.0~rc1^git1
+#>job noop provides 1.0^git1~pre = 1.0^git1~pre
+#>job noop provides 1.0^git1 > 1.0^git1~pre
+#>job noop provides 1.0^git1~pre < 1.0^git1
+#>job noop provides 1.0^1 > 1.0~1
+#>job noop provides 1.0~1 < 1.0^1
diff --git a/libsolv-0.7.2/test/testcases/evrcmp/conflicts.repo b/libsolv-0.7.2/test/testcases/evrcmp/conflicts.repo
new file mode 100644 (file)
index 0000000..c979cb0
--- /dev/null
@@ -0,0 +1,26 @@
+=Ver: 2.0
+#
+=Pkg: CEQ2 1 1 noarch
+=Con: B = 2
+=Pkg: CEQ22 1 1 noarch
+=Con: B = 2-2
+#
+=Pkg: CLT2 1 1 noarch
+=Con: B < 2
+=Pkg: CLT22 1 1 noarch
+=Con: B < 2-2
+#
+=Pkg: CGT2 1 1 noarch
+=Con: B > 2
+=Pkg: CGT22 1 1 noarch
+=Con: B > 2-2
+#
+=Pkg: CLE2 1 1 noarch
+=Con: B <= 2
+=Pkg: CLE22 1 1 noarch
+=Con: B <= 2-2
+#
+=Pkg: CGE2 1 1 noarch
+=Con: B >= 2
+=Pkg: CGE22 1 1 noarch
+=Con: B >= 2-2
diff --git a/libsolv-0.7.2/test/testcases/evrcmp/system.repo b/libsolv-0.7.2/test/testcases/evrcmp/system.repo
new file mode 100644 (file)
index 0000000..233b6b9
--- /dev/null
@@ -0,0 +1,127 @@
+=Ver: 2.0
+#
+=Pkg: AEQ1 1 1 noarch
+=Prv: B = 1
+=Pkg: AEQ11 1 1 noarch
+=Prv: B = 1-1
+=Pkg: AEQ12 1 1 noarch
+=Prv: B = 1-2
+=Pkg: AEQ13 1 1 noarch
+=Prv: B = 1-3
+=Pkg: AEQ2 1 1 noarch
+=Prv: B = 2
+=Pkg: AEQ21 1 1 noarch
+=Prv: B = 2-1
+=Pkg: AEQ22 1 1 noarch
+=Prv: B = 2-2
+=Pkg: AEQ23 1 1 noarch
+=Prv: B = 2-3
+=Pkg: AEQ3 1 1 noarch
+=Prv: B = 3
+=Pkg: AEQ31 1 1 noarch
+=Prv: B = 3-1
+=Pkg: AEQ32 1 1 noarch
+=Prv: B = 3-2
+=Pkg: AEQ33 1 1 noarch
+=Prv: B = 3-3
+#
+=Pkg: ALT1 1 1 noarch
+=Prv: B < 1
+=Pkg: ALT11 1 1 noarch
+=Prv: B < 1-1
+=Pkg: ALT12 1 1 noarch
+=Prv: B < 1-2
+=Pkg: ALT13 1 1 noarch
+=Prv: B < 1-3
+=Pkg: ALT2 1 1 noarch
+=Prv: B < 2
+=Pkg: ALT21 1 1 noarch
+=Prv: B < 2-1
+=Pkg: ALT22 1 1 noarch
+=Prv: B < 2-2
+=Pkg: ALT23 1 1 noarch
+=Prv: B < 2-3
+=Pkg: ALT3 1 1 noarch
+=Prv: B < 3
+=Pkg: ALT31 1 1 noarch
+=Prv: B < 3-1
+=Pkg: ALT32 1 1 noarch
+=Prv: B < 3-2
+=Pkg: ALT33 1 1 noarch
+=Prv: B < 3-3
+#
+=Pkg: AGT1 1 1 noarch
+=Prv: B > 1
+=Pkg: AGT11 1 1 noarch
+=Prv: B > 1-1
+=Pkg: AGT12 1 1 noarch
+=Prv: B > 1-2
+=Pkg: AGT13 1 1 noarch
+=Prv: B > 1-3
+=Pkg: AGT2 1 1 noarch
+=Prv: B > 2
+=Pkg: AGT21 1 1 noarch
+=Prv: B > 2-1
+=Pkg: AGT22 1 1 noarch
+=Prv: B > 2-2
+=Pkg: AGT23 1 1 noarch
+=Prv: B > 2-3
+=Pkg: AGT3 1 1 noarch
+=Prv: B > 3
+=Pkg: AGT31 1 1 noarch
+=Prv: B > 3-1
+=Pkg: AGT32 1 1 noarch
+=Prv: B > 3-2
+=Pkg: AGT33 1 1 noarch
+=Prv: B > 3-3
+#
+=Pkg: ALE1 1 1 noarch
+=Prv: B <= 1
+=Pkg: ALE11 1 1 noarch
+=Prv: B <= 1-1
+=Pkg: ALE12 1 1 noarch
+=Prv: B <= 1-2
+=Pkg: ALE13 1 1 noarch
+=Prv: B <= 1-3
+=Pkg: ALE2 1 1 noarch
+=Prv: B <= 2
+=Pkg: ALE21 1 1 noarch
+=Prv: B <= 2-1
+=Pkg: ALE22 1 1 noarch
+=Prv: B <= 2-2
+=Pkg: ALE23 1 1 noarch
+=Prv: B <= 2-3
+=Pkg: ALE3 1 1 noarch
+=Prv: B <= 3
+=Pkg: ALE31 1 1 noarch
+=Prv: B <= 3-1
+=Pkg: ALE32 1 1 noarch
+=Prv: B <= 3-2
+=Pkg: ALE33 1 1 noarch
+=Prv: B <= 3-3
+#
+=Pkg: AGE1 1 1 noarch
+=Prv: B >= 1
+=Pkg: AGE11 1 1 noarch
+=Prv: B >= 1-1
+=Pkg: AGE12 1 1 noarch
+=Prv: B >= 1-2
+=Pkg: AGE13 1 1 noarch
+=Prv: B >= 1-3
+=Pkg: AGE2 1 1 noarch
+=Prv: B >= 2
+=Pkg: AGE21 1 1 noarch
+=Prv: B >= 2-1
+=Pkg: AGE22 1 1 noarch
+=Prv: B >= 2-2
+=Pkg: AGE23 1 1 noarch
+=Prv: B >= 2-3
+=Pkg: AGE3 1 1 noarch
+=Prv: B >= 3
+=Pkg: AGE31 1 1 noarch
+=Prv: B >= 3-1
+=Pkg: AGE32 1 1 noarch
+=Prv: B >= 3-2
+=Pkg: AGE33 1 1 noarch
+=Prv: B >= 3-3
+#
diff --git a/libsolv-0.7.2/test/testcases/evrcmp/testevr.t b/libsolv-0.7.2/test/testcases/evrcmp/testevr.t
new file mode 100644 (file)
index 0000000..842c63c
--- /dev/null
@@ -0,0 +1,450 @@
+#
+# these tests check all dependency match combinations,
+# both with release present and missing
+#
+repo system 0 testtags system.repo
+repo c 0 testtags conflicts.repo
+system i686 rpm system
+solverflags allowuninstall
+job install name CEQ2
+result transaction,problems <inline>
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ21-1-1.noarch@system
+#>erase AEQ22-1-1.noarch@system
+#>erase AEQ23-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGE23-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase AGT22-1-1.noarch@system
+#>erase AGT23-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE21-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT21-1-1.noarch@system
+#>erase ALT22-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CEQ2-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CEQ22
+result transaction,problems <inline>
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ22-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CEQ22-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CLT2
+result transaction,problems <inline>
+#>erase AEQ1-1-1.noarch@system
+#>erase AEQ11-1-1.noarch@system
+#>erase AEQ12-1-1.noarch@system
+#>erase AEQ13-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase ALE1-1-1.noarch@system
+#>erase ALE11-1-1.noarch@system
+#>erase ALE12-1-1.noarch@system
+#>erase ALE13-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE21-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT1-1-1.noarch@system
+#>erase ALT11-1-1.noarch@system
+#>erase ALT12-1-1.noarch@system
+#>erase ALT13-1-1.noarch@system
+#>erase ALT2-1-1.noarch@system
+#>erase ALT21-1-1.noarch@system
+#>erase ALT22-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CLT2-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CLT22
+result transaction,problems <inline>
+#>erase AEQ1-1-1.noarch@system
+#>erase AEQ11-1-1.noarch@system
+#>erase AEQ12-1-1.noarch@system
+#>erase AEQ13-1-1.noarch@system
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ21-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase ALE1-1-1.noarch@system
+#>erase ALE11-1-1.noarch@system
+#>erase ALE12-1-1.noarch@system
+#>erase ALE13-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE21-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT1-1-1.noarch@system
+#>erase ALT11-1-1.noarch@system
+#>erase ALT12-1-1.noarch@system
+#>erase ALT13-1-1.noarch@system
+#>erase ALT2-1-1.noarch@system
+#>erase ALT21-1-1.noarch@system
+#>erase ALT22-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CLT22-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CGT2
+result transaction,problems <inline>
+#>erase AEQ3-1-1.noarch@system
+#>erase AEQ31-1-1.noarch@system
+#>erase AEQ32-1-1.noarch@system
+#>erase AEQ33-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGE23-1-1.noarch@system
+#>erase AGE3-1-1.noarch@system
+#>erase AGE31-1-1.noarch@system
+#>erase AGE32-1-1.noarch@system
+#>erase AGE33-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT2-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase AGT22-1-1.noarch@system
+#>erase AGT23-1-1.noarch@system
+#>erase AGT3-1-1.noarch@system
+#>erase AGT31-1-1.noarch@system
+#>erase AGT32-1-1.noarch@system
+#>erase AGT33-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CGT2-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CGT22
+result transaction,problems <inline>
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ23-1-1.noarch@system
+#>erase AEQ3-1-1.noarch@system
+#>erase AEQ31-1-1.noarch@system
+#>erase AEQ32-1-1.noarch@system
+#>erase AEQ33-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGE23-1-1.noarch@system
+#>erase AGE3-1-1.noarch@system
+#>erase AGE31-1-1.noarch@system
+#>erase AGE32-1-1.noarch@system
+#>erase AGE33-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT2-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase AGT22-1-1.noarch@system
+#>erase AGT23-1-1.noarch@system
+#>erase AGT3-1-1.noarch@system
+#>erase AGT31-1-1.noarch@system
+#>erase AGT32-1-1.noarch@system
+#>erase AGT33-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CGT22-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CLE2
+result transaction,problems <inline>
+#>erase AEQ1-1-1.noarch@system
+#>erase AEQ11-1-1.noarch@system
+#>erase AEQ12-1-1.noarch@system
+#>erase AEQ13-1-1.noarch@system
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ21-1-1.noarch@system
+#>erase AEQ22-1-1.noarch@system
+#>erase AEQ23-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGE23-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase AGT22-1-1.noarch@system
+#>erase AGT23-1-1.noarch@system
+#>erase ALE1-1-1.noarch@system
+#>erase ALE11-1-1.noarch@system
+#>erase ALE12-1-1.noarch@system
+#>erase ALE13-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE21-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT1-1-1.noarch@system
+#>erase ALT11-1-1.noarch@system
+#>erase ALT12-1-1.noarch@system
+#>erase ALT13-1-1.noarch@system
+#>erase ALT2-1-1.noarch@system
+#>erase ALT21-1-1.noarch@system
+#>erase ALT22-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CLE2-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CLE22
+result transaction,problems <inline>
+#>erase AEQ1-1-1.noarch@system
+#>erase AEQ11-1-1.noarch@system
+#>erase AEQ12-1-1.noarch@system
+#>erase AEQ13-1-1.noarch@system
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ21-1-1.noarch@system
+#>erase AEQ22-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase ALE1-1-1.noarch@system
+#>erase ALE11-1-1.noarch@system
+#>erase ALE12-1-1.noarch@system
+#>erase ALE13-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE21-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT1-1-1.noarch@system
+#>erase ALT11-1-1.noarch@system
+#>erase ALT12-1-1.noarch@system
+#>erase ALT13-1-1.noarch@system
+#>erase ALT2-1-1.noarch@system
+#>erase ALT21-1-1.noarch@system
+#>erase ALT22-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CLE22-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CGE2
+result transaction,problems <inline>
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ21-1-1.noarch@system
+#>erase AEQ22-1-1.noarch@system
+#>erase AEQ23-1-1.noarch@system
+#>erase AEQ3-1-1.noarch@system
+#>erase AEQ31-1-1.noarch@system
+#>erase AEQ32-1-1.noarch@system
+#>erase AEQ33-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGE23-1-1.noarch@system
+#>erase AGE3-1-1.noarch@system
+#>erase AGE31-1-1.noarch@system
+#>erase AGE32-1-1.noarch@system
+#>erase AGE33-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT2-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase AGT22-1-1.noarch@system
+#>erase AGT23-1-1.noarch@system
+#>erase AGT3-1-1.noarch@system
+#>erase AGT31-1-1.noarch@system
+#>erase AGT32-1-1.noarch@system
+#>erase AGT33-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE21-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT21-1-1.noarch@system
+#>erase ALT22-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CGE2-1-1.noarch@c
+nextjob
+solverflags allowuninstall
+job install name CGE22
+result transaction,problems <inline>
+#>erase AEQ2-1-1.noarch@system
+#>erase AEQ22-1-1.noarch@system
+#>erase AEQ23-1-1.noarch@system
+#>erase AEQ3-1-1.noarch@system
+#>erase AEQ31-1-1.noarch@system
+#>erase AEQ32-1-1.noarch@system
+#>erase AEQ33-1-1.noarch@system
+#>erase AGE1-1-1.noarch@system
+#>erase AGE11-1-1.noarch@system
+#>erase AGE12-1-1.noarch@system
+#>erase AGE13-1-1.noarch@system
+#>erase AGE2-1-1.noarch@system
+#>erase AGE21-1-1.noarch@system
+#>erase AGE22-1-1.noarch@system
+#>erase AGE23-1-1.noarch@system
+#>erase AGE3-1-1.noarch@system
+#>erase AGE31-1-1.noarch@system
+#>erase AGE32-1-1.noarch@system
+#>erase AGE33-1-1.noarch@system
+#>erase AGT1-1-1.noarch@system
+#>erase AGT11-1-1.noarch@system
+#>erase AGT12-1-1.noarch@system
+#>erase AGT13-1-1.noarch@system
+#>erase AGT2-1-1.noarch@system
+#>erase AGT21-1-1.noarch@system
+#>erase AGT22-1-1.noarch@system
+#>erase AGT23-1-1.noarch@system
+#>erase AGT3-1-1.noarch@system
+#>erase AGT31-1-1.noarch@system
+#>erase AGT32-1-1.noarch@system
+#>erase AGT33-1-1.noarch@system
+#>erase ALE2-1-1.noarch@system
+#>erase ALE22-1-1.noarch@system
+#>erase ALE23-1-1.noarch@system
+#>erase ALE3-1-1.noarch@system
+#>erase ALE31-1-1.noarch@system
+#>erase ALE32-1-1.noarch@system
+#>erase ALE33-1-1.noarch@system
+#>erase ALT23-1-1.noarch@system
+#>erase ALT3-1-1.noarch@system
+#>erase ALT31-1-1.noarch@system
+#>erase ALT32-1-1.noarch@system
+#>erase ALT33-1-1.noarch@system
+#>install CGE22-1-1.noarch@c
diff --git a/libsolv-0.7.2/test/testcases/favor/recommends.t b/libsolv-0.7.2/test/testcases/favor/recommends.t
new file mode 100644 (file)
index 0000000..c802d4a
--- /dev/null
@@ -0,0 +1,50 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Rec: X
+#>=Pkg: B 1 1 noarch
+#>=Prv: X
+#>=Pkg: C 1 1 noarch
+#>=Prv: X
+system unset * system
+
+# first favor B
+job install name A
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# then favor C
+nextjob
+job install name A
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# check disfavor 
+nextjob
+job install name A
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# check disfavor both, this is different from
+# the requires case
+
+nextjob
+job install name A
+job disfavor name B
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/favor/requires.t b/libsolv-0.7.2/test/testcases/favor/requires.t
new file mode 100644 (file)
index 0000000..e96a905
--- /dev/null
@@ -0,0 +1,112 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Req: X
+#>=Pkg: B 1 1 noarch
+#>=Prv: X
+#>=Pkg: C 1 1 noarch
+#>=Prv: X
+system unset * system
+
+# first favor B
+job install name A
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# then favor C
+nextjob
+job install name A
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+
+# if both are favored, the last one wins
+nextjob
+job install name A
+job favor name C
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job favor name B
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# now test disfavor
+
+# first disfavor B
+nextjob
+job install name A
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# then disfavor C
+nextjob
+job install name A
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+# then both
+nextjob
+job install name A
+job disfavor name B
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# then test combination
+nextjob
+job install name A
+job favor name B
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name B
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job favor name C
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
diff --git a/libsolv-0.7.2/test/testcases/favor/supplements.t b/libsolv-0.7.2/test/testcases/favor/supplements.t
new file mode 100644 (file)
index 0000000..7f415b0
--- /dev/null
@@ -0,0 +1,71 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Sup: A
+#>=Pkg: C 1 1 noarch
+#>=Sup: A
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Sup: A2
+#>=Pkg: C2 1 1 noarch
+#>=Sup: A2
+#>=Con: B2
+system unset * system
+
+# first favor B
+job install name A
+job favor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# then favor C
+nextjob
+job install name A
+job favor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+# same with A2 where B2 and C2 conflict
+
+nextjob
+job install name A2
+job favor name B2
+result transaction,problems <inline>
+#>install A2-1-1.noarch@test
+#>install B2-1-1.noarch@test
+
+nextjob
+job install name A2
+job favor name C2
+result transaction,problems <inline>
+#>install A2-1-1.noarch@test
+#>install C2-1-1.noarch@test
+
+
+# check disfavor 
+nextjob
+job install name A
+job disfavor name B
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install B-1-1.noarch@test
+
+nextjob
+job install name A
+job disfavor name B
+job disfavor name C
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/focus/best.t b/libsolv-0.7.2/test/testcases/focus/best.t
new file mode 100644 (file)
index 0000000..a7a46b9
--- /dev/null
@@ -0,0 +1,23 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A2 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Req: A = 1
+#>=Pkg: B 2 1 noarch
+#>=Req: A = 2
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: A2 2 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Req: A2 = 1
+#>=Pkg: B2 2 1 noarch
+#>=Req: A2 = 2
+#>=Pkg: C 1 1 noarch
+#>=Req: B2
+system i686 rpm system
+solverflags focusbest
+
+job install name B
+job install name C
diff --git a/libsolv-0.7.2/test/testcases/focus/installed.t b/libsolv-0.7.2/test/testcases/focus/installed.t
new file mode 100644 (file)
index 0000000..4f49d35
--- /dev/null
@@ -0,0 +1,23 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A2 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Req: A = 1
+#>=Pkg: B 2 1 noarch
+#>=Req: A = 2
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: A2 2 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Req: A2 = 1
+#>=Pkg: B2 2 1 noarch
+#>=Req: A2 = 2
+#>=Pkg: C 1 1 noarch
+#>=Req: B2
+system i686 rpm system
+solverflags focusinstalled
+
+job install name B
+job install name C
diff --git a/libsolv-0.7.2/test/testcases/focus/normal.t b/libsolv-0.7.2/test/testcases/focus/normal.t
new file mode 100644 (file)
index 0000000..6e562a3
--- /dev/null
@@ -0,0 +1,22 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A2 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 1 noarch
+#>=Req: A = 1
+#>=Pkg: B 2 1 noarch
+#>=Req: A = 2
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: A2 2 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Req: A2 = 1
+#>=Pkg: B2 2 1 noarch
+#>=Req: A2 = 2
+#>=Pkg: C 1 1 noarch
+#>=Req: B2
+system i686 rpm system
+
+job install name B
+job install name C
diff --git a/libsolv-0.7.2/test/testcases/forcebest/forcebest_dup.t b/libsolv-0.7.2/test/testcases/forcebest/forcebest_dup.t
new file mode 100644 (file)
index 0000000..7f1fbba
--- /dev/null
@@ -0,0 +1,31 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Vnd: foo
+#>=Pkg: D 1 1 noarch
+#>=Vnd: foo
+#>=Con: A = 3-1
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Vnd: foo
+#>=Pkg: A 3 1 noarch
+#>=Vnd: bar
+system i686 rpm system
+
+job distupgrade name A [forcebest]
+result transaction,problems <inline>
+#>erase D-1-1.noarch@system
+#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
+#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
+#>problem 1210fdfb solution d85f7c4e allow A-2-1.noarch@available
+#>upgrade A-1-1.noarch@system A-3-1.noarch@available
+
+# test if bestobeypolicy is a noop for dup jobs
+nextjob
+solverflags bestobeypolicy
+job distupgrade name A [forcebest]
+result transaction,problems <inline>
+#>erase D-1-1.noarch@system
+#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
+#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
+#>problem 1210fdfb solution d85f7c4e allow A-2-1.noarch@available
+#>upgrade A-1-1.noarch@system A-3-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/forcebest/forcebest_in.t b/libsolv-0.7.2/test/testcases/forcebest/forcebest_in.t
new file mode 100644 (file)
index 0000000..93165c8
--- /dev/null
@@ -0,0 +1,25 @@
+repo system 0 testtags <inline>
+#>=Pkg: D 1 1 noarch
+#>=Vnd: foo
+#>=Con: A = 3-1
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Vnd: foo
+#>=Pkg: A 3 1 noarch
+#>=Vnd: bar
+system i686 rpm system
+
+job install name A [forcebest]
+result transaction,problems <inline>
+#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
+#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
+#>problem 1210fdfb solution ee74e60f deljob install name A [forcebest]
+
+# currently bestobeypolicy is a noop for install jobs
+nextjob
+solverflags bestobeypolicy
+job install name A [forcebest]
+result transaction,problems <inline>
+#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
+#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
+#>problem 1210fdfb solution ee74e60f deljob install name A [forcebest]
diff --git a/libsolv-0.7.2/test/testcases/forcebest/forcebest_up.t b/libsolv-0.7.2/test/testcases/forcebest/forcebest_up.t
new file mode 100644 (file)
index 0000000..6e97bf8
--- /dev/null
@@ -0,0 +1,26 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Vnd: foo
+#>=Pkg: D 1 1 noarch
+#>=Vnd: foo
+#>=Con: A = 3-1
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Vnd: foo
+#>=Pkg: A 3 1 noarch
+#>=Vnd: bar
+system i686 rpm system
+
+job update name A [forcebest]
+result transaction,problems <inline>
+#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
+#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
+#>problem 1210fdfb solution 0d75a914 replace A-1-1.noarch@system A-3-1.noarch@available
+#>problem 1210fdfb solution d85f7c4e allow A-2-1.noarch@available
+#>upgrade A-1-1.noarch@system A-2-1.noarch@available
+
+nextjob
+solverflags bestobeypolicy
+job update name A [forcebest]
+result transaction,problems <inline>
+#>upgrade A-1-1.noarch@system A-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/lockstep/lockstep_install.t b/libsolv-0.7.2/test/testcases/lockstep/lockstep_install.t
new file mode 100644 (file)
index 0000000..f626da0
--- /dev/null
@@ -0,0 +1,9 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Pkg: A 1 1 i586
+#>=Prv: A(x32)
+#>=Pkg: A 1 1 x86_64
+#>=Prv: A(x64)
+system x86_64 rpm system
+poolflags implicitobsoleteusescolors
+job install provides A(x32)
diff --git a/libsolv-0.7.2/test/testcases/lockstep/lockstep_update.t b/libsolv-0.7.2/test/testcases/lockstep/lockstep_update.t
new file mode 100644 (file)
index 0000000..128bcc3
--- /dev/null
@@ -0,0 +1,11 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 i586
+#>=Pkg: A 1 1 x86_64
+repo test 0 testtags <inline>
+#>=Pkg: A 2 1 i586
+#>=Pkg: A 2 1 x86_64
+#>=Pkg: A 3 1 i586
+#>=Pkg: A 4 1 x86_64
+system x86_64 rpm system
+poolflags implicitobsoleteusescolors
+job update all packages
diff --git a/libsolv-0.7.2/test/testcases/multiversion/multiversion.t b/libsolv-0.7.2/test/testcases/multiversion/multiversion.t
new file mode 100644 (file)
index 0000000..decf22f
--- /dev/null
@@ -0,0 +1,30 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: B 1 1 noarch
+repo test 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Obs: B
+system i686 rpm system
+
+solverflags keepexplicitobsoletes
+job multiversion name A
+job install name A = 2
+result transaction,problems <inline>
+#>erase B-1-1.noarch@system
+#>install A-2-1.noarch@test
+
+nextjob
+solverflags keepexplicitobsoletes
+poolflags noobsoletesmultiversion
+job multiversion name A
+job install name A = 2
+result transaction,problems <inline>
+#>erase B-1-1.noarch@system
+#>install A-2-1.noarch@test
+
+nextjob
+poolflags !noobsoletesmultiversion
+job multiversion name A
+job install name A = 2
+result transaction,problems <inline>
+#>install A-2-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/multiversion/update.t b/libsolv-0.7.2/test/testcases/multiversion/update.t
new file mode 100644 (file)
index 0000000..c3a2d9a
--- /dev/null
@@ -0,0 +1,65 @@
+repo system 0 testtags <inline>
+#>=Pkg: k 1 0 x86_64
+#>=Pkg: k-m 1 0 x86_64
+#>=Req: k = 1-0
+#>=Pkg: k-freak-1-0 1 0 x86_64
+#>=Req: k = 1-0
+#>=Pkg: k 1 1 x86_64
+#>=Pkg: k-m 1 1 x86_64
+#>=Req: k = 1-1
+#>=Pkg: k 2 0 x86_64
+#>=Pkg: k-m 2 0 x86_64
+#>=Req: k = 2-0
+#>=Pkg: k 3 0 x86_64
+#>=Pkg: k-m 3 0 x86_64
+#>=Req: k = 3-0
+repo available 0 testtags <inline>
+#>=Pkg: k 3 1 x86_64
+#>=Pkg: k-m 3 1 x86_64
+#>=Req: k = 3-1
+#>=Pkg: k 3 6 x86_64
+#>=Pkg: k-m 3 6 x86_64
+#>=Req: k = 3-6
+#>=Pkg: c 1 1 noarch
+#>=Con: k = 3-6
+system x86_64 rpm system
+poolflags implicitobsoleteusescolors
+
+job multiversion provides k
+job multiversion provides k-m
+job update all packages
+result transaction,problems <inline>
+#>install k-3-6.x86_64@available
+#>install k-m-3-6.x86_64@available
+
+nextjob
+
+job multiversion provides k
+job multiversion provides k-m
+job install name c
+job update all packages
+result transaction,problems <inline>
+#>install k-3-1.x86_64@available
+#>install k-m-3-1.x86_64@available
+#>install c-1-1.noarch@available
+
+
+nextjob
+
+job multiversion provides k
+job multiversion provides k-m
+job install name c
+job update all packages [forcebest]
+result transaction,problems <inline>
+#>install k-3-6.x86_64@available
+#>install k-m-3-6.x86_64@available
+#>problem ca7106eb info package c-1-1.noarch conflicts with k = 3-6 provided by k-3-6.x86_64
+#>problem ca7106eb solution 4d4bc71f allow k-1-0.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-1-1.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-2-0.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-3-0.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-m-1-0.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-m-1-1.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-m-2-0.x86_64@system
+#>problem ca7106eb solution 4d4bc71f allow k-m-3-0.x86_64@system
+#>problem ca7106eb solution 86764155 deljob install name c
diff --git a/libsolv-0.7.2/test/testcases/namespace/namespaceprovides.t b/libsolv-0.7.2/test/testcases/namespace/namespaceprovides.t
new file mode 100644 (file)
index 0000000..609b58a
--- /dev/null
@@ -0,0 +1,85 @@
+repo system 0 testtags <inline>
+#>=Ver: 2
+#>=Pkg: B 1 1 noarch
+#>=Prv: locale(en)
+#>=Pkg: C 1 1 noarch
+repo test 0 testtags <inline>
+#>=Ver: 2
+#>=Pkg: A 1 1 noarch
+#>=Prv: locale(de)
+#>=Pkg: C-de 1 1 noarch
+#>=Prv: locale(C:de)
+#>=Pkg: C-en 1 1 noarch
+#>=Prv: locale(C:en)
+#>=Pkg: D 1 1 noarch
+#>=Sup: C
+#>=Pkg: E 1 1 noarch
+#>=Prv: locale(F:de)
+#>=Pkg: F 1 1 noarch
+#>=Pkg: G 1 1 noarch
+#>=Sup: F
+system i686 rpm system
+
+# first test an empty job
+namespace namespace:language(de) @SYSTEM
+result transaction,problems <inline>
+
+# then test addalreadyrecommended
+nextjob
+namespace namespace:language(de) @SYSTEM
+solverflags addalreadyrecommended
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-de-1-1.noarch@test
+#>install D-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+job install provides namespace:language(de)
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-de-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+job erase provides namespace:language(en) [cleandeps]
+result transaction,problems <inline>
+#>erase B-1-1.noarch@system
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+job install provides namespace:language(<NULL>)
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-de-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+job erase provides namespace:language(<NULL>) [cleandeps]
+result transaction,problems <inline>
+#>erase B-1-1.noarch@system
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+job install provides namespace:language(<NULL>)
+job erase provides namespace:language(<NULL>) [cleandeps]
+result transaction,problems <inline>
+#>erase B-1-1.noarch@system
+#>install A-1-1.noarch@test
+#>install C-de-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+solverflags addalreadyrecommended onlynamespacerecommended
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-de-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+solverflags onlynamespacerecommended
+job install name F
+result transaction,problems <inline>
+#>install E-1-1.noarch@test
+#>install F-1-1.noarch@test
+
diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_conflicts.t
new file mode 100644 (file)
index 0000000..92afd75
--- /dev/null
@@ -0,0 +1,16 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Rec: B
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Con: A
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>recommended B-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_multirepo.t
new file mode 100644 (file)
index 0000000..0addaf4
--- /dev/null
@@ -0,0 +1,19 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Rec: B
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+repo other 0 testtags <inline>
+#>=Pkg: B 4 1 noarch
+#>=Pkg: B 6 1 noarch
+#>=Pkg: B 5 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>recommended B-6-1.noarch@other
diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_oldversion.t
new file mode 100644 (file)
index 0000000..27c62f1
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Rec: B < 3
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>recommended B-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_targeted.t
new file mode 100644 (file)
index 0000000..2b8a842
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Rec: B = 2-1
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>recommended B-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/recommended_version.t b/libsolv-0.7.2/test/testcases/recommendations/recommended_version.t
new file mode 100644 (file)
index 0000000..b2e3637
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Rec: B
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>recommended B-3-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_conflicts.t
new file mode 100644 (file)
index 0000000..8de6f3d
--- /dev/null
@@ -0,0 +1,16 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Sug: B
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Con: A
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>suggested B-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_multirepo.t
new file mode 100644 (file)
index 0000000..c0a6d8f
--- /dev/null
@@ -0,0 +1,19 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Sug: B
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+repo other 0 testtags <inline>
+#>=Pkg: B 4 1 noarch
+#>=Pkg: B 6 1 noarch
+#>=Pkg: B 5 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>suggested B-6-1.noarch@other
diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_oldversion.t
new file mode 100644 (file)
index 0000000..b259b65
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Sug: B < 3
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>suggested B-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_targeted.t
new file mode 100644 (file)
index 0000000..01da811
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Sug: B = 2-1
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>suggested B-2-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/recommendations/suggested_version.t b/libsolv-0.7.2/test/testcases/recommendations/suggested_version.t
new file mode 100644 (file)
index 0000000..1af6a77
--- /dev/null
@@ -0,0 +1,15 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Sug: B
+#>=Pkg: B 1 1 noarch
+#>=Pkg: B 3 1 noarch
+#>=Pkg: B 2 1 noarch
+system i686 rpm system
+
+solverflags ignorerecommended
+job install name A
+
+result transaction,recommended,problems <inline>
+#>install A-1-1.noarch@available
+#>suggested B-3-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/sat/assert.t b/libsolv-0.7.2/test/testcases/sat/assert.t
new file mode 100644 (file)
index 0000000..b3a2482
--- /dev/null
@@ -0,0 +1,9 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 x86_64
+#>=Prv: AA
+#>=Pkg: B 1 1 x86_64
+#>=Prv: AA
+system x86_64 * system
+job erase provides AA [weak]
+job install pkg B-1-1.x86_64@system
+result transaction,problems <inline>
diff --git a/libsolv-0.7.2/test/testcases/sat/mm-test.t b/libsolv-0.7.2/test/testcases/sat/mm-test.t
new file mode 100644 (file)
index 0000000..6665cad
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# testcase to check enabling/disabling of learnt rules
+#
+repo system 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1.0 1 noarch
+#>=Req: D
+#>=Prv: A = 1.0-1
+#>=Con: C
+#>=Pkg: C 1.0 1 noarch
+#>=Prv: foo
+#>=Prv: C = 1.0-1
+#>=Con: D
+#>=Pkg: D 1.0 1 noarch
+#>=Prv: D = 1.0-1
+#>=Pkg: A2 1.0 1 noarch
+#>=Req: D2
+#>=Prv: A2 = 1.0-1
+#>=Con: C2
+#>=Pkg: C2 1.0 1 noarch
+#>=Prv: foo
+#>=Prv: C2 = 1.0-1
+#>=Con: D2
+#>=Pkg: D2 1.0 1 noarch
+#>=Prv: D2 = 1.0-1
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: C 2.0 1 noarch
+#>=Prv: C = 2.0-1
+#>=Pkg: A 2.0 1 noarch
+#>=Prv: A = 2.0-1
+#>=Pkg: D 2.0 1 noarch
+#>=Prv: D = 2.0-1
+#>=Pkg: C2 2.0 1 noarch
+#>=Prv: C2 = 2.0-1
+#>=Pkg: A2 2.0 1 noarch
+#>=Prv: A2 = 2.0-1
+#>=Pkg: D2 2.0 1 noarch
+#>=Prv: D2 = 2.0-1
+#>=Pkg: E 2.0 1 noarch
+#>=Req: foo
+#>=Prv: E = 2.0-1
+system unset * system
+job install provides E
+job verify all packages
+result transaction,problems <inline>
+#>erase D-1.0-1.noarch@system
+#>erase D2-1.0-1.noarch@system
+#>problem a3755a16 info package E-2.0-1.noarch requires foo, but none of the providers can be installed
+#>problem a3755a16 solution 6d40bce1 deljob install provides E
+#>problem a3755a16 solution c06ed43e erase D-1.0-1.noarch@system
+#>problem a3755a16 solution c8a04f77 erase D2-1.0-1.noarch@system
+#>upgrade A-1.0-1.noarch@system A-2.0-1.noarch@test
+#>upgrade A2-1.0-1.noarch@system A2-2.0-1.noarch@test
diff --git a/libsolv-0.7.2/test/testcases/sat/reuse.t b/libsolv-0.7.2/test/testcases/sat/reuse.t
new file mode 100644 (file)
index 0000000..7abb266
--- /dev/null
@@ -0,0 +1,20 @@
+repo system 0 testtags <inline>
+#>=Pkg: X 1 1 x86_64
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 x86_64
+#>=Req: X
+#>=Pkg: B 1 1 x86_64
+job install name A
+result transaction,problems,rules <inline>
+#>install A-1-1.x86_64@available
+#>install X-1-1.x86_64@system
+#>rule job 300db6ce502dde94261e267a8c535441  A-1-1.x86_64@available
+#>rule pkg 11c27e407a56aad27bd6b3eadc17374b  X-1-1.x86_64@system
+#>rule pkg 11c27e407a56aad27bd6b3eadc17374b -A-1-1.x86_64@available
+nextjob reusesolver
+job install name B
+result transaction,problems,rules <inline>
+#>install B-1-1.x86_64@available
+#>rule job ad168c1819736b8aa6f507ab075b3494  B-1-1.x86_64@available
+#>rule pkg 11c27e407a56aad27bd6b3eadc17374b  X-1-1.x86_64@system
+#>rule pkg 11c27e407a56aad27bd6b3eadc17374b -A-1-1.x86_64@available
diff --git a/libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t b/libsolv-0.7.2/test/testcases/selection/selection_canon_rpm.t
new file mode 100644 (file)
index 0000000..018db31
--- /dev/null
@@ -0,0 +1,53 @@
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Pkg: A 1:1 1 i686
+#>=Pkg: A 2 2 badarch
+#>=Pkg: A 1:3 1 i686
+system i686 rpm
+
+disable pkg E-1-1.src@available
+disable pkg F-1-1.src@available
+
+job noop selection A-2 canon
+result jobs <inline>
+#>job noop name A = 2 [setev]
+
+nextjob
+job noop selection A-2-1 canon
+result jobs <inline>
+#>job noop name A = 2-1 [setevr]
+
+nextjob
+job noop selection A-3 canon
+result jobs <inline>
+#>job noop name A = 1:3 [setev]
+
+nextjob
+job noop selection A-3-1 canon
+result jobs <inline>
+#>job noop name A = 1:3-1 [setevr]
+
+nextjob
+job noop selection A-1 canon
+result jobs <inline>
+#>job noop oneof A-1-1.noarch@available A-1:1-1.i686@available
+
+nextjob
+job noop selection A-1-1 canon
+result jobs <inline>
+#>job noop oneof A-1-1.noarch@available A-1:1-1.i686@available
+
+
+nextjob
+job noop selection A-0:1-1 canon
+result jobs <inline>
+#>job noop name A = 0:1-1 [setevr]
+
+nextjob
+job noop selection A-1:1-1 canon
+result jobs <inline>
+#>job noop name A = 1:1-1 [setevr]
+
diff --git a/libsolv-0.7.2/test/testcases/selection/selection_filelist.t b/libsolv-0.7.2/test/testcases/selection/selection_filelist.t
new file mode 100644 (file)
index 0000000..2005643
--- /dev/null
@@ -0,0 +1,20 @@
+repo available 0 testtags <inline>
+#>=Pkg: bash 1 1 noarch
+#>=Fls: /usr/bin/bash
+#>=Fls: /usr/bin/bashbug
+#>=Pkg: bash 2 1 noarch
+#>=Fls: /usr/bin/bash
+#>=Fls: /usr/bin/bashbug
+#>=Pkg: coreutils 1 1 noarch
+#>=Fls: /usr/bin/basename
+system i686 rpm
+
+job noop selection /usr/bin/ba* filelist,glob
+result jobs <inline>
+#>job noop oneof bash-1-1.noarch@available bash-2-1.noarch@available
+#>job noop pkg coreutils-1-1.noarch@available [noautoset]
+
+nextjob
+job noop selection /usr/bin/ba* filelist,glob,flat
+result jobs <inline>
+#>job noop oneof bash-1-1.noarch@available bash-2-1.noarch@available coreutils-1-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t b/libsolv-0.7.2/test/testcases/selection/selection_matchdeps.t
new file mode 100644 (file)
index 0000000..cdf9ebc
--- /dev/null
@@ -0,0 +1,54 @@
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: AP 3 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Req: BBB > 5
+#>=Pkg: B 1 1 src
+#>=Pkg: A 2 2 badarch
+system i686 rpm
+
+job noop selection_matchdeps solvable:name a = 2 rel,flat,nocase
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available A-2-2.i686@available
+
+nextjob
+job noop selection_matchdeps solvable:name a = 2-* flat,glob,nocase,depstr
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available A-2-2.i686@available
+
+nextjob
+job noop selection_matchdepid solvable:name A = 2-1 flat
+result jobs <inline>
+#>job noop pkg A-2-1.noarch@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:name A = 2-2 flat,depstr
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:name A = 2-2 flat,depstr,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-2.i686@available A-2-2.badarch@available
+
+nextjob
+job noop selection_matchdeps solvable:requires bbb < 10 rel,flat,nocase
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdeps solvable:requires bbb >* depstr,glob,flat,nocase
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:requires BBB < 10 flat
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:requires BBB > 5 flat,depstr
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
diff --git a/libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t b/libsolv-0.7.2/test/testcases/selection/selection_matchsolvable.t
new file mode 100644 (file)
index 0000000..545abc4
--- /dev/null
@@ -0,0 +1,27 @@
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 noarch
+#>=Req: B > 1 + B < 3
+#>=Pkg: A2 1 1 noarch
+#>=Req: B > 1 & B < 3
+#>=Pkg: X 1 1 noarch
+#>=Prv: B = 4
+#>=Pkg: Y 1 1 noarch
+#>=Prv: B = 2
+#>=Pkg: A1 2 1 noarch
+system i686 rpm
+
+job noop selection_matchsolvable solvable:requires X-1-1.noarch@available flat
+result jobs <inline>
+#>job noop pkg A2-1-1.noarch@available [noautoset]
+
+nextjob
+job noop selection_matchsolvable solvable:requires Y-1-1.noarch@available flat
+result jobs <inline>
+#>job noop oneof A1-1-1.noarch@available A2-1-1.noarch@available
+
+nextjob
+job noop selection A1 name
+job noop selection_matchsolvable solvable:requires Y-1-1.noarch@available flat,filter
+result jobs <inline>
+#>job noop pkg A1-1-1.noarch@available [noautoset]
+
diff --git a/libsolv-0.7.2/test/testcases/selection/selection_name.t b/libsolv-0.7.2/test/testcases/selection/selection_name.t
new file mode 100644 (file)
index 0000000..b0a8520
--- /dev/null
@@ -0,0 +1,85 @@
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: AP 3 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Req: BBB > 5
+#>=Pkg: B 1 1 src
+#>=Pkg: A 2 2 badarch
+#>=Pkg: C 2 2 badarch
+#>=Pkg: D 2 2 noarch
+#>=Pkg: D 2 2 badarch
+#>=Pkg: E 1 1 src
+#>=Pkg: F 1 1 src
+#>=Pkg: F 1 2 src
+#>=Pkg: G 1 1 src
+#>=Pkg: G 1 2 src
+system i686 rpm
+
+disable pkg E-1-1.src@available
+disable pkg F-1-1.src@available
+
+job noop selection A name
+result jobs <inline>
+#>job noop name A
+
+nextjob
+job noop selection A.i686 name,dotarch
+result jobs <inline>
+#>job noop name A . i686 [setarch]
+
+nextjob
+job noop selection A.i686>1 name,dotarch,rel
+result jobs <inline>
+#>job noop name (A . i686) > 1 [setarch]
+
+nextjob
+job noop selection B* glob,name,withsource
+result jobs <inline>
+#>job noop pkg B-1-1.src@available [noautoset]
+
+nextjob
+job noop selection A=2-2 name,dotarch,rel,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-2.i686@available A-2-2.badarch@available [setevr]
+
+nextjob
+job noop selection C name,withbadarch
+result jobs <inline>
+#>job noop pkg C-2-2.badarch@available [noautoset]
+
+nextjob
+job noop selection D name,withbadarch
+result jobs <inline>
+#>job noop oneof D-2-2.noarch@available D-2-2.badarch@available
+
+nextjob
+job noop selection E name,sourceonly,withdisabled
+result jobs <inline>
+#>job noop pkg E-1-1.src@available [noautoset]
+
+nextjob
+job noop selection E name,withsource,withdisabled
+result jobs <inline>
+#>job noop pkg E-1-1.src@available [noautoset]
+
+nextjob
+job noop selection F name,sourceonly,withdisabled
+result jobs <inline>
+#>job noop oneof F-1-1.src@available F-1-2.src@available
+
+nextjob
+job noop selection F name,withsource,withdisabled
+result jobs <inline>
+#>job noop oneof F-1-1.src@available F-1-2.src@available
+
+nextjob
+job noop selection G name,sourceonly,withdisabled
+result jobs <inline>
+#>job noop name G . src
+
+nextjob
+job noop selection G name,withsource,withdisabled
+result jobs <inline>
+#>job noop oneof G-1-1.src@available G-1-2.src@available
+
diff --git a/libsolv-0.7.2/test/testcases/selection/selection_provides.t b/libsolv-0.7.2/test/testcases/selection/selection_provides.t
new file mode 100644 (file)
index 0000000..cb3a029
--- /dev/null
@@ -0,0 +1,49 @@
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: AP 3 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Req: BBB > 5
+#>=Pkg: B 1 1 src
+#>=Pkg: A 2 2 badarch
+#>=Pkg: C 2 2 badarch
+#>=Pkg: D 2 2 badarch
+#>=Pkg: D 2 2 noarch
+system i686 rpm
+
+job noop selection A provides
+result jobs <inline>
+#>job noop provides A
+
+nextjob
+job noop selection A.i686 provides,dotarch
+result jobs <inline>
+#>job noop provides A . i686 [setarch]
+
+nextjob
+job noop selection A.i686>1 provides,dotarch,rel
+result jobs <inline>
+#>job noop provides (A . i686) > 1 [setarch]
+
+nextjob
+job noop selection A* glob,provides,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available AP-3-1.noarch@available A-2-2.i686@available A-2-2.badarch@available
+#>job noop provides AP
+
+nextjob
+job noop selection A*>=2 glob,provides,dotarch,rel,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available AP-3-1.noarch@available A-2-2.i686@available A-2-2.badarch@available
+#>job noop provides AP >= 2
+
+nextjob
+job noop selection C provides,withbadarch
+result jobs <inline>
+#>job noop pkg C-2-2.badarch@available [noautoset]
+
+
+nextjob
+job noop selection D provides,withbadarch
+result jobs <inline>
+#>job noop oneof D-2-2.badarch@available D-2-2.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/strongrecommends/break.t b/libsolv-0.7.2/test/testcases/strongrecommends/break.t
new file mode 100644 (file)
index 0000000..54031c0
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# A recommends B and B recommends C
+#
+# With strongrecommends, we get the following
+# rules:
+#   A -> B
+#   B -> C
+# after pkg rules sorting, this will be (-B is less than -A)
+#   B -> C (weak)
+#   A -> B (weak)
+# If just the last weak rule is broken, only A will be
+# installed but but B. So the code now breaks all weak
+# recommends rules.
+repo system 0 testtags <inline>
+#>=Pkg: X 1 1 noarch
+#>=Con: C
+repo available 0 testtags <inline>
+#>=Pkg: A 1 2 noarch
+#>=Rec: B
+#>=Pkg: B 1 1 noarch
+#>=Rec: C
+#>=Pkg: C 1 1 noarch
+system i686 rpm system
+solverflags strongrecommends
+job install name A
+result transaction,problems <inline>
+#>install A-1-2.noarch@available
+#>install B-1-1.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/strongrecommends/strongr.t b/libsolv-0.7.2/test/testcases/strongrecommends/strongr.t
new file mode 100644 (file)
index 0000000..e6f5295
--- /dev/null
@@ -0,0 +1,27 @@
+# test strong recommends
+#
+# with normal recommends, the solver will
+# not backtrack to fulfill them.
+#
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Con: C
+#>=Pkg: A2 1 1 noarch
+#>=Con: C2
+repo available 0 testtags <inline>
+#>=Pkg: A 1 2 noarch
+#>=Pkg: B 1 1 noarch
+#>=Rec: C
+#>=Pkg: C 1 1 noarch
+#>=Pkg: B2 1 1 noarch
+#>=Rec: C2
+#>=Pkg: C2 1 1 noarch
+system i686 rpm system
+solverflags strongrecommends
+job install name B
+job install name B2
+result transaction,problems <inline>
+#>install B-1-1.noarch@available
+#>install B2-1-1.noarch@available
+#>install C-1-1.noarch@available
+#>upgrade A-1-1.noarch@system A-1-2.noarch@available
diff --git a/libsolv-0.7.2/test/testcases/targeted/targeted_dup.t b/libsolv-0.7.2/test/testcases/targeted/targeted_dup.t
new file mode 100644 (file)
index 0000000..bce3fef
--- /dev/null
@@ -0,0 +1,61 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: D 1 1 noarch
+#>=Pkg: Z 1 1 noarch
+#>=Con: D = 2-1 
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 0 noarch
+#>=Obs: A
+#>=Pkg: C 1 0 noarch
+#>=Obs: A = 1-1 
+#>=Pkg: D 2 1 noarch
+#>=Pkg: D 3 1 noarch
+system unset * system
+
+# first check untargeted
+job distupgrade name A = 1-1
+result transaction,problems <inline>
+#>erase A-1-1.noarch@system B-1-0.noarch@available
+#>install B-1-0.noarch@available
+
+# then targeted to A-2-1
+nextjob
+job distupgrade name A = 2-1
+result transaction,problems <inline>
+#>upgrade A-1-1.noarch@system A-2-1.noarch@available
+
+# then targeted to B
+nextjob
+job distupgrade name B
+result transaction,problems <inline>
+#>erase A-1-1.noarch@system B-1-0.noarch@available
+#>install B-1-0.noarch@available
+
+# first check forced to targeted
+nextjob
+job distupgrade name A = 1-1 [targeted]
+result transaction,problems <inline>
+
+# second check forced to untargeted
+nextjob
+solverflags noautotarget
+job distupgrade name A = 2-1
+result transaction,problems <inline>
+
+# then targeted to D
+nextjob
+job distupgrade name D
+result transaction,problems <inline>
+#>upgrade D-1-1.noarch@system D-3-1.noarch@available
+
+# then targeted to D-2-1 (should not go to D-3-1)
+nextjob
+job distupgrade name D = 2-1 
+result transaction,problems <inline>
+#>problem 840e2c39 info package Z-1-1.noarch conflicts with D = 2-1 provided by D-2-1.noarch
+#>problem 840e2c39 solution 3158736f erase Z-1-1.noarch@system
+#>problem 840e2c39 solution 42076df5 erase D-1-1.noarch@system
+#>problem 840e2c39 solution cdacbabe allow D-3-1.noarch@available
+#>upgrade D-1-1.noarch@system D-3-1.noarch@available
+
diff --git a/libsolv-0.7.2/test/testcases/targeted/targeted_up.t b/libsolv-0.7.2/test/testcases/targeted/targeted_up.t
new file mode 100644 (file)
index 0000000..a3cdd45
--- /dev/null
@@ -0,0 +1,56 @@
+repo system 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: D 1 1 noarch
+#>=Pkg: Z 1 1 noarch
+#>=Con: D = 2-1
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: B 1 0 noarch
+#>=Obs: A
+#>=Pkg: C 1 0 noarch
+#>=Obs: A = 1-1
+#>=Pkg: D 2 1 noarch
+#>=Pkg: D 3 1 noarch
+system unset * system
+
+# first check untargeted
+job update name A = 1-1
+result transaction,problems <inline>
+#>erase A-1-1.noarch@system B-1-0.noarch@available
+#>install B-1-0.noarch@available
+
+# then targeted to A-2-1
+nextjob
+job update name A = 2-1
+result transaction,problems <inline>
+#>upgrade A-1-1.noarch@system A-2-1.noarch@available
+
+# then targeted to B
+nextjob
+job update name B
+result transaction,problems <inline>
+#>erase A-1-1.noarch@system B-1-0.noarch@available
+#>install B-1-0.noarch@available
+
+# first check forced to targeted
+nextjob
+job update name A = 1-1 [targeted]
+result transaction,problems <inline>
+
+# second check forced to untargeted
+nextjob
+solverflags noautotarget
+job update name A = 2-1
+result transaction,problems <inline>
+
+# then targeted to D
+nextjob
+job update name D
+result transaction,problems <inline>
+#>upgrade D-1-1.noarch@system D-3-1.noarch@available
+
+# then targeted to D-2-1 (should not go to D-3-1)
+nextjob
+job update name D = 2-1
+result transaction,problems <inline>
+
diff --git a/libsolv-0.7.2/test/testcases/testcase/nested.t b/libsolv-0.7.2/test/testcases/testcase/nested.t
new file mode 100644 (file)
index 0000000..355f014
--- /dev/null
@@ -0,0 +1,56 @@
+# regression test for testcase_dep2str of deeply nested dependencies
+# this used to segfault or return wrong roundtrip results
+genid dep a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y |z
+result genid <inline>
+#>genid  1: genid lit a
+#>genid  2: genid lit b
+#>genid  3: genid lit c
+#>genid  4: genid lit d
+#>genid  5: genid lit e
+#>genid  6: genid lit f
+#>genid  7: genid lit g
+#>genid  8: genid lit h
+#>genid  9: genid lit i
+#>genid 10: genid lit j
+#>genid 11: genid lit k
+#>genid 12: genid lit l
+#>genid 13: genid lit m
+#>genid 14: genid lit n
+#>genid 15: genid lit o
+#>genid 16: genid lit p
+#>genid 17: genid lit q
+#>genid 18: genid lit r
+#>genid 19: genid lit s
+#>genid 20: genid lit t
+#>genid 21: genid lit u
+#>genid 22: genid lit v
+#>genid 23: genid lit w
+#>genid 24: genid lit x
+#>genid 25: genid lit y
+#>genid 26: genid lit z
+#>genid 27: genid op |
+#>genid 28: genid op |
+#>genid 29: genid op |
+#>genid 30: genid op |
+#>genid 31: genid op |
+#>genid 32: genid op |
+#>genid 33: genid op |
+#>genid 34: genid op |
+#>genid 35: genid op |
+#>genid 36: genid op |
+#>genid 37: genid op |
+#>genid 38: genid op |
+#>genid 39: genid op |
+#>genid 40: genid op |
+#>genid 41: genid op |
+#>genid 42: genid op |
+#>genid 43: genid op |
+#>genid 44: genid op |
+#>genid 45: genid op |
+#>genid 46: genid op |
+#>genid 47: genid op |
+#>genid 48: genid op |
+#>genid 49: genid op |
+#>genid 50: genid op |
+#>genid 51: genid op |
+#>genid dep a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z
diff --git a/libsolv-0.7.2/test/testcases/testcase/str2dep.t b/libsolv-0.7.2/test/testcases/testcase/str2dep.t
new file mode 100644 (file)
index 0000000..d08c110
--- /dev/null
@@ -0,0 +1,185 @@
+# testcase for testcase_str2dep and testcase_dep2str
+
+#
+# first test literal escaping
+#
+genid dep <NULL>
+result genid <inline>
+#>genid  1: genid null
+#>genid dep <NULL>
+nextjob
+
+genid dep \00
+result genid <inline>
+#>genid  1: genid lit 
+#>genid dep \00
+nextjob
+
+genid dep \21\20\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f\3a\3b\3c\3d\3e\3f\40\5b\5c\5d\5e\5f\60\7b\7c\7d\7e
+result genid <inline>
+#>genid  1: genid lit ! "#$%&'()*+,-./:;<=>?@[\]^_`{|}~
+#>genid dep \21\20"#$%&'\28\29*+,-./:;<=>?@[\5c]^_`{|}~
+# make vim happy again: '
+nextjob
+
+genid dep foo(bar)
+result genid <inline>
+#>genid  1: genid lit foo(bar)
+#>genid dep foo(bar)
+nextjob
+
+genid dep foo()bar\29
+result genid <inline>
+#>genid  1: genid lit foo()bar)
+#>genid dep foo\28\29bar\29
+nextjob
+
+#
+# test namespace hack
+#
+genid dep namespace:foo(bar)
+result genid <inline>
+#>genid  1: genid lit namespace:foo
+#>genid  2: genid lit bar
+#>genid  3: genid op <NAMESPACE>
+#>genid dep namespace:foo(bar)
+nextjob
+genid lit namespace:foo(bar)
+result genid <inline>
+#>genid  1: genid lit namespace:foo(bar)
+#>genid dep namespace\3afoo\28bar\29
+nextjob
+
+#
+# test :any hack
+#
+genid dep foo:any
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit any
+#>genid  3: genid op <MULTIARCH>
+#>genid dep foo:any
+nextjob
+genid lit foo:any
+result genid <inline>
+#>genid  1: genid lit foo:any
+#>genid dep foo\3aany
+nextjob
+
+#
+# test simple ops
+#
+genid dep foo < 1-1
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit 1-1
+#>genid  3: genid op <
+#>genid dep foo < 1-1
+nextjob
+
+genid dep foo = 1-1
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit 1-1
+#>genid  3: genid op =
+#>genid dep foo = 1-1
+nextjob
+
+genid dep foo > 1-1
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit 1-1
+#>genid  3: genid op >
+#>genid dep foo > 1-1
+nextjob
+
+genid dep foo >= 1-1
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit 1-1
+#>genid  3: genid op >=
+#>genid dep foo >= 1-1
+nextjob
+
+genid dep foo <= 1-1
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit 1-1
+#>genid  3: genid op <=
+#>genid dep foo <= 1-1
+nextjob
+
+# test arch op
+genid dep foo . i586
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit i586
+#>genid  3: genid op .
+#>genid dep foo . i586
+nextjob
+
+# test haiku compat dep
+genid dep foo = 2-1 compat >= 1-1
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit 2-1
+#>genid  3: genid lit 1-1
+#>genid  4: genid op compat >=
+#>genid  5: genid op =
+#>genid dep foo = 2-1 compat >= 1-1
+nextjob
+
+#
+# test complex (aka rich) deps
+#
+
+genid dep foo & bar
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit bar
+#>genid  3: genid op &
+#>genid dep foo & bar
+nextjob
+
+genid dep foo & bar & baz
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit bar
+#>genid  3: genid lit baz
+#>genid  4: genid op &
+#>genid  5: genid op &
+#>genid dep foo & bar & baz
+nextjob
+
+genid dep foo & bar | baz
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit bar
+#>genid  3: genid lit baz
+#>genid  4: genid op |
+#>genid  5: genid op &
+#>genid dep foo & (bar | baz)
+nextjob
+
+genid dep (foo & bar) | baz
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit bar
+#>genid  3: genid op &
+#>genid  4: genid lit baz
+#>genid  5: genid op |
+#>genid dep (foo & bar) | baz
+nextjob
+
+genid dep (foo & bar > 2) | baz
+result genid <inline>
+#>genid  1: genid lit foo
+#>genid  2: genid lit bar
+#>genid  3: genid lit 2
+#>genid  4: genid op >
+#>genid  5: genid op &
+#>genid  6: genid lit baz
+#>genid  7: genid op |
+#>genid dep (foo & bar > 2) | baz
+nextjob
+
diff --git a/libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t b/libsolv-0.7.2/test/testcases/weakdeps/supplements_implicitobsoleteusescolors.t
new file mode 100644 (file)
index 0000000..6de4544
--- /dev/null
@@ -0,0 +1,20 @@
+repo system 0 empty
+repo test 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: A 1 1 noarch
+#>=Pkg: B 1 1 x86_64
+#>=Sup: A
+#>=Pkg: B 1 1 i686
+#>=Sup: A
+#>=Pkg: A2 1 1 noarch
+#>=Pkg: B2 1 1 x86_64
+#>=Sup: A2
+#>=Req: XX
+#>=Pkg: B2 1 1 i686
+#>=Sup: A2
+system x86_64 * system
+poolflags implicitobsoleteusescolors
+job install name A
+
+nextjob
+job install name A2
diff --git a/libsolv-0.7.2/test/testcases/yumobs/split.t b/libsolv-0.7.2/test/testcases/yumobs/split.t
new file mode 100644 (file)
index 0000000..a3921ed
--- /dev/null
@@ -0,0 +1,24 @@
+repo system 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: c 27 1 x86_64
+repo available 0 testtags <inline>
+#>=Ver: 2.0
+#>=Pkg: d 28 1 x86_64
+#>=Obs: c
+#>=Pkg: e 28 1 x86_64
+#>=Obs: c
+
+system x86_64 rpm system
+
+job update all packages
+result transaction,problems <inline>
+#>erase c-27-1.x86_64@system d-28-1.x86_64@available
+#>install d-28-1.x86_64@available
+
+nextjob
+solverflags yumobsoletes
+job update all packages
+result transaction,problems <inline>
+#>erase c-27-1.x86_64@system d-28-1.x86_64@available
+#>install d-28-1.x86_64@available
+#>install e-28-1.x86_64@available
diff --git a/libsolv-0.7.2/tools/CMakeLists.txt b/libsolv-0.7.2/tools/CMakeLists.txt
new file mode 100644 (file)
index 0000000..802dc50
--- /dev/null
@@ -0,0 +1,114 @@
+#
+# CMakeLists.txt for tools
+#
+
+ADD_LIBRARY (toolstuff STATIC common_write.c)
+
+SET (tools_list mergesolv dumpsolv installcheck testsolv repo2solv)
+
+IF (ENABLE_RPMDB)
+ADD_EXECUTABLE (rpmdb2solv rpmdb2solv.c)
+TARGET_LINK_LIBRARIES (rpmdb2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (findfileconflicts findfileconflicts.c)
+TARGET_LINK_LIBRARIES (findfileconflicts libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} rpmdb2solv)
+ENDIF (ENABLE_RPMDB)
+
+IF (ENABLE_RPMPKG)
+ADD_EXECUTABLE (rpms2solv rpms2solv.c)
+TARGET_LINK_LIBRARIES (rpms2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+SET (tools_list ${tools_list} rpms2solv)
+ENDIF (ENABLE_RPMPKG)
+
+IF (ENABLE_RPMMD)
+ADD_EXECUTABLE (repomdxml2solv repomdxml2solv.c)
+TARGET_LINK_LIBRARIES (repomdxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (rpmmd2solv rpmmd2solv.c)
+TARGET_LINK_LIBRARIES (rpmmd2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (updateinfoxml2solv updateinfoxml2solv.c)
+TARGET_LINK_LIBRARIES (updateinfoxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (deltainfoxml2solv deltainfoxml2solv.c)
+TARGET_LINK_LIBRARIES (deltainfoxml2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} repomdxml2solv rpmmd2solv updateinfoxml2solv deltainfoxml2solv)
+ENDIF (ENABLE_RPMMD)
+
+IF (ENABLE_HELIXREPO)
+ADD_EXECUTABLE (helix2solv helix2solv.c)
+TARGET_LINK_LIBRARIES (helix2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} helix2solv)
+ENDIF (ENABLE_HELIXREPO)
+
+IF (ENABLE_SUSEREPO)
+ADD_EXECUTABLE (susetags2solv susetags2solv.c)
+TARGET_LINK_LIBRARIES (susetags2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} susetags2solv)
+ENDIF (ENABLE_SUSEREPO)
+
+IF (ENABLE_COMPS)
+ADD_EXECUTABLE (comps2solv comps2solv.c)
+TARGET_LINK_LIBRARIES (comps2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} comps2solv)
+ENDIF (ENABLE_COMPS)
+
+IF (ENABLE_DEBIAN)
+ADD_EXECUTABLE (deb2solv deb2solv.c)
+TARGET_LINK_LIBRARIES (deb2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} deb2solv)
+ENDIF (ENABLE_DEBIAN)
+
+IF (ENABLE_MDKREPO)
+ADD_EXECUTABLE (mdk2solv mdk2solv.c)
+TARGET_LINK_LIBRARIES (mdk2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} mdk2solv)
+ENDIF (ENABLE_MDKREPO)
+
+IF (ENABLE_ARCHREPO)
+ADD_EXECUTABLE (archpkgs2solv archpkgs2solv.c)
+TARGET_LINK_LIBRARIES (archpkgs2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (archrepo2solv archrepo2solv.c)
+TARGET_LINK_LIBRARIES (archrepo2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} archpkgs2solv archrepo2solv)
+ENDIF (ENABLE_ARCHREPO)
+
+IF (ENABLE_CUDFREPO)
+ADD_EXECUTABLE (cudftest cudftest.c)
+TARGET_LINK_LIBRARIES (cudftest libsolvext libsolv ${SYSTEM_LIBRARIES})
+ENDIF (ENABLE_CUDFREPO)
+
+ADD_EXECUTABLE (installcheck installcheck.c)
+TARGET_LINK_LIBRARIES (installcheck libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+IF (ENABLE_APPDATA)
+ADD_EXECUTABLE (appdata2solv appdata2solv.c)
+TARGET_LINK_LIBRARIES (appdata2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} appdata2solv)
+ENDIF (ENABLE_APPDATA)
+
+ADD_EXECUTABLE (dumpsolv dumpsolv.c )
+TARGET_LINK_LIBRARIES (dumpsolv libsolv)
+
+ADD_EXECUTABLE (mergesolv mergesolv.c )
+TARGET_LINK_LIBRARIES (mergesolv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (testsolv testsolv.c)
+TARGET_LINK_LIBRARIES (testsolv libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (repo2solv repo2solv.c )
+TARGET_LINK_LIBRARIES (repo2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+INSTALL (TARGETS ${tools_list} DESTINATION ${BIN_INSTALL_DIR})
+
diff --git a/libsolv-0.7.2/tools/appdata2solv.c b/libsolv-0.7.2/tools/appdata2solv.c
new file mode 100644 (file)
index 0000000..e5a42cf
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * appdata2solv.c
+ * 
+ * parse AppStream appdata type xml and write out .solv file
+ *
+ * reads from stdin
+ * writes to stdout
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_appdata.h"
+#include "common_write.h"
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool = pool_create();
+  Repo *repo;
+  int c;
+  const char *appdatadir = 0;
+  const char *root = 0;
+
+  while ((c = getopt(argc, argv, "hd:r:")) >= 0)
+    {
+      switch (c)
+       {
+       case 'd':
+         appdatadir = optarg;
+         break;
+       case 'r':
+         root = optarg;
+         break;
+       default:
+         fprintf(stderr, "usage: appdata2solv [-d appdatadir]");
+         exit(c == 'h' ? 0 : 1);
+       }
+    }
+
+  if (root)
+    pool_set_rootdir(pool, root);
+    
+  repo = repo_create(pool, "<stdin>");
+  if (!appdatadir)
+    {
+      if (repo_add_appdata(repo, stdin, 0))
+       {
+         fprintf(stderr, "appdata2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+  else
+    {
+      if (repo_add_appdata_dir(repo, appdatadir, REPO_USE_ROOTDIR))
+       {
+         fprintf(stderr, "appdata2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/archpkgs2solv.c b/libsolv-0.7.2/tools/archpkgs2solv.c
new file mode 100644 (file)
index 0000000..14c3ba4
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * archpkgs2solv - create a solv file from multiple arch packages
+ * 
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "util.h"
+#include "pool.h"
+#include "repo.h"
+#include "repo_arch.h"
+#include "repo_solv.h"
+#include "common_write.h"
+
+static char *
+fgets0(char *s, int size, FILE *stream)
+{
+  char *p = s;
+  int c;
+
+  while (--size > 0)
+    {
+      c = getc(stream);
+      if (c == EOF)
+       {
+         if (p == s)
+           return 0;
+         c = 0;
+       }
+      *p++ = c;
+      if (!c)
+       return s;
+    }
+  *p = 0;
+  return s;
+}
+
+int
+main(int argc, char **argv)
+{
+  const char **pkgs = 0;
+  char *manifest = 0;
+  int manifest0 = 0;
+  int i, c, res, npkgs = 0;
+  Pool *pool = pool_create();
+  Repo *repo;
+  FILE *fp;
+  char buf[4096], *p;
+  int flags = 0;
+
+  while ((c = getopt(argc, argv, "0:m:i")) >= 0)
+    {
+      switch(c)
+       {
+       case 'm':
+         manifest = optarg;
+         break;
+       case '0':
+         manifest0 = 1;
+         break;
+       case 'i':
+         flags |= ARCH_ADD_WITH_PKGID;
+         break;
+       default:
+         exit(1);
+       }
+    }
+  if (manifest)
+    {
+      if (!strcmp(manifest, "-"))
+        fp = stdin;
+      else if ((fp = fopen(manifest, "r")) == 0)
+       {
+         perror(manifest);
+         exit(1);
+       }
+      for (;;)
+       {
+         if (manifest0)
+           {
+             if (!fgets0(buf, sizeof(buf), fp))
+               break;
+           }
+         else
+           {
+             if (!fgets(buf, sizeof(buf), fp))
+               break;
+             if ((p = strchr(buf, '\n')) != 0)
+               *p = 0;
+           }
+          pkgs = solv_extend(pkgs, npkgs, 1, sizeof(char *), 15);
+         pkgs[npkgs++] = strdup(buf);
+       }
+      if (fp != stdin)
+        fclose(fp);
+    }
+  while (optind < argc)
+    {
+      pkgs = solv_extend(pkgs, npkgs, 1, sizeof(char *), 15);
+      pkgs[npkgs++] = solv_strdup(argv[optind++]);
+    }
+  repo = repo_create(pool, "archpkgs2solv");
+  repo_add_repodata(repo, 0);
+  res = 0;
+  for (i = 0; i < npkgs; i++)
+    if (repo_add_arch_pkg(repo, pkgs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|flags) == 0)
+      {
+       fprintf(stderr, "archpkgs2solv: %s\n", pool_errstr(pool));
+       res = 1;
+      }
+  repo_internalize(repo);
+  tool_write(repo, stdout);
+  pool_free(pool);
+  for (c = 0; c < npkgs; c++)
+    solv_free((char *)pkgs[c]);
+  solv_free(pkgs);
+  exit(res);
+}
+
diff --git a/libsolv-0.7.2/tools/archrepo2solv.c b/libsolv-0.7.2/tools/archrepo2solv.c
new file mode 100644 (file)
index 0000000..e60960f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * archrepo2solv.c
+ *
+ * parse archlinux repo file
+ *
+ * reads from stdin
+ * writes to stdout
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_arch.h"
+#include "solv_xfopen.h"
+#include "common_write.h"
+
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "archrepo2solv\n"
+          "  reads a repository from <stdin> and writes a .solv file to <stdout>\n"
+          "  -l <dbdir> : read local database\n"
+          "  -h : print help & exit\n"
+         );
+   exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Repo *repo;
+  int c, ret;
+  const char *localdb = 0;
+
+  while ((c = getopt(argc, argv, "hl:")) >= 0)
+    {
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       case 'l':
+         localdb = optarg;
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  pool = pool_create();
+  repo = repo_create(pool, "<stdin>");
+  if (localdb)
+    ret = repo_add_arch_local(repo, localdb, 0);
+  else
+    ret = repo_add_arch_repo(repo, stdin, 0);
+  if (ret)
+    {
+      fprintf(stderr, "archrepo2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/common_write.c b/libsolv-0.7.2/tools/common_write.c
new file mode 100644 (file)
index 0000000..36f8dd8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_write.h"
+#include "common_write.h"
+#include "solvversion.h"
+
+/* toolversion history
+ * 1.0: initial tool version
+ * 1.1: changed PRODUCT_ENDOFLIFE parsing
+*/
+
+static int
+keyfilter_solv(Repo *repo, Repokey *key, void *kfdata)
+{
+  if (key->name == SUSETAGS_SHARE_NAME || key->name == SUSETAGS_SHARE_EVR || key->name == SUSETAGS_SHARE_ARCH)
+    return KEY_STORAGE_DROPPED;
+  return repo_write_stdkeyfilter(repo, key, kfdata);
+}
+
+/*
+ * Write <repo> to fp
+ */
+void
+tool_write(Repo *repo, FILE *fp)
+{
+  Repodata *info;
+  Queue addedfileprovides;
+  Repowriter *writer;
+
+  info = repo_add_repodata(repo, 0);   /* add new repodata for our meta info */
+  repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
+  repodata_unset(info, SOLVID_META, REPOSITORY_EXTERNAL);      /* do not propagate this */
+
+  queue_init(&addedfileprovides);
+  pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0);
+  if (addedfileprovides.count)
+    repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides);
+  else
+    repodata_unset(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES);
+  queue_free(&addedfileprovides);
+
+  pool_freeidhashes(repo->pool);       /* free some mem */
+
+  repodata_internalize(info);
+  writer = repowriter_create(repo);
+  repowriter_set_keyfilter(writer, keyfilter_solv, 0);
+  if (repowriter_write(writer, fp) != 0)
+    {
+      fprintf(stderr, "repo write failed: %s\n", pool_errstr(repo->pool));
+      exit(1);
+    }
+  if (fflush(fp))
+    {
+      perror("fflush");
+      exit(1);
+    }
+  repowriter_free(writer);
+  repodata_free(info);         /* delete meta info repodata again */
+}
diff --git a/libsolv-0.7.2/tools/common_write.h b/libsolv-0.7.2/tools/common_write.h
new file mode 100644 (file)
index 0000000..fda1fd5
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef COMMON_WRITE_H
+#define COMMON_WRITE_H
+
+#include "repo.h"
+
+void tool_write(Repo *repo, FILE *fp);
+
+#endif
diff --git a/libsolv-0.7.2/tools/comps2solv.c b/libsolv-0.7.2/tools/comps2solv.c
new file mode 100644 (file)
index 0000000..ebb39b5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * comps2solv.c
+ * 
+ * parse Fedora Comps type xml and write out .solv file
+ *
+ * reads from stdin
+ * writes to stdout
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_comps.h"
+#include "common_write.h"
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+  if (repo_add_comps(repo, stdin, 0))
+    {
+      fprintf(stderr, "comps2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/cudftest.c b/libsolv-0.7.2/tools/cudftest.c
new file mode 100644 (file)
index 0000000..75aeef5
--- /dev/null
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "evr.h"
+#include "solver.h"
+#include "solverdebug.h"
+#include "repo_cudf.h"
+#include "repo_write.h"
+#include "solv_xfopen.h"
+
+static void
+dump_repo(Repo *repo, char *name)
+{
+  FILE *fp;
+  if ((fp = fopen(name, "w")) == 0)
+    {
+      perror(name);
+      exit(1);
+    }
+  repo_write(repo, fp);
+  fclose(fp);
+}
+
+static int
+sortfunc(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  Solvable *sa, *sb;
+  sa = pool->solvables + *(Id *)ap;
+  sb = pool->solvables + *(Id *)bp;
+  if (sa->name != sb->name)
+    {
+      int r = strcmp(pool_id2str(pool, sa->name), pool_id2str(pool, sb->name));
+      if (r)
+       return r;
+    }
+  if (sa->evr != sb->evr)
+    {
+      int r = pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE);
+      if (r)
+       return r;
+    }
+  return *(Id *)ap - *(Id *)bp;
+}
+
+int
+main(int argc, char **argv)
+{
+  char *cudfin;
+  char *cudfout = 0;
+  Pool *pool;
+  Repo *installed, *repo;
+  FILE *fp, *ofp;
+  Solver *solv;
+  Transaction *trans;
+  Queue job;
+  Queue dq;
+  int i;
+  int debug = 0;
+
+  while (argc > 1 && !strcmp(argv[1], "-d"))
+    {
+      debug++;
+      argc--;
+      argv++;
+    }
+  if (argc < 2)
+    {
+      fprintf(stderr, "Usage: cudftest <cudfin> [cudfout]\n");
+      exit(1);
+    }
+  cudfin = argv[1];
+  cudfout = argc > 2 ? argv[2] : 0;
+
+  if ((fp = solv_xfopen(cudfin, 0)) == 0)
+    {
+      perror(cudfin);
+      exit(1);
+    }
+  pool = pool_create();
+  if (debug > 1)
+    pool_setdebuglevel(pool, debug - 1);
+  installed = repo_create(pool, "installed");
+  pool_set_installed(pool, installed);
+  repo = repo_create(pool, "repo");
+  queue_init(&job);
+  repo_add_cudf(repo, installed, fp, &job, 0);
+  fclose(fp);
+
+  pool_createwhatprovides(pool);
+
+  /* debug */
+  if (debug)
+    {
+      dump_repo(installed, "cudf_installed.solv");
+      dump_repo(repo, "cudf_repo.solv");
+    }
+
+  solv = solver_create(pool);
+  solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
+  /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */
+
+  queue_push2(&job, SOLVER_VERIFY | SOLVER_SOLVABLE_ALL, 0);
+  if (solver_solve(solv, &job) != 0)
+    {
+      int problem;
+      int pcnt = solver_problem_count(solv);
+      printf("Found %d problems:\n", pcnt);
+      for (problem = 1; problem <= pcnt; problem++)
+        {
+          printf("Problem %d:\n", problem);
+          solver_printprobleminfo(solv, problem);
+          printf("\n");
+       }
+    }
+  trans = solver_create_transaction(solv);
+  solver_free(solv);
+
+  if (debug)
+    transaction_print(trans);
+
+  queue_init(&dq);
+  transaction_installedresult(trans, &dq);
+  solv_sort(dq.elements, dq.count, sizeof(Id), sortfunc, pool);
+
+  ofp = stdout;
+  if (cudfout && ((ofp = fopen(cudfout, "w")) == 0))
+    {
+      perror(cudfout);
+      exit(1);
+    }
+  for (i = 0; i < dq.count; i++)
+    {
+      Solvable *s = pool_id2solvable(pool, dq.elements[i]);
+      fprintf(ofp, "package: %s\n", pool_id2str(pool, s->name));
+      fprintf(ofp, "version: %s\n", pool_id2str(pool, s->evr));
+      fprintf(ofp, "installed: true\n");
+      if (s->repo == pool->installed)
+        fprintf(ofp, "was-installed: true\n");
+      fprintf(ofp, "\n");
+    }
+  queue_free(&dq);
+  transaction_free(trans);
+  queue_free(&job);
+  pool_free(pool);
+  if (ofp != stdout)
+    {
+      if (fclose(ofp))
+       {
+         perror("fclose");
+         exit(1);
+       }
+    }
+  exit(0);
+}
+
diff --git a/libsolv-0.7.2/tools/deb2solv.c b/libsolv-0.7.2/tools/deb2solv.c
new file mode 100644 (file)
index 0000000..ad27541
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * deb2solv - create a solv file from one or multiple debs
+ * 
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "util.h"
+#include "pool.h"
+#include "repo.h"
+#include "repo_deb.h"
+#include "repo_solv.h"
+#include "common_write.h"
+
+static char *
+fgets0(char *s, int size, FILE *stream)
+{
+  char *p = s;
+  int c;
+
+  while (--size > 0)
+    {
+      c = getc(stream);
+      if (c == EOF)
+       {
+         if (p == s)
+           return 0;
+         c = 0;
+       }
+      *p++ = c;
+      if (!c)
+       return s;
+    }
+  *p = 0;
+  return s;
+}
+
+int
+main(int argc, char **argv)
+{
+  const char **debs = 0;
+  char *manifest = 0;
+  int manifest0 = 0;
+  int c, i, res, ndebs = 0;
+  Pool *pool = pool_create();
+  Repo *repo;
+  FILE *fp;
+  char buf[4096], *p;
+  const char *basefile = 0;
+  int is_repo = 0;
+
+  while ((c = getopt(argc, argv, "0:m:r")) >= 0)
+    {
+      switch(c)
+       {
+       case 'm':
+         manifest = optarg;
+         break;
+       case 'r':
+         is_repo = 1;
+         break;
+       case '0':
+         manifest0 = 1;
+         break;
+       default:
+         exit(1);
+       }
+    }
+  if (manifest)
+    {
+      if (!strcmp(manifest, "-"))
+        fp = stdin;
+      else if ((fp = fopen(manifest, "r")) == 0)
+       {
+         perror(manifest);
+         exit(1);
+       }
+      for (;;)
+       {
+         if (manifest0)
+           {
+             if (!fgets0(buf, sizeof(buf), fp))
+               break;
+           }
+         else
+           {
+             if (!fgets(buf, sizeof(buf), fp))
+               break;
+             if ((p = strchr(buf, '\n')) != 0)
+               *p = 0;
+           }
+          debs = solv_extend(debs, ndebs, 1, sizeof(char *), 15);
+         debs[ndebs++] = strdup(buf);
+       }
+      if (fp != stdin)
+        fclose(fp);
+    }
+  while (optind < argc)
+    {
+      debs = solv_extend(debs, ndebs, 1, sizeof(char *), 15);
+      debs[ndebs++] = strdup(argv[optind++]);
+    }
+  repo = repo_create(pool, "deb2solv");
+  repo_add_repodata(repo, 0);
+  res = 0;
+  if (!ndebs && !manifest && is_repo)
+    {
+      if (repo_add_debpackages(repo, stdin, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE))
+       {
+         fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));
+         res = 1;
+       }
+    }
+  for (i = 0; i < ndebs; i++)
+    {
+      if (is_repo)
+       {
+         if ((fp = fopen(debs[i], "r")) == 0)
+           {
+             perror(debs[i]);
+             res = 1;
+             continue;
+           }
+         if (repo_add_debpackages(repo, fp, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE))
+           {
+             fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));
+             res = 1;
+           }
+         fclose(fp);
+         continue;
+       }
+      if (repo_add_deb(repo, debs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE) == 0)
+       {
+         fprintf(stderr, "deb2solv: %s\n", pool_errstr(pool));
+         res = 1;
+       }
+    }
+  repo_internalize(repo);
+  tool_write(repo, stdout);
+  pool_free(pool);
+  for (c = 0; c < ndebs; c++)
+    free((char *)debs[c]);
+  solv_free(debs);
+  exit(res);
+}
+
diff --git a/libsolv-0.7.2/tools/deltainfoxml2solv.c b/libsolv-0.7.2/tools/deltainfoxml2solv.c
new file mode 100644 (file)
index 0000000..906b3ad
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_deltainfoxml.h"
+#include "common_write.h"
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "deltainfoxml2solv [-h]\n"
+         "  reads a 'deltainfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
+         "  -h : print help & exit\n"
+        );
+  exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, flags = 0;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+
+  while ((c = getopt(argc, argv, "h")) >= 0)
+    {   
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  if (repo_add_deltainfoxml(repo, stdin, flags))
+    {
+      fprintf(stderr, "deltainfoxml2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/diskusagexml2solv.c b/libsolv-0.7.2/tools/diskusagexml2solv.c
new file mode 100644 (file)
index 0000000..850b02c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_diskusagexml.h"
+#include "common_write.h"
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "diskusagexml2solv [-h]\n"
+         "  reads a 'diskusage.xml' file from <stdin> and writes a .solv file to <stdout>\n"
+         "  -h : print help & exit\n"
+        );
+  exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, flags = 0;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+
+  while ((c = getopt(argc, argv, "h")) >= 0)
+    {   
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  if (repo_add_diskusagexml(repo, stdin, flags))
+    {
+      fprintf(stderr, "diskusagexml2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/dumpsolv.c b/libsolv-0.7.2/tools/dumpsolv.c
new file mode 100644 (file)
index 0000000..bdd521e
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+static int with_attr;
+static int dump_json;
+
+#include "pool.h"
+#include "chksum.h"
+#include "repo_solv.h"
+
+
+static int
+dump_attr(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  const char *keyname;
+  KeyValue *kvp;
+  int indent = 0;
+
+  keyname = pool_id2str(repo->pool, key->name);
+  for (kvp = kv; (kvp = kvp->parent) != 0; indent += 2)
+    printf("  ");
+  switch(key->type)
+    {
+    case REPOKEY_TYPE_ID:
+      if (data && data->localpool)
+       kv->str = stringpool_id2str(&data->spool, kv->id);
+      else
+       kv->str = pool_dep2str(repo->pool, kv->id);
+      printf("%s: %s\n", keyname, kv->str);
+      break;
+    case REPOKEY_TYPE_CONSTANTID:
+      printf("%s: %s\n", keyname, pool_dep2str(repo->pool, kv->id));
+      break;
+    case REPOKEY_TYPE_IDARRAY:
+      if (!kv->entry)
+        printf("%s:\n%*s", keyname, indent, "");
+      if (data && data->localpool)
+        printf("  %s\n", stringpool_id2str(&data->spool, kv->id));
+      else
+        printf("  %s\n", pool_dep2str(repo->pool, kv->id));
+      break;
+    case REPOKEY_TYPE_STR:
+      printf("%s: %s\n", keyname, kv->str);
+      break;
+    case REPOKEY_TYPE_VOID:
+      printf("%s: (void)\n", keyname);
+      break;
+    case REPOKEY_TYPE_CONSTANT:
+      printf("%s: %u\n", keyname, kv->num);
+      break;
+    case REPOKEY_TYPE_NUM:
+      printf("%s: %llu\n", keyname, SOLV_KV_NUM64(kv));
+      break;
+    case REPOKEY_TYPE_BINARY:
+      if (kv->num)
+        printf("%s: %02x..%02x len %u\n", keyname, (unsigned char)kv->str[0], (unsigned char)kv->str[kv->num - 1], kv->num);
+      else
+        printf("%s: len 0\n", keyname);
+      break;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      if (!kv->entry)
+        printf("%s:\n%*s", keyname, indent, "");
+      printf("  %s %u %u\n", repodata_dir2str(data, kv->id, 0), kv->num, kv->num2);
+      break;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      if (!kv->entry)
+        printf("%s:\n%*s", keyname, indent, "");
+      printf("  %s\n", repodata_dir2str(data, kv->id, kv->str));
+      break;
+    case REPOKEY_TYPE_FIXARRAY:
+    case REPOKEY_TYPE_FLEXARRAY:
+      if (!kv->entry)
+        printf("%s:\n", keyname);
+      else
+        printf("\n");
+      break;
+    default:
+      if (solv_chksum_len(key->type))
+       {
+         printf("%s: %s (%s)\n", keyname, repodata_chk2str(data, key->type, (unsigned char *)kv->str), solv_chksum_type2str(key->type));
+         break;
+       }
+      printf("%s: ?\n", keyname);
+      break;
+    }
+  return 0;
+}
+
+static const char *
+jsonstring(Pool *pool, const char *s)
+{
+  int needed = 0;
+  const unsigned char *s1;
+  char *r, *rp;
+  
+  for (s1 = (const unsigned char *)s; *s1; s1++)
+    {
+      if (*s1 < 32)
+       needed += *s1 == '\n' ? 2 : 6;
+      else if (*s1 == '\\' || *s1 == '\"')
+       needed += 2;
+      else
+       needed++;
+    }
+  r = rp = pool_alloctmpspace(pool, needed + 3);
+  *rp++ = '\"';
+  for (s1 = (const unsigned char *)s; *s1; s1++)
+    {
+      if (*s1 < 32)
+       {
+         int x;
+         if (*s1 == '\n')
+           {
+             *rp++ = '\\';
+             *rp++ = 'n';
+             continue;
+           }
+         *rp++ = '\\';
+         *rp++ = 'u';
+         *rp++ = '0';
+         *rp++ = '0';
+         x = *s1 / 16;
+         *rp++ = (x < 10 ? '0' : 'a' - 10) + x;
+         x = *s1 & 15;
+         *rp++ = (x < 10 ? '0' : 'a' - 10) + x;
+       }
+      else if (*s1 == '\\' || *s1 == '\"')
+       {
+         *rp++ = '\\';
+         *rp++ = *s1;
+       }
+      else
+        *rp++ = *s1;
+    }
+  *rp++ = '\"';
+  *rp = 0;
+  return r;
+}
+
+struct cbdata {
+  unsigned char *first;
+  int nfirst;
+  int baseindent;
+};
+
+static int
+dump_attr_json(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv, struct cbdata *cbdata)
+{
+  Pool *pool = repo->pool;
+  const char *keyname;
+  KeyValue *kvp;
+  int indent = cbdata->baseindent;
+  int isarray = 0;
+  const char *str;
+  int depth = 0;
+
+  keyname = pool_id2str(repo->pool, key->name);
+  for (kvp = kv; (kvp = kvp->parent) != 0; indent += 4)
+    depth++;
+  if (cbdata->nfirst < depth + 1)
+    {
+      cbdata->first = solv_realloc(cbdata->first, depth + 16);
+      memset(cbdata->first + cbdata->nfirst, 0, depth + 16 - cbdata->nfirst);
+      cbdata->nfirst = depth + 16;
+    }
+  switch(key->type)
+    {
+    case REPOKEY_TYPE_IDARRAY:
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      isarray = 1;
+      break;
+    case REPOKEY_TYPE_FIXARRAY:
+    case REPOKEY_TYPE_FLEXARRAY:
+      isarray = 2;
+      break;
+    default:
+      break;
+    }
+  if (!isarray || !kv->entry)
+    {
+      if (cbdata->first[depth])
+       printf(",\n");
+      printf("%*s%s: ", indent, "", jsonstring(pool, keyname));
+      cbdata->first[depth] = 1;
+    }
+  if (isarray == 1 && !kv->entry)
+    printf("[\n%*s", indent + 2, "");
+  else if (isarray == 1 && kv->entry)
+    printf("%*s", indent + 2, "");
+  switch(key->type)
+    {
+    case REPOKEY_TYPE_ID:
+      if (data && data->localpool)
+       str = stringpool_id2str(&data->spool, kv->id);
+      else
+       str = pool_dep2str(repo->pool, kv->id);
+      printf("%s", jsonstring(pool, str));
+      break;
+    case REPOKEY_TYPE_CONSTANTID:
+      str = pool_dep2str(repo->pool, kv->id);
+      printf("%s", jsonstring(pool, str));
+      break;
+    case REPOKEY_TYPE_IDARRAY:
+      if (data && data->localpool)
+        str = stringpool_id2str(&data->spool, kv->id);
+      else
+        str = pool_dep2str(repo->pool, kv->id);
+      printf("%s", jsonstring(pool, str));
+      break;
+    case REPOKEY_TYPE_STR:
+      str = kv->str;
+      printf("%s", jsonstring(pool, str));
+      break;
+    case REPOKEY_TYPE_VOID:
+      printf("null");
+      break;
+    case REPOKEY_TYPE_CONSTANT:
+      printf("%u", kv->num);
+      break;
+    case REPOKEY_TYPE_NUM:
+      printf("%llu", SOLV_KV_NUM64(kv));
+      break;
+    case REPOKEY_TYPE_BINARY:
+      printf("\"<binary>\"");
+      break;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      printf("{\n");
+      printf("%*s    \"dir\": %s,\n", indent, "", jsonstring(pool, repodata_dir2str(data, kv->id, 0)));
+      printf("%*s    \"num1\": %u,\n", indent, "", kv->num);
+      printf("%*s    \"num2\": %u\n", indent, "", kv->num2);
+      printf("%*s  }", indent, "");
+      break;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      printf("%s", jsonstring(pool, repodata_dir2str(data, kv->id, kv->str)));
+      break;
+    case REPOKEY_TYPE_FIXARRAY:
+    case REPOKEY_TYPE_FLEXARRAY:
+      cbdata->first[depth + 1] = 0;
+      if (!kv->entry)
+       printf("[\n");
+      else
+       {
+         if (kv->eof != 2)
+            printf("\n%*s  },\n", indent, "");
+         else
+            printf("\n%*s  }\n", indent, "");
+       }
+      if (kv->eof != 2)
+        printf("%*s  {\n", indent, "");
+      else
+        printf("%*s]", indent, "");
+      break;
+    default:
+      if (solv_chksum_len(key->type))
+       {
+         printf("{\n");
+         printf("%*s  \"value\": %s,\n", indent, "", jsonstring(pool, repodata_chk2str(data, key->type, (unsigned char *)kv->str)));
+         printf("%*s  \"type\": %s\n", indent, "", jsonstring(pool, solv_chksum_type2str(key->type)));
+         printf("%*s}", indent, "");
+         break;
+       }
+      printf("\"?\"");
+      break;
+    }
+  if (isarray == 1)
+    {
+      if (!kv->eof)
+        printf(",\n");
+      else
+        printf("\n%*s]", indent, "");
+    }
+  return 0;
+}
+
+static int
+dump_repodata_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  if (key->name == REPOSITORY_SOLVABLES)
+    return SEARCH_NEXT_SOLVABLE;
+  if (!dump_json)
+    return dump_attr(data->repo, data, key, kv);
+  else
+    return dump_attr_json(data->repo, data, key, kv, vcbdata);
+}
+
+static void
+dump_repodata(Repo *repo)
+{
+  int i;
+  Repodata *data;
+  if (repo->nrepodata == 0)
+    return;
+  printf("repo contains %d repodata sections:\n", repo->nrepodata - 1);
+  FOR_REPODATAS(repo, i, data)
+    {
+      unsigned int j;
+      printf("\nrepodata %d has %d keys, %d schemata\n", i, data->nkeys - 1, data->nschemata - 1);
+      for (j = 1; j < data->nkeys; j++)
+       printf("  %s (type %s size %d storage %d)\n", pool_id2str(repo->pool, data->keys[j].name), pool_id2str(repo->pool, data->keys[j].type), data->keys[j].size, data->keys[j].storage);
+      if (data->localpool)
+       printf("  localpool has %d strings, size is %d\n", data->spool.nstrings, data->spool.sstrings);
+      if (data->dirpool.ndirs)
+       printf("  localpool has %d directories\n", data->dirpool.ndirs);
+      printf("\n");
+      repodata_search(data, SOLVID_META, 0, SEARCH_ARRAYSENTINEL|SEARCH_SUB, dump_repodata_cb, 0);
+    }
+  printf("\n");
+}
+
+static void
+dump_repodata_json(Repo *repo, struct cbdata *cbdata)
+{
+  int i;
+  Repodata *data;
+  if (repo->nrepodata == 0)
+    return;
+  cbdata->baseindent = 6;
+  FOR_REPODATAS(repo, i, data)
+    repodata_search(data, SOLVID_META, 0, SEARCH_ARRAYSENTINEL|SEARCH_SUB, dump_repodata_cb, cbdata);
+}
+
+/*
+ * dump all attributes for Id <p>
+ */
+
+void
+dump_solvable(Repo *repo, Id p, struct cbdata *cbdata)
+{
+  Dataiterator di;
+  dataiterator_init(&di, repo->pool, repo, p, 0, 0, SEARCH_ARRAYSENTINEL|SEARCH_SUB);
+  if (cbdata && cbdata->first)
+    cbdata->first[0] = 0;
+  if (cbdata)
+    cbdata->baseindent = 10;
+  while (dataiterator_step(&di))
+    {
+      if (!dump_json)
+        dump_attr(repo, di.data, di.key, &di.kv);
+      else
+        dump_attr_json(repo, di.data, di.key, &di.kv, cbdata);
+    }
+  dataiterator_free(&di);
+}
+
+static int
+loadcallback(Pool *pool, Repodata *data, void *vdata)
+{
+  FILE *fp = 0;
+  int r;
+  const char *location;
+
+  location = repodata_lookup_str(data, SOLVID_META, REPOSITORY_LOCATION);
+  if (!location || !with_attr)
+    return 0;
+  fprintf(stderr, "[Loading SOLV file %s]\n", location);
+  fp = fopen (location, "r");
+  if (!fp)
+    {
+      perror(location);
+      return 0;
+    }
+  r = repo_add_solv(data->repo, fp, REPO_USE_LOADING|REPO_LOCALPOOL);
+  fclose(fp);
+  return !r ? 1 : 0;
+}
+
+
+static void
+usage(int status)
+{
+  fprintf( stderr, "\nUsage:\n"
+          "dumpsolv [-a] [-j] [<solvfile>]\n"
+          "  -a  read attributes.\n"
+          "  -j  dump json format.\n"
+          );
+  exit(status);
+}
+
+int main(int argc, char **argv)
+{
+  Repo *repo;
+  Pool *pool;
+  int c, i, j, n;
+  Solvable *s;
+  
+  pool = pool_create();
+  pool_setloadcallback(pool, loadcallback, 0);
+
+  while ((c = getopt(argc, argv, "haj")) >= 0)
+    {
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       case 'a':
+         with_attr = 1;
+         break;
+       case 'j':
+         dump_json = 1;
+         break;
+       default:
+          usage(1);
+          break;
+       }
+    }
+  if (!dump_json)
+    pool_setdebuglevel(pool, 1);
+  if (dump_json)
+    pool->debugmask |= SOLV_DEBUG_TO_STDERR;
+  for (; optind < argc; optind++)
+    {
+      if (freopen(argv[optind], "r", stdin) == 0)
+       {
+         perror(argv[optind]);
+         exit(1);
+       }
+      repo = repo_create(pool, argv[optind]);
+      if (repo_add_solv(repo, stdin, 0))
+       {
+         fprintf(stderr, "could not read repository: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+  if (!pool->urepos)
+    {
+      repo = repo_create(pool, argc != 1 ? argv[1] : "<stdin>");
+      if (repo_add_solv(repo, stdin, 0))
+       {
+         fprintf(stderr, "could not read repository: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+
+  if (dump_json)
+    {
+      int openrepo = 0;
+      struct cbdata cbdata;
+
+      memset(&cbdata, 0, sizeof(cbdata));
+      printf("{\n");
+      printf("  \"repositories\": [\n");
+      FOR_REPOS(j, repo)
+       {
+         int open = 0;
+
+         if (openrepo)
+           printf("\n    },");
+         printf("    {\n");
+         openrepo = 1;
+         if (cbdata.first)
+           cbdata.first[0] = 0;
+         dump_repodata_json(repo, &cbdata);
+         if (cbdata.first[0])
+           printf(",\n");
+         printf("      \"solvables\": [\n");
+         FOR_REPO_SOLVABLES(repo, i, s)
+           {
+             if (open)
+               printf("\n        },\n");
+             printf("        {\n");
+             open = 1;
+             dump_solvable(repo, i, &cbdata);
+           }
+         if (open)
+           printf("\n        }\n");
+         printf("      ]\n");
+       }
+      if (openrepo)
+       printf("    }\n");
+      printf("  ]\n");
+      printf("}\n");
+      solv_free(cbdata.first);
+    }
+  else
+    {
+      printf("pool contains %d strings, %d rels, string size is %d\n", pool->ss.nstrings, pool->nrels, pool->ss.sstrings);
+      n = 0;
+      FOR_REPOS(j, repo)
+       {
+         dump_repodata(repo);
+         printf("repo %d contains %d solvables\n", j, repo->nsolvables);
+         printf("repo start: %d end: %d\n", repo->start, repo->end);
+         FOR_REPO_SOLVABLES(repo, i, s)
+           {
+             n++;
+             printf("\n");
+             printf("solvable %d (%d):\n", n, i);
+             dump_solvable(repo, i, 0);
+           }
+       }
+    }
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/findfileconflicts.c b/libsolv-0.7.2/tools/findfileconflicts.c
new file mode 100644 (file)
index 0000000..712602d
--- /dev/null
@@ -0,0 +1,101 @@
+/* vim: sw=2 et
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "solver.h"
+#include "solverdebug.h"
+#include "hash.h"
+#include "repo_rpmdb.h"
+#include "pool_fileconflicts.h"
+
+static void *
+iterate_handle(Pool *pool, Id p, void *cbdata)
+{
+  Solvable *s = pool->solvables + p;
+  Id rpmdbid;
+  void *handle;
+  
+  if (!s->repo->rpmdbid)
+    return 0;
+  rpmdbid = s->repo->rpmdbid[p - s->repo->start];
+  if (!rpmdbid)
+    return 0;
+  handle = rpm_byrpmdbid(cbdata, rpmdbid);
+  if (!handle)
+    fprintf(stderr, "rpm_byrpmdbid: %s\n", pool_errstr(pool));
+  return handle;
+}
+
+int main(int argc, char **argv)
+{
+  Pool *pool;
+  Repo *installed;
+  Solvable *s;
+  Id p;
+  int i;
+  Queue todo, conflicts;
+  void *state = 0;
+  char *rootdir = 0;
+  if (argc == 3 && !strcmp(argv[1], "--root"))
+    rootdir = argv[2];
+  pool = pool_create();
+  if (rootdir)
+    pool_set_rootdir(pool, rootdir);
+  pool_setdebuglevel(pool, 1);
+  installed = repo_create(pool, "@System");
+  pool_set_installed(pool, installed);
+  if (repo_add_rpmdb(installed, 0, REPO_USE_ROOTDIR))
+    {
+      fprintf(stderr, "findfileconflicts: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  queue_init(&todo);
+  queue_init(&conflicts);
+  FOR_REPO_SOLVABLES(installed, p, s)
+    queue_push(&todo, p);
+  state = rpm_state_create(pool, pool_get_rootdir(pool));
+  pool_findfileconflicts(pool, &todo, 0, &conflicts, FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, &iterate_handle, state);
+  rpm_state_free(state);
+  queue_free(&todo);
+  for (i = 0; i < conflicts.count; i += 6)
+    {
+      if (conflicts.elements[i] != conflicts.elements[i + 3])
+        printf("%s - %s: %s[%s] %s[%s]\n", pool_id2str(pool, conflicts.elements[i]), pool_id2str(pool, conflicts.elements[i + 3]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_id2str(pool, conflicts.elements[i + 2]), pool_solvid2str(pool, conflicts.elements[i + 4]), pool_id2str(pool, conflicts.elements[i + 5]));
+      else
+        printf("%s: %s[%s] %s[%s]\n", pool_id2str(pool, conflicts.elements[i]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_id2str(pool, conflicts.elements[i + 2]), pool_solvid2str(pool, conflicts.elements[i + 4]), pool_id2str(pool, conflicts.elements[i + 5]));
+    }
+  if (conflicts.count)
+    {
+      Queue job;
+      int problemcnt;
+
+      queue_init(&job);
+      pool_add_fileconflicts_deps(pool, &conflicts);
+      pool_addfileprovides(pool);
+      pool_createwhatprovides(pool);
+      pool_setdebuglevel(pool, 0);
+      Solver *solv = solver_create(pool);
+      queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0);
+#if 0
+      solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
+#endif
+      problemcnt = solver_solve(solv, &job);
+      if (problemcnt)
+        solver_printallsolutions(solv);
+      else
+       {
+         Transaction *trans = solver_create_transaction(solv);
+          transaction_print(trans);
+          transaction_free(trans);
+       }
+      queue_free(&job);
+      solver_free(solv);
+    }
+  queue_free(&conflicts);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/helix2solv.c b/libsolv-0.7.2/tools/helix2solv.c
new file mode 100644 (file)
index 0000000..8ab531e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * helix2solv.c
+ * 
+ * parse 'helix' type xml and write out .solv file
+ *
+ * reads from stdin
+ * writes to stdout
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo_helix.h"
+#include "common_write.h"
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+  if (repo_add_helix(repo, stdin, 0))
+    {
+      fprintf(stderr, "helix2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/installcheck.c b/libsolv-0.7.2/tools/installcheck.c
new file mode 100644 (file)
index 0000000..6c090d8
--- /dev/null
@@ -0,0 +1,447 @@
+/* vim: sw=2 et cino=>4,n-2,{1s
+ */
+
+/*
+ * Copyright (c) 2009-2015, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pool.h"
+#include "poolarch.h"
+#include "repo_solv.h"
+#ifdef ENABLE_SUSEREPO
+#include "repo_susetags.h"
+#endif
+#ifdef ENABLE_RPMMD
+#include "repo_rpmmd.h"
+#endif
+#ifdef ENABLE_DEBIAN
+#include "repo_deb.h"
+#endif
+#ifdef ENABLE_ARCHREPO
+#include "repo_arch.h"
+#endif
+#include "solver.h"
+#include "solv_xfopen.h"
+
+
+void
+usage(char** argv)
+{
+  printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
+         "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
+         "packagenames to ignore\n"
+         "\t--withobsoletes\t\tCheck for obsoletes on packages contained in repos\n"
+         "\t--nocheck\t\tDo not warn about all following repos (only use them to fulfill dependencies)\n"
+         "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
+         , argv[0]);
+  exit(1);
+}
+
+#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
+static int
+strlen_comp(const char *str)
+{
+  size_t l = strlen(str);
+  if (l > 3 && !strcmp(str + l - 3, ".gz"))
+    return l - 3;
+  if (l > 3 && !strcmp(str + l - 3, ".xz"))
+    return l - 3;
+  if (l > 4 && !strcmp(str + l - 4, ".bz2"))
+    return l - 4;
+  if (l > 5 && !strcmp(str + l - 4, ".lzma"))
+    return l - 5;
+  return l;
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Solver *solv;
+  Repo *repo;
+  Queue job;
+  Queue rids;
+  Queue cand;
+  char *arch, *exclude_pat;
+  int i, j;
+  Id p;
+  Id archid, noarchid;
+  Id rpmrel;
+#ifndef DEBIAN
+  Id rpmid;
+#endif
+  int status = 0;
+  int nocheck = 0;
+  int withsrc = 0;
+  int obsoletepkgcheck = 0;
+
+  exclude_pat = 0;
+  if (argc < 3)
+    usage(argv);
+
+  arch = argv[1];
+  pool = pool_create();
+  pool_setarch(pool, arch);
+  noarchid = pool->solvables[SYSTEMSOLVABLE].arch;
+  for (i = 2; i < argc; i++)
+    {
+      FILE *fp;
+      int r;
+#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
+      int l;
+#endif
+
+      if (!strcmp(argv[i], "--withsrc"))
+       {
+         withsrc++;
+         continue;
+       }
+      if (!strcmp(argv[i], "--withobsoletes"))
+        {
+          obsoletepkgcheck++;
+          continue;
+        }
+      if (!strcmp(argv[i], "--nocheck"))
+       {
+         if (!nocheck)
+           nocheck = pool->nsolvables;
+         continue;
+       }
+      if (!strcmp(argv[i], "--exclude"))
+        {
+          if (i + 1 >= argc)
+            {
+              printf("--exclude needs a whitespace separated list of substrings as parameter\n");
+              exit(1);
+            }
+          exclude_pat = argv[i + 1];
+          ++i;
+          continue;
+        }
+#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_DEBIAN) || defined(ENABLE_ARCHREPO)
+      l = strlen_comp(argv[i]);
+#endif
+      if (!strcmp(argv[i], "-"))
+       fp = stdin;
+      else if ((fp = solv_xfopen(argv[i], 0)) == 0)
+       {
+         perror(argv[i]);
+         exit(1);
+       }
+      repo = repo_create(pool, argv[i]);
+      r = 0;
+      if (0)
+        {
+        }
+#ifdef ENABLE_SUSEREPO
+      else if (l >= 8 && !strncmp(argv[i] + l - 8, "packages", 8))
+       {
+         r = repo_add_susetags(repo, fp, 0, 0, 0);
+       }
+#endif
+#ifdef ENABLE_RPMMD
+      else if (l >= 11 && !strncmp(argv[i] + l - 11, "primary.xml", 11))
+       {
+         r = repo_add_rpmmd(repo, fp, 0, 0);
+          if (!r && i + 1 < argc)
+            {
+              l = strlen_comp(argv[i + 1]);
+              if (l >= 13 && !strncmp(argv[i + 1] + l - 13, "filelists.xml", 13))
+                {
+                  i++;
+                  fclose(fp);
+                  if ((fp = solv_xfopen(argv[i], 0)) == 0)
+                    {
+                      perror(argv[i]);
+                      exit(1);
+                    }
+                  r = repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL);
+                }
+            }
+       }
+#endif
+#ifdef ENABLE_DEBIAN
+      else if (l >= 8 && !strncmp(argv[i] + l - 8, "Packages", 8))
+       {
+         r = repo_add_debpackages(repo, fp, 0);
+       }
+#endif
+#ifdef ENABLE_ARCHREPO
+      else if (l >= 7 && (!strncmp(argv[i] + l - 7, ".db.tar", 7)))
+        {
+         r = repo_add_arch_repo(repo, fp, 0);
+        }
+#endif
+      else
+       r = repo_add_solv(repo, fp, 0);
+      if (r)
+       {
+         fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool));
+         exit(1);
+       }
+      if (fp != stdin)
+        fclose(fp);
+    }
+  pool_addfileprovides(pool);
+  pool_createwhatprovides(pool);
+  archid = pool_str2id(pool, arch, 0);
+#ifndef DEBIAN
+  rpmid = pool_str2id(pool, "rpm", 0);
+  rpmrel = 0;
+  if (rpmid && archid)
+    {
+      for (p = 1; p < pool->nsolvables; p++)
+       {
+         Solvable *s = pool->solvables + p;
+         if (s->name == rpmid && s->arch == archid && pool_installable(pool, s))
+           break;
+       }
+      if (p < pool->nsolvables)
+        rpmrel = pool_rel2id(pool, rpmid, archid, REL_ARCH, 1);
+    }
+#else
+  rpmrel = 0;
+#endif
+  
+  queue_init(&job);
+  queue_init(&rids);
+  queue_init(&cand);
+  for (p = 1; p < (nocheck ? nocheck : pool->nsolvables); p++)
+    {
+      Solvable *s = pool->solvables + p;
+      if (!s->repo)
+       continue;
+      if (withsrc && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
+       {
+         queue_push(&cand, p);
+         continue;
+       }
+      if (!pool_installable(pool, s))
+       continue;
+      if (archid && s->arch != archid && s->arch != noarchid)
+       {
+         /* check if we will conflict with a infarch rule, if yes,
+          * don't bother checking the package */
+         Id rp, rpp;
+         FOR_PROVIDES(rp, rpp, s->name)
+           {
+             if (pool->solvables[rp].name != s->name)
+               continue;
+             if (pool->solvables[rp].arch == archid)
+               break;
+           }
+         if (rp)
+           continue;
+       }
+      queue_push(&cand, p);
+    }
+  if (obsoletepkgcheck)
+    {
+      int obsoleteusesprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
+      int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
+
+      for (i = 0; i < cand.count; i++)
+       {
+         Solvable *s;
+         s = pool->solvables + cand.elements[i];
+
+         if (s->obsoletes)
+           {
+             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+
+             while ((obs = *obsp++) != 0)
+               {
+                 Id op, opp;
+                 FOR_PROVIDES(op, opp, obs)
+                   {
+                     Solvable *os = pool->solvables + op;
+                     if (nocheck && op >= nocheck)
+                       continue;
+                     if (solvable_identical(s, os))
+                       continue;
+                     if (!obsoleteusesprovides && !pool_match_nevr(pool, os, obs))
+                       continue;
+                     if (obsoleteusescolors && !pool_colormatch(pool, s, os))
+                       continue;
+                     status = 2;
+                     printf("can't install %s:\n", pool_solvid2str(pool, op));
+                     printf("  package is obsoleted by %s\n", pool_solvable2str(pool, s));
+                   }
+               }
+           }
+       }
+    }
+
+  solv = solver_create(pool);
+
+  /* prune cand by doing weak installs */
+  while (cand.count)
+    {
+      queue_empty(&job);
+      for (i = 0; i < cand.count; i++)
+       {
+         p = cand.elements[i];
+         queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK, p);
+       }
+      if (rpmrel)
+       queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
+      solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
+      solver_solve(solv, &job);
+      /* prune... */
+      for (i = j = 0; i < cand.count; i++)
+       {
+         p = cand.elements[i];
+         if (solver_get_decisionlevel(solv, p) <= 0)
+           {
+             cand.elements[j++] = p;
+             continue;
+           }
+       }
+      cand.count = j;
+      if (i == j)
+       break;
+    }
+
+  /* now check every candidate */
+  for (i = 0; i < cand.count; i++)
+    {
+      Solvable *s;
+      int problemcount;
+
+      p = cand.elements[i];
+      if (exclude_pat)
+        {
+          char *ptr, *save = 0, *pattern;
+          int match = 0;
+          pattern = solv_strdup(exclude_pat);
+
+          for (ptr = strtok_r(pattern, " ", &save);
+              ptr;
+              ptr = strtok_r(NULL, " ", &save))
+            {
+              if (*ptr && strstr(pool_solvid2str(pool, p), ptr))
+                {
+                  match = 1;
+                  break;
+                }
+            }
+          solv_free(pattern);
+          if (match)
+            continue;
+        }
+      s = pool->solvables + p;
+      queue_empty(&job);
+      queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE, p);
+      if (rpmrel)
+       queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_NAME, rpmrel);
+      solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
+      problemcount = solver_solve(solv, &job);
+      if (problemcount)
+       {
+         Id problem = 0;
+         Solvable *s2;
+
+         status = 1;
+         printf("can't install %s:\n", pool_solvable2str(pool, s));
+         while ((problem = solver_next_problem(solv, problem)) != 0)
+           {
+             solver_findallproblemrules(solv, problem, &rids);
+             for (j = 0; j < rids.count; j++)
+               {
+                 Id probr = rids.elements[j];
+                 int k;
+                 Queue rinfo;
+                 queue_init(&rinfo);
+
+                 solver_allruleinfos(solv, probr, &rinfo);
+                 for (k = 0; k < rinfo.count; k += 4)
+                   {
+                     Id dep, source, target;
+                     source = rinfo.elements[k + 1];
+                     target = rinfo.elements[k + 2];
+                     dep = rinfo.elements[k + 3];
+                     switch (rinfo.elements[k])
+                       {
+                       case SOLVER_RULE_DISTUPGRADE:
+                         break;
+                       case SOLVER_RULE_INFARCH:
+                         s = pool_id2solvable(pool, source);
+                         printf("  %s has inferior architecture\n", pool_solvable2str(pool, s));
+                         break;
+                       case SOLVER_RULE_UPDATE:
+                         s = pool_id2solvable(pool, source);
+                         printf("  %s can not be updated\n", pool_solvable2str(pool, s));
+                         break;
+                       case SOLVER_RULE_JOB:
+                       case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
+                       case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
+                       case SOLVER_RULE_JOB_UNSUPPORTED:
+                         break;
+                       case SOLVER_RULE_RPM:
+                         printf("  some dependency problem\n");
+                         break;
+                       case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
+                         printf("  nothing provides requested %s\n", pool_dep2str(pool, dep));
+                         break;
+                       case SOLVER_RULE_RPM_NOT_INSTALLABLE:
+                         s = pool_id2solvable(pool, source);
+                         printf("  package %s is not installable\n", pool_solvable2str(pool, s));
+                         break;
+                       case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
+                         s = pool_id2solvable(pool, source);
+                         printf("  nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvable2str(pool, s));
+                         if (ISRELDEP(dep))
+                           {
+                             Reldep *rd = GETRELDEP(pool, dep);
+                             if (!ISRELDEP(rd->name))
+                               {
+                                 Id rp, rpp;
+                                 FOR_PROVIDES(rp, rpp, rd->name)
+                                   printf("    (we have %s)\n", pool_solvable2str(pool, pool->solvables + rp));
+                               }
+                           }
+                         break;
+                       case SOLVER_RULE_RPM_SAME_NAME:
+                         s = pool_id2solvable(pool, source);
+                         s2 = pool_id2solvable(pool, target);
+                         printf("  cannot install both %s and %s\n", pool_solvable2str(pool, s), pool_solvable2str(pool, s2));
+                         break;
+                       case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
+                         s = pool_id2solvable(pool, source);
+                         s2 = pool_id2solvable(pool, target);
+                         printf("  package %s conflicts with %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
+                         break;
+                       case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
+                         s = pool_id2solvable(pool, source);
+                         s2 = pool_id2solvable(pool, target);
+                         printf("  package %s obsoletes %s provided by %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep), pool_solvable2str(pool, s2));
+                         break;
+                       case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
+                         s = pool_id2solvable(pool, source);
+                         printf("  package %s requires %s, but none of the providers can be installed\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
+                         break;
+                       case SOLVER_RULE_RPM_SELF_CONFLICT:
+                         s = pool_id2solvable(pool, source);
+                         printf("  package %s conflicts with %s provided by itself\n", pool_solvable2str(pool, s), pool_dep2str(pool, dep));
+                         break;
+                       }
+                   }
+               }
+           }
+       }
+    }
+  solver_free(solv);
+  exit(status);
+}
diff --git a/libsolv-0.7.2/tools/mdk2solv.c b/libsolv-0.7.2/tools/mdk2solv.c
new file mode 100644 (file)
index 0000000..3a6cf94
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012, Novell Inc.);
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * mdk2solv.c
+ *
+ * parse Mandriva/Mageie synthesis file
+ *
+ * reads from stdin
+ * writes to stdout
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_mdk.h"
+#include "solv_xfopen.h"
+#include "common_write.h"
+
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "mdk2solv [-i <infoxml>]\n"
+          "  reads a 'synthesis' repository from <stdin> and writes a .solv file to <stdout>\n"
+          "  -i : info.xml file for extra attributes\n"
+          "  -f : files.xml file for extra attributes\n"
+          "  -h : print help & exit\n"
+         );
+   exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Repo *repo;
+  char *infofile = 0, *filesfile = 0;
+  int c;
+
+  while ((c = getopt(argc, argv, "hi:f:")) >= 0)
+    {
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       case 'i':
+         infofile = optarg;
+         break;
+       case 'f':
+         filesfile = optarg;
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  pool = pool_create();
+  repo = repo_create(pool, "<stdin>");
+  if (repo_add_mdk(repo, stdin, REPO_NO_INTERNALIZE))
+    {
+      fprintf(stderr, "mdk2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  if (infofile)
+    {
+      FILE *fp = solv_xfopen(infofile, "r");
+      if (!fp)
+       {
+         perror(infofile);
+         exit(1);
+       }
+      if (repo_add_mdk_info(repo, fp, REPO_EXTEND_SOLVABLES | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+       {
+         fprintf(stderr, "mdk2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+    }
+  if (filesfile)
+    {
+      FILE *fp = solv_xfopen(filesfile, "r");
+      if (!fp)
+       {
+         perror(filesfile);
+         exit(1);
+       }
+      if (repo_add_mdk_info(repo, fp, REPO_EXTEND_SOLVABLES | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+       {
+         fprintf(stderr, "mdk2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+    }
+  repo_internalize(repo);
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/mergesolv.c b/libsolv-0.7.2/tools/mergesolv.c
new file mode 100644 (file)
index 0000000..8746ac6
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * mergesolv
+ * 
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pool.h"
+#include "repo_solv.h"
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#include "common_write.h"
+
+static void
+usage()
+{
+  fprintf(stderr, "\nUsage:\n"
+         "mergesolv [file] [file] [...]\n"
+         "  merges multiple solv files into one and writes it to stdout\n"
+         );
+  exit(0);
+}
+
+static int
+loadcallback (Pool *pool, Repodata *data, void *vdata)
+{
+  FILE *fp;
+  const char *location = repodata_lookup_str(data, SOLVID_META, REPOSITORY_LOCATION);
+  int r;
+
+  if (!location)
+    return 0;
+  fprintf(stderr, "Loading SOLV file %s\n", location);
+  fp = fopen (location, "r");
+  if (!fp)
+    {
+      perror(location);
+      return 0;
+    }
+  r = repo_add_solv(data->repo, fp, REPO_USE_LOADING|REPO_LOCALPOOL);
+  fclose(fp);
+  return r ? 0 : 1;
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Repo *repo;
+  int with_attr = 0;
+#ifdef SUSE
+  int add_auto = 0;
+#endif
+  int c;
+
+  pool = pool_create();
+  repo = repo_create(pool, "<mergesolv>");
+  
+  while ((c = getopt(argc, argv, "ahX")) >= 0)
+    {
+      switch (c)
+      {
+       case 'h':
+         usage();
+         break;
+       case 'a':
+         with_attr = 1;
+         break;
+       case 'X':
+#ifdef SUSE
+         add_auto = 1;
+#endif
+         break;
+       default:
+         usage();
+         exit(1);
+      }
+    }
+  if (with_attr)
+    pool_setloadcallback(pool, loadcallback, 0);
+
+  for (; optind < argc; optind++)
+    {
+      FILE *fp;
+      if ((fp = fopen(argv[optind], "r")) == NULL)
+       {
+         perror(argv[optind]);
+         exit(1);
+       }
+      if (repo_add_solv(repo, fp, 0))
+       {
+         fprintf(stderr, "repo %s: %s\n", argv[optind], pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+    }
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, 0);
+#endif
+  tool_write(repo, stdout);
+  pool_free(pool);
+  return 0;
+}
diff --git a/libsolv-0.7.2/tools/repo2solv.c b/libsolv-0.7.2/tools/repo2solv.c
new file mode 100644 (file)
index 0000000..d5b3328
--- /dev/null
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+
+#ifdef ENABLE_RPMPKG
+#include "repo_rpmdb.h"
+#endif
+
+#ifdef ENABLE_RPMMD
+#include "repo_repomdxml.h"
+#include "repo_rpmmd.h"
+#include "repo_updateinfoxml.h"
+#include "repo_deltainfoxml.h"
+#endif
+
+#ifdef ENABLE_SUSEREPO
+#include "repo_content.h"
+#include "repo_susetags.h"
+#endif
+
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#ifdef ENABLE_APPDATA
+#include "repo_appdata.h"
+#endif
+#include "common_write.h"
+#include "solv_xfopen.h"
+
+
+#ifdef SUSE
+int add_auto = 0;
+#endif
+#ifdef ENABLE_APPDATA
+int add_appdata = 0;
+#endif
+int recursive = 0;
+int add_filelist = 0;
+int add_changelog = 0;
+int filtered_filelist = 0;
+
+
+#define REPO_PLAINDIR          1
+#define REPO_RPMMD             2
+#define REPO_RPMMD_REPODATA    3
+#define REPO_SUSETAGS          4
+
+int
+autodetect_repotype(Pool *pool, const char *dir)
+{
+  struct stat stb;
+  char *tmp;
+  FILE *fp;
+
+  tmp = pool_tmpjoin(pool, dir, "/repomd.xml", 0);
+  if (stat(tmp, &stb) == 0)
+    return REPO_RPMMD;
+  tmp = pool_tmpjoin(pool, dir, "/repodata/repomd.xml", 0);
+  if (stat(tmp, &stb) == 0)
+    return REPO_RPMMD_REPODATA;
+  tmp = pool_tmpjoin(pool, dir, "/content", 0);
+  if ((fp = fopen(tmp, "r")) != 0)
+    {
+      char buf[512], *descrdir = 0;
+      while (fgets(buf, sizeof(buf), fp))
+       {
+         int l = strlen(buf);
+         char *bp = buf;
+         if (buf[l - 1] != '\n')
+           {
+             int c;
+             while ((c = getc(fp)) != EOF && c != '\n')
+               ;
+             continue;
+           }
+         while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+           l--;
+         buf[l] = 0;
+         while (*bp == ' ' || *bp == '\t')
+           bp++;
+         if (strncmp(bp, "DESCRDIR", 8) != 0 || (bp[8] != ' ' && bp[8] != '\t'))
+           continue;
+         bp += 9;
+         while (*bp == ' ' || *bp == '\t')
+           bp++;
+         descrdir = bp;
+         break;
+       }
+      fclose(fp);
+      if (descrdir)
+       {
+         tmp = pool_tmpjoin(pool, dir, "/", descrdir);
+         if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
+           return REPO_SUSETAGS;
+       }
+    }
+  tmp = pool_tmpjoin(pool, dir, "/suse/setup/descr", 0);
+  if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
+    return REPO_SUSETAGS;
+  return REPO_PLAINDIR;
+}
+
+
+#ifdef ENABLE_RPMPKG
+
+int
+read_plaindir_repo(Repo *repo, const char *dir)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  int c;
+  FILE *fp;
+  int wstatus;
+  int fds[2];
+  pid_t pid;
+  char *buf = 0;
+  char *buf_end = 0;
+  char *bp = 0;
+  char *rpm;
+  int res = 0;
+  Id p;
+
+  /* run find command */
+  if (pipe(fds))
+    {
+      perror("pipe");
+      exit(1);
+    }
+  while ((pid = fork()) == (pid_t)-1)
+    {
+      if (errno != EAGAIN)
+       {
+         perror("fork");
+         exit(1);
+       }
+      sleep(3);
+    }
+  if (pid == 0)
+    {
+      if (chdir(dir))
+       {
+         perror(dir);
+         _exit(1);
+       }
+      close(fds[0]);
+      if (fds[1] != 1)
+       {
+         if (dup2(fds[1], 1) == -1)
+           {
+             perror("dup2");
+             _exit(1);
+           }
+         close(fds[1]);
+       }
+      if (recursive)
+       execl("/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
+      else
+       execl("/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
+      perror("/usr/bin/find");
+      _exit(1);
+    }
+  close(fds[1]);
+  if ((fp = fdopen(fds[0], "r")) == 0)
+    {
+      perror("fdopen");
+      exit(1);
+    }
+  data = repo_add_repodata(repo, 0);
+  bp = buf;
+  while ((c = getc(fp)) != EOF)
+    {
+      if (bp == buf_end)
+       {
+         size_t len = bp - buf;
+         buf = solv_realloc(buf, len + 4096);
+         bp = buf + len;
+         buf_end = bp + 4096;
+       }
+      *bp++ = c;
+      if (c)
+       continue;
+      bp = buf;
+      rpm = solv_dupjoin(dir, "/", bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
+      if ((p = repo_add_rpm(repo, rpm, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0))) == 0)
+       {
+         fprintf(stderr, "%s: %s\n", rpm, pool_errstr(pool));
+#if 0
+         res = 1;
+#endif
+       }
+      else
+       repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
+      solv_free(rpm);
+    }
+  fclose(fp);
+  while (waitpid(pid, &wstatus, 0) == -1)
+    {
+      if (errno == EINTR)
+       continue;
+      perror("waitpid");
+      exit(1);
+    }
+  if (wstatus)
+    {
+      fprintf(stderr, "find: exit status %d\n", (wstatus >> 8) | (wstatus & 255) << 8);
+#if 0
+      res = 1;
+#endif
+    }
+  repo_internalize(repo);
+  return res;
+}
+
+#else
+
+int
+read_plaindir_repo(Repo *repo, const char *dir)
+{
+  fprintf(stderr, "plaindir repo type is not supported\n");
+  exit(1);
+}
+
+#endif
+
+#ifdef ENABLE_SUSEREPO
+
+static const char *
+susetags_find(char **files, int nfiles, const char *what)
+{
+  int i;
+  size_t l = strlen(what);
+  for (i = 0; i < nfiles; i++)
+    {
+      char *fn = files[i];
+      if (strncmp(fn, what, l) != 0)
+       continue;
+      if (fn[l] == 0)
+       return fn;
+      if (fn[l] != '.')
+       continue;
+      if (strchr(fn + l + 1, '.') != 0)
+       continue;
+      if (solv_xfopen_iscompressed(fn) <= 0)
+       continue;
+      return fn;
+    }
+  return 0;
+}
+
+static FILE *
+susetags_open(const char *dir, const char *filename, char **tmpp, int missingok)
+{
+  FILE *fp;
+  if (!filename)
+    {
+      *tmpp = 0;
+      return 0;
+    }
+  *tmpp = solv_dupjoin(dir, "/", filename);
+  if ((fp = solv_xfopen(*tmpp, "r")) == 0)
+    {
+      if (!missingok)
+       {
+         perror(*tmpp);
+         exit(1);
+       }
+      *tmpp = solv_free(*tmpp);
+      return 0;
+    }
+  return fp;
+}
+
+static void
+susetags_extend(Repo *repo, const char *dir, char **files, int nfiles, char *what, Id defvendor, char *language, int missingok)
+{
+  const char *filename;
+  FILE *fp;
+  char *tmp;
+
+  filename = susetags_find(files, nfiles, what);
+  if (!filename)
+    return;
+  if ((fp = susetags_open(dir, filename, &tmp, missingok)) != 0)
+    {
+      if (repo_add_susetags(repo, fp, defvendor, language, REPO_EXTEND_SOLVABLES))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
+         exit(1);
+       }
+      fclose(fp);
+      solv_free(tmp);
+    }
+}
+
+static void
+susetags_extend_languages(Repo *repo, const char *dir, char **files, int nfiles, Id defvendor, int missingok)
+{
+  int i;
+  for (i = 0; i < nfiles; i++)
+    {
+      char *fn = files[i];
+      char lang[64], *p;
+      if (strncmp(fn, "packages.", 9) != 0)
+       continue;
+      if (strlen(fn + 9) + 1 >= sizeof(lang))
+       continue;
+      strncpy(lang, fn + 9, sizeof(lang) - 1);
+      lang[sizeof(lang) - 1] = 0;
+      p = strrchr(lang, '.');
+      if (p)
+       {
+          if (solv_xfopen_iscompressed(lang) <= 0)
+           continue;
+         *p = 0;
+       }
+      if (strchr(lang, '.'))
+       continue;
+      if (!strcmp(lang, "en"))
+       continue;       /* already did that one */
+      if (!strcmp(lang, "DU"))
+       continue;       /* disk usage */
+      if (!strcmp(lang, "FL"))
+       continue;       /* file list */
+      if (!strcmp(lang, "DL"))
+       continue;       /* deltas */
+      susetags_extend(repo, dir, files, nfiles, fn, defvendor, lang, missingok);
+    }
+}
+
+static int
+susetags_dircmp(const void *ap, const void *bp, void *dp)
+{
+  return strcmp(*(const char **)ap, *(const char **)bp);
+}
+
+int
+read_susetags_repo(Repo *repo, const char *dir)
+{
+  Pool *pool = repo->pool;
+  const char *filename;
+  char *ddir;
+  char *tmp;
+  FILE *fp;
+  Id defvendor = 0;
+  const char *descrdir = 0;
+  char **files = 0;
+  int nfiles = 0;
+  DIR *dp;
+  struct dirent *de;
+
+  /* read content file */
+  repo_add_repodata(repo, 0);
+  tmp = solv_dupjoin(dir, "/content", 0);
+  if ((fp = fopen(tmp, "r")) != 0)
+    {
+      if (repo_add_content(repo, fp, REPO_REUSE_REPODATA))
+        {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+        }
+      fclose(fp);
+      descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
+      defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+    }
+  if (!descrdir)
+    descrdir = "suse/setup/descr";
+  tmp = solv_free(tmp);
+
+  /* get content of descrdir directory */
+  ddir = solv_dupjoin(dir, "/", descrdir);
+  if ((dp = opendir(ddir)) == 0)
+    {
+      perror(ddir);
+      exit(1);
+    }
+  while ((de = readdir(dp)) != 0)
+    {
+      if (de->d_name[0] == 0 || de->d_name[0] == '.')
+       continue;
+      files = solv_extend(files, nfiles, 1, sizeof(char *), 63);
+      files[nfiles++] = solv_strdup(de->d_name);
+    }
+  closedir(dp);
+  if (nfiles > 1)
+    solv_sort(files, nfiles, sizeof(char *), susetags_dircmp, 0);
+  
+  /* add packages */
+  filename = susetags_find(files, nfiles, "packages");
+  if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_susetags(repo, fp, defvendor, 0, SUSETAGS_RECORD_SHARES))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+
+      /* now extend the packages */
+      susetags_extend(repo, ddir, files, nfiles, "packages.DU", defvendor, 0, 1);
+      susetags_extend(repo, ddir, files, nfiles, "packages.en", defvendor, 0, 1);
+      susetags_extend_languages(repo, ddir, files, nfiles, defvendor, 1);
+      if (add_filelist)
+        susetags_extend(repo, ddir, files, nfiles, "packages.FL", defvendor, 0, 1);
+    }
+
+  /* add deltas */
+  filename = susetags_find(files, nfiles, "packages.DL");
+  if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_susetags(repo, fp, defvendor, 0, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+
+  /* add legacy patterns */
+  tmp = solv_dupjoin(ddir, "/patterns", 0);
+  if ((fp = fopen(tmp, "r")) != 0)
+    {
+      char pbuf[4096];
+
+      repo_add_repodata(repo, 0);
+      while (fgets(pbuf, sizeof(pbuf), fp))
+       {
+         char *p;
+         FILE *pfp;
+         if (strchr(pbuf, '/') != 0)
+           continue;
+         if ((p = strchr(pbuf, '\n')) != 0)
+           *p = 0;
+         if (*pbuf == 0)
+           continue;
+         solv_free(tmp);
+         tmp = solv_dupjoin(ddir, "/", pbuf);
+         if ((pfp = solv_xfopen(tmp, "r")) != 0)
+           {
+             if (repo_add_susetags(repo, pfp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA))
+               {
+                 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+                 exit(1);
+               }
+             fclose(pfp);
+           }
+       }
+      fclose(fp);
+    }
+  tmp = solv_free(tmp);
+#ifdef ENABLE_APPDATA
+  /* appdata */
+  filename = add_appdata ? susetags_find(files, nfiles, "appdata.xml") : 0;
+  if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_appdata(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+#endif
+
+  while (nfiles > 0)
+    solv_free(files[--nfiles]);
+  solv_free(files);
+  solv_free(ddir);
+  repo_internalize(repo);
+  return 0;
+}
+
+#else
+
+int
+read_susetags_repo(Repo *repo, const char *dir)
+{
+  fprintf(stderr, "susetags repo type is not supported\n");
+  exit(1);
+}
+
+#endif
+
+
+#ifdef ENABLE_RPMMD
+
+static const char *
+repomd_find(Repo *repo, const char *what)
+{
+  Pool *pool = repo->pool;
+  Dataiterator di;
+  const char *filename;
+
+  filename = 0;
+  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING);
+  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
+  if (dataiterator_step(&di))
+    {
+      dataiterator_setpos_parent(&di);
+      filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
+    }
+  dataiterator_free(&di);
+  if (filename && strncmp(filename, "repodata/", 9) == 0)
+    filename += 9;
+  return filename;
+}
+
+static FILE *
+repomd_open(const char *dir, const char *filename, char **tmpp, int missingok)
+{
+  FILE *fp;
+  if (!filename)
+    {
+      *tmpp = 0;
+      return 0;
+    }
+  *tmpp = solv_dupjoin(dir, "/", filename);
+  if ((fp = solv_xfopen(*tmpp, "r")) == 0)
+    {
+      if (!missingok)
+       {
+         perror(*tmpp);
+         exit(1);
+       }
+      *tmpp = solv_free(*tmpp);
+      return 0;
+    }
+  return fp;
+}
+
+static void
+repomd_extend(Repo *repo, const char *dir, const char *what, const char *language, int missingok)
+{
+  const char *filename;
+  FILE *fp;
+  char *tmp;
+
+  filename = repomd_find(repo, what);
+  if (!filename)
+    return;
+  fp = repomd_open(dir, filename, &tmp, missingok);
+  if (fp)
+    {
+      if (repo_add_rpmmd(repo, fp, language, REPO_EXTEND_SOLVABLES))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
+         exit(1);
+       }
+      fclose(fp);
+    }
+  solv_free(tmp);
+}
+
+static void
+repomd_extend_languages(Repo *repo, const char *dir, int missingok)
+{
+  char **susedatas = 0;
+  int nsusedatas = 0, i;
+  Dataiterator di;
+  dataiterator_init(&di, repo->pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, "susedata.", SEARCH_STRINGSTART);
+  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
+  while (dataiterator_step(&di))
+    {
+      susedatas = solv_extend(susedatas, nsusedatas, 1, sizeof(char *), 15);
+      susedatas[nsusedatas++] = solv_strdup(di.kv.str);
+    }
+  dataiterator_free(&di);
+  for (i = 0; i < nsusedatas; i++)
+    {
+      repomd_extend(repo, dir, susedatas[i], susedatas[i] + 9, missingok);
+      susedatas[i] = solv_free(susedatas[i]);
+    }
+  solv_free(susedatas);
+}
+
+static void
+add_rpmmd_file(Repo *repo, const char *dir, const char *filename, int missingok)
+{
+  FILE *fp;
+  char *tmp;
+
+  fp = repomd_open(dir, filename, &tmp, missingok);
+  if (!fp)
+    return;
+  if (repo_add_rpmmd(repo, fp, 0, 0))
+    {
+      fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
+      exit(1);
+    }
+  fclose(fp);
+  solv_free(tmp);
+}
+
+int
+read_rpmmd_repo(Repo *repo, const char *dir)
+{
+  Pool *pool = repo->pool;
+  FILE *fp;
+  char *tmp = 0;
+  const char *filename;
+
+  /* add repomd.xml and suseinfo.xml */
+  fp = repomd_open(dir, "repomd.xml", &tmp, 0);
+  if (repo_add_repomdxml(repo, fp, 0))
+    {
+      fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+      exit(1);
+    }
+  fclose(fp);
+  tmp = solv_free(tmp);
+  filename = repomd_find(repo, "suseinfo");
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
+    {
+      if (repo_add_repomdxml(repo, fp, REPO_REUSE_REPODATA))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+  
+  /* first all primary packages */
+  filename = repomd_find(repo, "primary");
+  if (filename)
+    {
+      add_rpmmd_file(repo, dir, filename, 0);
+      repomd_extend(repo, dir, "susedata", 0, 1);
+      repomd_extend_languages(repo, dir, 1);
+      if (add_filelist)
+        repomd_extend(repo, dir, "filelists", 0, 1);
+      if (add_changelog)
+        repomd_extend(repo, dir, "other", 0, 1);
+    }
+
+  /* some legacy stuff */
+  filename = repomd_find(repo, "products");
+  if (!filename)
+    filename = repomd_find(repo, "product");
+  if (filename)
+    add_rpmmd_file(repo, dir, filename, 1);
+  filename = repomd_find(repo, "patterns");
+    add_rpmmd_file(repo, dir, filename, 1);
+  
+  /* updateinfo */
+  filename = repomd_find(repo, "updateinfo");
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
+    {
+      if (repo_add_updateinfoxml(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+
+  /* deltainfo */
+  filename = repomd_find(repo, "deltainfo");
+  if (!filename)
+    filename = repomd_find(repo, "prestodelta");
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_deltainfoxml(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+
+#ifdef ENABLE_APPDATA
+  /* appdata */
+  filename = add_appdata ? repomd_find(repo, "appdata") : 0;
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_appdata(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+#endif
+
+  repo_internalize(repo);
+  return 0;
+}
+
+#else
+
+int
+read_rpmmd_repo(Repo *repo, const char *dir)
+{
+  fprintf(stderr, "rpmmd repo type is not supported\n");
+  exit(1);
+}
+
+#endif
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "repo2solv [-R] [-X] [-A] [-o <out.solv>] <dir>\n"
+         "  Convert a repository in <dir> to a solv file\n"
+         "  -h : print help & exit\n"
+         "  -o <out.solv>: write to this file instead of stdout\n"
+         "  -F : add filelist\n"
+         "  -R : also search subdirectories for rpms\n"
+         "  -X : generate pattern/product pseudo packages\n"
+         "  -A : add appdata packages\n"
+        );
+   exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, res;
+  int repotype = 0;
+  char *outfile = 0;
+  char *dir;
+  struct stat stb;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<repo>");
+
+  while ((c = getopt(argc, argv, "hAXRFCo:")) >= 0)
+    {
+      switch(c)
+       {
+        case 'h':
+          usage(0);
+          break;
+       case 'X':
+#ifdef SUSE
+         add_auto = 1;
+#endif
+         break;
+       case 'A':
+#ifdef ENABLE_APPDATA
+         add_appdata = 1;
+#endif
+         break;
+       case 'R':
+         repotype = REPO_PLAINDIR;
+         recursive = 1;
+         break;
+       case 'F':
+         add_filelist = 1;
+         break;
+       case 'C':
+         add_changelog = 1;
+         break;
+       case 'o':
+         outfile = optarg;
+         break;
+        default:
+          usage(1);
+          break;
+       }
+    }
+  if (optind + 1 != argc)
+    usage(1);
+  dir = argv[optind];
+  if (stat(dir, &stb))
+    {
+      perror(dir);
+      exit(1);
+    }
+  if (!S_ISDIR(stb.st_mode))
+    {
+      fprintf(stderr, "%s: not a directory\n", dir);
+      exit(1);
+    }
+  dir = solv_strdup(dir);
+  if (repotype == 0)
+    repotype = autodetect_repotype(pool, dir);
+
+  switch (repotype)
+    {
+    case REPO_RPMMD:
+      res = read_rpmmd_repo(repo, dir);
+      break;
+    case REPO_RPMMD_REPODATA:
+      dir = solv_dupappend(dir, "/repodata", 0);
+      res = read_rpmmd_repo(repo, dir);
+      break;
+    case REPO_SUSETAGS:
+      res = read_susetags_repo(repo, dir);
+      break;
+    case REPO_PLAINDIR:
+      res = read_plaindir_repo(repo, dir);
+      break;
+    default:
+      fprintf(stderr, "unknown repotype %d\n", repotype);
+      exit(1);
+    }
+  if (outfile && freopen(outfile, "w", stdout) == 0)
+    {
+      perror(outfile);
+      exit(1);
+    }
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, 0);
+#endif
+  tool_write(repo, stdout);
+  pool_free(pool);
+  solv_free(dir);
+  exit(res);
+}
diff --git a/libsolv-0.7.2/tools/repomdxml2solv.c b/libsolv-0.7.2/tools/repomdxml2solv.c
new file mode 100644 (file)
index 0000000..fdf7666
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007-2009, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "chksum.h"
+#include "repo_repomdxml.h"
+#include "common_write.h"
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "repomdxml2solv [-q query]\n"
+         "  reads a 'repomd.xml' file from <stdin> and writes a .solv file to <stdout>\n"
+         "  -q : query a repomd data entry\n"
+         "  -h : print help & exit\n"
+        );
+   exit(status);
+}
+
+static void
+doquery(Pool *pool, Repo *repo, const char *query)
+{
+  Id id, type = 0;
+  char qbuf[256];
+  const char *qp;
+  Dataiterator di;
+
+  qp = strchr(query, ':');
+  if (qp)
+    {
+      type = pool_strn2id(pool, query, qp - query, 0);
+      if (!type)
+       exit(0);
+      qp++;
+    }
+  else
+    qp = query;
+  snprintf(qbuf, sizeof(qbuf), "repository:repomd:%s", qp);
+  id = pool_str2id(pool, qbuf, 0);
+  if (!id)
+    exit(0);
+  dataiterator_init(&di, pool, repo, SOLVID_META, id, 0, 0);
+  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
+  while (dataiterator_step(&di))
+    {
+      if (type)
+       {
+         dataiterator_setpos_parent(&di);
+         if (pool_lookup_id(pool, SOLVID_POS, REPOSITORY_REPOMD_TYPE) != type)
+           continue;
+       }
+      switch (di.key->type)
+       {
+       case REPOKEY_TYPE_ID:
+       case REPOKEY_TYPE_CONSTANTID:
+         printf("%s\n", pool_id2str(pool, di.kv.id));
+         break;
+       case REPOKEY_TYPE_STR:
+         printf("%s\n", di.kv.str);
+         break;
+       case REPOKEY_TYPE_NUM:
+       case REPOKEY_TYPE_CONSTANT:
+         printf("%llu\n", SOLV_KV_NUM64(&di.kv));
+         break;
+       default:
+         if (solv_chksum_len(di.key->type))
+           printf("%s:%s\n", solv_chksum_type2str(di.key->type), repodata_chk2str(di.data, di.key->type, (unsigned char *)di.kv.str));
+         break;
+       }
+    }
+  dataiterator_free(&di);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, flags = 0;
+  const char *query = 0;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+
+  while ((c = getopt (argc, argv, "hq:")) >= 0)
+    {
+      switch(c)
+        {
+        case 'h':
+          usage(0);
+          break;
+        case 'q':
+         query = optarg;
+          break;
+       default:
+          usage(1);
+          break;
+        }
+    }
+  if (repo_add_repomdxml(repo, stdin, flags))
+    {
+      fprintf(stderr, "repomdxml2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  if (query)
+    doquery(pool, repo, query);
+  else
+    tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/rpmdb2solv.c b/libsolv-0.7.2/tools/rpmdb2solv.c
new file mode 100644 (file)
index 0000000..58ef567
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * rpmdb2solv
+ * 
+ * Reads rpm database (and evtl. more, like product metadata) to build
+ * a .solv file of 'installed' solvables.
+ * Writes .solv to stdout
+ * 
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_rpmdb.h"
+#ifdef ENABLE_PUBKEY
+#include "repo_pubkey.h"
+#endif
+#include "repo_products.h"
+#include "repo_solv.h"
+#include "common_write.h"
+#ifdef ENABLE_APPDATA
+#include "repo_appdata.h"
+#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+         "rpmdb2solv [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
+         " -n : No packages, do not read rpmdb, useful to only parse products\n"
+         " -p <productsdir> : Scan <productsdir> for .prod files, representing installed products\n"
+         " -r <root> : Prefix rpmdb path and <productsdir> with <root>\n"
+         " -o <solv> : Write .solv to file instead of stdout\n"
+        );
+  exit(status);
+}
+
+
+int
+main(int argc, char **argv)
+{
+  FILE *reffp = 0;
+  Pool *pool = pool_create();
+  Repo *repo;
+  Repodata *data;
+  int c, percent = 0;
+  int nopacks = 0;
+  int add_changelog = 0;
+  const char *root = 0;
+  const char *refname = 0;
+#ifdef ENABLE_SUSEREPO
+  char *proddir = 0;
+#endif
+  char *outfile = 0;
+#ifdef ENABLE_PUBKEY
+  int pubkeys = 0;
+#endif
+#ifdef ENABLE_APPDATA
+  int add_appdata = 0;
+#endif
+#ifdef SUSE
+  int add_auto = 0;
+#endif
+
+  /*
+   * parse arguments
+   */
+  
+  while ((c = getopt(argc, argv, "ACPhnkxXr:p:o:")) >= 0)
+    switch (c)
+      {
+      case 'h':
+         usage(0);
+       break;
+      case 'r':
+        root = optarg;
+        break;
+      case 'n':
+       nopacks = 1;
+       break;
+      case 'P':
+       percent = 1;
+       break;
+      case 'p':
+#ifdef ENABLE_SUSEREPO
+       proddir = optarg;
+#endif
+       break;
+      case 'x':
+        break; /* extrapool no longer supported */
+      case 'X':
+#ifdef SUSE
+       add_auto = 1;
+#endif
+       break;
+      case 'A':
+#ifdef ENABLE_APPDATA
+       add_appdata = 1;
+#endif
+       break;
+      case 'o':
+        outfile = optarg;
+        break;
+#ifdef ENABLE_PUBKEY
+      case 'k':
+        nopacks = 1;
+        pubkeys = 1;
+        break;
+#endif
+      case 'C':
+       add_changelog = 1;
+       break;
+      default:
+       usage(1);
+      }
+  
+  if (outfile && !freopen(outfile, "w", stdout))
+    {
+      perror(outfile);
+      exit(1);
+    }
+    
+  /*
+   * optional arg is old version of rpmdb solv file
+   * should make this a real option instead
+   */
+  
+  if (optind < argc)
+    refname = argv[optind];
+
+  if (refname && !nopacks)
+    {
+      if ((reffp = fopen(refname, "r")) == NULL)
+        perror(refname);
+    }
+
+  /*
+   * create 'installed' repository
+   * add products
+   * add rpmdb
+   * write .solv
+   */
+
+  if (root && *root)
+    pool_set_rootdir(pool, root);
+
+  repo = repo_create(pool, "installed");
+  data = repo_add_repodata(repo, 0);
+
+  if (!nopacks)
+    {
+      int flags = REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE;
+      if (percent)
+       flags |= RPMDB_REPORT_PROGRESS;
+      if (add_changelog)
+       flags |= RPM_ADD_WITH_CHANGELOG;
+      if (repo_add_rpmdb_reffp(repo, reffp, flags))
+       {
+         fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+#ifdef ENABLE_PUBKEY
+  if (pubkeys)
+    {
+      if (repo_add_rpmdb_pubkeys(repo, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | ADD_WITH_KEYSIGNATURES))
+       {
+         fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+#endif
+
+#ifdef ENABLE_SUSEREPO
+  if (proddir && *proddir)
+    {
+      if (root && *root)
+       {
+         int rootlen = strlen(root);
+         if (!strncmp(root, proddir, rootlen))
+           {
+             proddir += rootlen;
+             if (*proddir != '/' && proddir[-1] == '/')
+               proddir--;
+           }
+       }
+      if (repo_add_products(repo, proddir, REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+       {
+         fprintf(stderr, "rpmdb2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+#endif
+
+#ifdef ENABLE_APPDATA
+  if (add_appdata)
+    {
+      repo_add_appdata_dir(repo, "/usr/share/metainfo", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
+      repo_add_appdata_dir(repo, "/usr/share/appdata", REPO_USE_ROOTDIR | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | APPDATA_SEARCH_UNINTERNALIZED_FILELIST);
+    }
+#endif
+  repodata_internalize(data);
+
+  if (reffp)
+    fclose(reffp);
+
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, ADD_NO_AUTOPRODUCTS);
+#endif
+
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/rpmmd2solv.c b/libsolv-0.7.2/tools/rpmmd2solv.c
new file mode 100644 (file)
index 0000000..ad75025
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_rpmmd.h"
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#include "common_write.h"
+#include "solv_xfopen.h"
+
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "rpmmd2solv [-h]\n"
+         "  reads 'primary' from a 'rpmmd' repository from <stdin> and writes a .solv file to <stdout>\n"
+         "  -h : print help & exit\n"
+        );
+   exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c;
+#ifdef SUSE
+  int add_auto = 0;
+#endif
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+
+  while ((c = getopt (argc, argv, "hX")) >= 0)
+    {
+      switch (c)
+       {
+        case 'h':
+          usage(0);
+          break;
+       case 'X':
+#ifdef SUSE
+         add_auto = 1;
+#endif
+         break;
+        default:
+          usage(1);
+          break;
+       }
+    }
+  if (repo_add_rpmmd(repo, stdin, 0, 0))
+    {
+      fprintf(stderr, "rpmmd2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, 0);
+#endif
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/rpms2solv.c b/libsolv-0.7.2/tools/rpms2solv.c
new file mode 100644 (file)
index 0000000..c012b46
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * rpms2solv - create a solv file from multiple rpms
+ * 
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "util.h"
+#include "pool.h"
+#include "repo.h"
+#include "repo_rpmdb.h"
+#ifdef ENABLE_PUBKEY
+#include "repo_pubkey.h"
+#include "solv_xfopen.h"
+#endif
+#include "repo_solv.h"
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#include "common_write.h"
+
+static char *
+fgets0(char *s, int size, FILE *stream)
+{
+  char *p = s;
+  int c;
+
+  while (--size > 0)
+    {
+      c = getc(stream);
+      if (c == EOF)
+       {
+         if (p == s)
+           return 0;
+         c = 0;
+       }
+      *p++ = c;
+      if (!c)
+       return s;
+    }
+  *p = 0;
+  return s;
+}
+
+int
+main(int argc, char **argv)
+{
+  const char **rpms = 0;
+  char *manifest = 0;
+  int manifest0 = 0;
+  int c, i, res, nrpms = 0;
+  Pool *pool = pool_create();
+  Repo *repo;
+  FILE *fp;
+  char buf[4096], *p;
+#ifdef ENABLE_PUBKEY
+  int pubkeys = 0;
+#endif
+#ifdef SUSE
+  int add_auto = 0;
+#endif
+  int filtered_filelist = 0;
+
+  while ((c = getopt(argc, argv, "0XkKm:F")) >= 0)
+    {
+      switch(c)
+       {
+       case 'm':
+         manifest = optarg;
+         break;
+       case '0':
+         manifest0 = 1;
+         break;
+       case 'F':
+         filtered_filelist = 1;
+         break;
+#ifdef ENABLE_PUBKEY
+       case 'k':
+         pubkeys = 1;
+         break;
+       case 'K':
+         pubkeys = 2;
+         break;
+#endif
+       case 'X':
+#ifdef SUSE
+         add_auto = 1;
+#endif
+         break;
+       default:
+         exit(1);
+       }
+    }
+  if (manifest)
+    {
+      if (!strcmp(manifest, "-"))
+        fp = stdin;
+      else if ((fp = fopen(manifest, "r")) == 0)
+       {
+         perror(manifest);
+         exit(1);
+       }
+      for (;;)
+       {
+         if (manifest0)
+           {
+             if (!fgets0(buf, sizeof(buf), fp))
+               break;
+           }
+         else
+           {
+             if (!fgets(buf, sizeof(buf), fp))
+               break;
+             if ((p = strchr(buf, '\n')) != 0)
+               *p = 0;
+           }
+          rpms = solv_extend(rpms, nrpms, 1, sizeof(char *), 15);
+         rpms[nrpms++] = strdup(buf);
+       }
+      if (fp != stdin)
+        fclose(fp);
+    }
+  while (optind < argc)
+    {
+      rpms = solv_extend(rpms, nrpms, 1, sizeof(char *), 15);
+      rpms[nrpms++] = strdup(argv[optind++]);
+    }
+  repo = repo_create(pool, "rpms2solv");
+  repo_add_repodata(repo, 0);
+  res = 0;
+  for (i = 0; i < nrpms; i++)
+    {
+#ifdef ENABLE_PUBKEY
+      if (pubkeys == 2)
+       {
+         FILE *fp = solv_xfopen(rpms[i], "r");
+         if (!fp)
+           {
+             perror(rpms[i]);
+             res = 1;
+             continue;
+           }
+         if (repo_add_keyring(repo, fp, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|ADD_WITH_KEYSIGNATURES))
+           {
+             fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool));
+             res = 1;
+           }
+         fclose(fp);
+         continue;
+       }
+      if (pubkeys)
+        {
+         if (repo_add_pubkey(repo, rpms[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|ADD_WITH_KEYSIGNATURES) == 0)
+           {
+             fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool));
+             res = 1;
+           }
+         continue;
+        }
+#endif
+      if (repo_add_rpm(repo, rpms[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0)) == 0)
+       {
+         fprintf(stderr, "rpms2solv: %s\n", pool_errstr(pool));
+         res = 1;
+       }
+    }
+  repo_internalize(repo);
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, 0);
+#endif
+  tool_write(repo, stdout);
+  pool_free(pool);
+  for (c = 0; c < nrpms; c++)
+    free((char *)rpms[c]);
+  solv_free(rpms);
+  exit(res);
+}
+
diff --git a/libsolv-0.7.2/tools/susetags2solv.c b/libsolv-0.7.2/tools/susetags2solv.c
new file mode 100644 (file)
index 0000000..f7544dc
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_solv.h"
+#include "repo_susetags.h"
+#include "repo_content.h"
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#include "common_write.h"
+#include "solv_xfopen.h"
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "susetags2solv [-c <content>][-d <descrdir>][-h][-n <name>]\n"
+         "  reads a 'susetags' repository from <stdin> and writes a .solv file to <stdout>\n"
+         "  -c <contentfile> : parse given contentfile (for product information)\n"
+          "  -d <descrdir> : do not read from stdin, but use data in descrdir\n"
+         "  -h : print help & exit\n"
+        );
+   exit(status);
+}
+
+/* content file query */
+static void
+doquery(Pool *pool, Repo *repo, const char *arg)
+{
+  char qbuf[256];
+  const char *str;
+  Id id;
+
+  snprintf(qbuf, sizeof(qbuf), "susetags:%s", arg);
+  id = pool_str2id(pool, qbuf, 0);
+  if (!id)
+    return;
+  str = repo_lookup_str(repo, SOLVID_META, id);
+  if (str)
+    printf("%s\n", str);
+}
+
+int
+main(int argc, char **argv)
+{
+  const char *contentfile = 0;
+  const char *descrdir = 0;
+  const char *query = 0;
+  const char *mergefile = 0;
+  Id defvendor = 0;
+  int flags = 0;
+#ifdef SUSE
+  int add_auto = 0;
+#endif
+  int c;
+  Pool *pool;
+  Repo *repo;
+
+  while ((c = getopt(argc, argv, "hc:d:q:M:X")) >= 0)
+    {
+      switch (c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       case 'c':
+         contentfile = optarg;
+         break;
+       case 'd':
+         descrdir = optarg;
+         break;
+       case 'q':
+         query = optarg;
+         break;
+       case 'M':
+         mergefile = optarg;
+         break;
+       case 'X':
+#ifdef SUSE
+         add_auto = 1;
+#endif
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  pool = pool_create();
+  repo = repo_create(pool, "<susetags>");
+
+  repo_add_repodata(repo, 0);
+
+  if (contentfile)
+    {
+      FILE *fp = fopen(contentfile, "r");
+      if (!fp)
+        {
+         perror(contentfile);
+         exit(1);
+       }
+      if (repo_add_content(repo, fp, REPO_REUSE_REPODATA))
+       {
+         fprintf(stderr, "susetags2solv: %s: %s\n", contentfile, pool_errstr(pool));
+         exit(1);
+       }
+      defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+      fclose(fp);
+    }
+
+  /*
+   * descrdir path given, open files and read from there
+   */
+  
+  if (descrdir)
+    {
+      char *fnp;
+      int ndirs, i;
+      struct dirent **files;
+
+      ndirs = scandir(descrdir, &files, 0, alphasort);
+      if (ndirs < 0)
+       {
+         perror(descrdir);
+         exit(1);
+       }
+
+      /* bring packages to front */
+      for (i = 0; i < ndirs; i++)
+       {
+         char *fn = files[i]->d_name;
+         if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz"))
+           break;
+        }
+      if (i == ndirs)
+       {
+         fprintf(stderr, "found no packages file\n");
+         exit(1);
+       }
+      if (i)
+       {
+         struct dirent *de = files[i];
+         memmove(files + 1, files, i * sizeof(de));
+         files[0] = de;
+       }
+
+      fnp = solv_malloc(strlen(descrdir) + 128);
+      for (i = 0; i < ndirs; i++)
+       {
+         char *fn = files[i]->d_name;
+
+         if (!strcmp(fn, "packages") || !strcmp(fn, "packages.gz"))
+           {
+             FILE *fp;
+             sprintf(fnp, "%s/%s", descrdir, fn);
+             fp = solv_xfopen(fnp, 0);
+             if (!fp)
+               {
+                 perror(fn);
+                 exit(1);
+               }
+             if (repo_add_susetags(repo, fp, defvendor, 0, flags | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | SUSETAGS_RECORD_SHARES))
+               {
+                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
+                 exit(1);
+               }
+             fclose(fp);
+           }
+         else if (!strcmp(fn, "packages.DU") || !strcmp(fn, "packages.DU.gz"))
+           {
+             FILE *fp;
+             sprintf(fnp, "%s/%s", descrdir, fn);
+             fp = solv_xfopen(fnp, 0);
+             if (!fp)
+               {
+                 perror(fn);
+                 exit(1);
+               }
+             if (repo_add_susetags(repo, fp, defvendor, 0, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+               {
+                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
+                 exit(1);
+               }
+             fclose(fp);
+           }
+         else if (!strcmp(fn, "packages.FL") || !strcmp(fn, "packages.FL.gz"))
+           {
+#if 0
+             sprintf(fnp, "%s/%s", descrdir, fn);
+             FILE *fp = solv_xfopen(fnp, 0);
+             if (!fp)
+               {
+                 perror(fn);
+                 exit(1);
+               }
+             if (repo_add_susetags(repo, fp, defvendor, 0, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+               {
+                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
+                 exit(1);
+               }
+             fclose(fp);
+#else
+             /* ignore for now. reactivate when filters work */
+             continue;
+#endif
+           }
+         else if (!strncmp(fn, "packages.", 9))
+           {
+             char lang[6];
+             char *p;
+             FILE *fp;
+             sprintf(fnp, "%s/%s", descrdir, fn);
+             p = strrchr(fnp, '.');
+             if (p && !strcmp(p, ".gz"))
+               {
+                 *p = 0;
+                 p = strrchr(fnp, '.');
+               }
+             if (!p || !p[1] || strlen(p + 1) > 5)
+               continue;
+             strcpy(lang, p + 1);
+             sprintf(fnp, "%s/%s", descrdir, fn);
+             fp = solv_xfopen(fnp, 0);
+             if (!fp)
+               {
+                 perror(fn);
+                 exit(1);
+               }
+             if (repo_add_susetags(repo, fp, defvendor, lang, flags | SUSETAGS_EXTEND | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+               {
+                 fprintf(stderr, "susetags2solv: %s: %s\n", fnp, pool_errstr(pool));
+                 exit(1);
+               }
+             fclose(fp);
+           }
+       }
+      for (i = 0; i < ndirs; i++)
+       free(files[i]);
+      free(files);
+      free(fnp);
+      repo_internalize(repo);
+    }
+  else
+    {
+      /* read data from stdin */
+      if (repo_add_susetags(repo, stdin, defvendor, 0, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE))
+       {
+         fprintf(stderr, "susetags2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+    }
+  repo_internalize(repo);
+  if (mergefile)
+    {
+      FILE *fp = fopen(mergefile, "r");
+      if (!fp)
+       {
+         perror(mergefile);
+         exit(1);
+       }
+      if (repo_add_solv(repo, fp, 0))
+       {
+         fprintf(stderr, "susetags2solv: %s\n", pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+    }
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, 0); 
+#endif
+
+  if (query)
+    doquery(pool, repo, query);
+  else
+    tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/libsolv-0.7.2/tools/testsolv.c b/libsolv-0.7.2/tools/testsolv.c
new file mode 100644 (file)
index 0000000..3331fae
--- /dev/null
@@ -0,0 +1,356 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "solver.h"
+#include "selection.h"
+#include "solverdebug.h"
+#include "testcase.h"
+
+static struct resultflags2str {
+  Id flag;
+  const char *str;
+} resultflags2str[] = {
+  { TESTCASE_RESULT_TRANSACTION,        "transaction" },
+  { TESTCASE_RESULT_PROBLEMS,           "problems" },
+  { TESTCASE_RESULT_ORPHANED,           "orphaned" },
+  { TESTCASE_RESULT_RECOMMENDED,        "recommended" },
+  { TESTCASE_RESULT_UNNEEDED,           "unneeded" },
+  { TESTCASE_RESULT_ALTERNATIVES,       "alternatives" },
+  { TESTCASE_RESULT_RULES,              "rules" },
+  { TESTCASE_RESULT_GENID,              "genid" },
+  { TESTCASE_RESULT_REASON,             "reason" },
+  { TESTCASE_RESULT_CLEANDEPS,          "cleandeps" },
+  { TESTCASE_RESULT_JOBS,               "jobs" },
+  { 0, 0 }
+};
+
+static void
+usage(int ex)
+{
+  fprintf(ex ? stderr : stdout, "Usage: testsolv <testcase>\n");
+  exit(ex);
+}
+
+struct reportsolutiondata {
+  int count;
+  char *result;
+};
+
+static int
+reportsolutioncb(Solver *solv, void *cbdata)
+{
+  struct reportsolutiondata *sd = cbdata;
+  char *res;
+
+  sd->count++;
+  res = testcase_solverresult(solv, TESTCASE_RESULT_TRANSACTION);
+  if (*res)
+    {
+      char prefix[64];
+      char *p2, *p = res;
+      sprintf(prefix, "callback%d:", sd->count);
+      while ((p2 = strchr(p, '\n')) != 0)
+       {
+         char c = p2[1];
+         p2[1] = 0;
+         sd->result = solv_dupappend(sd->result, prefix, p);
+         p2[1] = c;
+         p = p2 + 1;
+       }
+    }
+  solv_free(res);
+  return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Queue job;
+  Queue solq;
+  Solver *solv, *reusesolv = 0;
+  char *result = 0;
+  int resultflags = 0;
+  int debuglevel = 0;
+  int writeresult = 0;
+  char *writetestcase = 0;
+  int multijob = 0;
+  int rescallback = 0;
+  int c;
+  int ex = 0;
+  const char *list = 0;
+  int list_with_deps = 0;
+  FILE *fp;
+  const char *p;
+
+  queue_init(&solq);
+  while ((c = getopt(argc, argv, "vmrhL:l:s:T:")) >= 0)
+    {
+      switch (c)
+      {
+        case 'v':
+          debuglevel++;
+          break;
+        case 'r':
+          writeresult++;
+          break;
+        case 'm':
+          rescallback = 1;
+          break;
+        case 'h':
+         usage(0);
+          break;
+        case 'l':
+         list = optarg;
+         list_with_deps = 0;
+          break;
+        case 'L':
+         list = optarg;
+         list_with_deps = 1;
+          break;
+        case 's':
+         if ((p = strchr(optarg, ':')))
+           queue_push2(&solq, atoi(optarg), atoi(p + 1));
+         else
+           queue_push2(&solq, 1, atoi(optarg));
+          break;
+        case 'T':
+         writetestcase = optarg;
+          break;
+        default:
+         usage(1);
+          break;
+      }
+    }
+  if (optind == argc)
+    usage(1);
+  for (; optind < argc; optind++)
+    {
+      pool = pool_create();
+      pool_setdebuglevel(pool, debuglevel);
+      /* report all errors */
+      pool_setdebugmask(pool, pool->debugmask | SOLV_ERROR);
+
+      fp = fopen(argv[optind], "r");
+      if (!fp)
+       {
+         perror(argv[optind]);
+         exit(0);
+       }
+      while (!feof(fp))
+       {
+         queue_init(&job);
+         result = 0;
+         resultflags = 0;
+         solv = testcase_read(pool, fp, argv[optind], &job, &result, &resultflags);
+         if (!solv)
+           {
+             pool_free(pool);
+             exit(resultflags == 77 ? 77 : 1);
+           }
+         if (reusesolv)
+           {
+             solver_free(solv);
+             solv = reusesolv;
+             reusesolv = 0;
+           }
+         if (!multijob && !feof(fp))
+           multijob = 1;
+
+         if (multijob)
+           printf("test %d:\n", multijob++);
+         if (list)
+           {
+             Id p = 0;
+             int selflags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL|SELECTION_GLOB|SELECTION_FLAT;
+             if (*list == '/')
+               selflags |= SELECTION_FILELIST;
+             queue_empty(&job);
+             if (list_with_deps)
+               p = testcase_str2solvid(pool, list);
+             if (p)
+               queue_push2(&job, SOLVER_SOLVABLE, p);
+             else
+               selection_make(pool, &job, list, selflags);
+             if (!job.elements)
+               printf("No match\n");
+             else
+               {
+                 Queue q;
+                 int i;
+                 queue_init(&q);
+                 selection_solvables(pool, &job, &q);
+                 for (i = 0; i < q.count; i++)
+                   {
+                     printf("  - %s\n", testcase_solvid2str(pool, q.elements[i]));
+                     if (list_with_deps)
+                       {
+                         int j, k;
+                         const char *vendor;
+                         static Id deps[] = {
+                           SOLVABLE_PROVIDES, SOLVABLE_REQUIRES, SOLVABLE_CONFLICTS, SOLVABLE_OBSOLETES,
+                           SOLVABLE_RECOMMENDS, SOLVABLE_SUGGESTS, SOLVABLE_SUPPLEMENTS, SOLVABLE_ENHANCES,
+                           SOLVABLE_PREREQ_IGNOREINST,
+                           0
+                         };
+                         vendor = pool_lookup_str(pool, q.elements[i], SOLVABLE_VENDOR);
+                         if (vendor)
+                           printf("    %s: %s\n", pool_id2str(pool, SOLVABLE_VENDOR), vendor);
+                         for (j = 0; deps[j]; j++)
+                           {
+                             Queue dq;
+                             queue_init(&dq);
+                             pool_lookup_idarray(pool, q.elements[i], deps[j], &dq);
+                             if (dq.count)
+                               printf("    %s:\n", pool_id2str(pool, deps[j]));
+                             for (k = 0; k < dq.count; k++)
+                               printf("      %s\n", pool_dep2str(pool, dq.elements[k]));
+                             queue_free(&dq);
+                           }
+                       }
+                   }
+                 queue_free(&q);
+               }
+           }
+         else if (result || writeresult)
+           {
+             char *myresult, *resultdiff;
+             struct reportsolutiondata reportsolutiondata;
+             memset(&reportsolutiondata, 0, sizeof(reportsolutiondata));
+             if (rescallback)
+               {
+                 solv->solution_callback = reportsolutioncb;
+                 solv->solution_callback_data = &reportsolutiondata;
+               }
+             solver_solve(solv, &job);
+             solv->solution_callback = 0;
+             solv->solution_callback_data = 0;
+             if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) == 0)
+               resultflags |= TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS;
+             myresult = testcase_solverresult(solv, resultflags);
+             if (rescallback && reportsolutiondata.result)
+               {
+                 reportsolutiondata.result = solv_dupjoin(reportsolutiondata.result, myresult, 0);
+                 solv_free(myresult);
+                 myresult = reportsolutiondata.result;
+               }
+             if (writeresult)
+               {
+                 if (*myresult)
+                   {
+                     if (writeresult > 1)
+                       {
+                         const char *p;
+                         int i;
+                         
+                         printf("result ");
+                         p = "%s";
+                         for (i = 0; resultflags2str[i].str; i++)
+                           if ((resultflags & resultflags2str[i].flag) != 0)
+                             {
+                               printf(p, resultflags2str[i].str);
+                               p = ",%s";
+                             }
+                         printf(" <inline>\n");
+                         p = myresult;
+                         while (*p)
+                           {
+                             const char *p2 = strchr(p, '\n');
+                             p2 = p2 ? p2 + 1 : p + strlen(p);
+                             printf("#>%.*s", (int)(p2 - p), p);
+                             p = p2;
+                           }
+                       }
+                     else
+                       printf("%s", myresult);
+                   }
+               }
+             else
+               {
+                 resultdiff = testcase_resultdiff(result, myresult);
+                 if (resultdiff)
+                   {
+                     printf("Results differ:\n%s", resultdiff);
+                     ex = 1;
+                     solv_free(resultdiff);
+                   }
+               }
+             solv_free(result);
+             solv_free(myresult);
+           }
+         else
+           {
+             int pcnt = solver_solve(solv, &job);
+             if (writetestcase)
+               testcase_write(solv, writetestcase, resultflags, 0, 0);
+             if (pcnt && solq.count)
+               {
+                 int i, taken = 0;
+                 for (i = 0; i < solq.count; i += 2)
+                   {
+                     if (solq.elements[i] > 0 && solq.elements[i] <= pcnt)
+                       if (solq.elements[i + 1] > 0 && solq.elements[i + 1] <=  solver_solution_count(solv, solq.elements[i]))
+                         {
+                           printf("problem %d: taking solution %d\n", solq.elements[i], solq.elements[i + 1]);
+                           solver_take_solution(solv, solq.elements[i], solq.elements[i + 1], &job);
+                           taken = 1;
+                         }
+                   }
+                 if (taken)
+                   pcnt = solver_solve(solv, &job);
+               }
+             if (pcnt)
+               {
+                 int problem, solution, scnt;
+                 printf("Found %d problems:\n", pcnt);
+                 for (problem = 1; problem <= pcnt; problem++)
+                   {
+                     printf("Problem %d:\n", problem);
+#if 1
+                     solver_printprobleminfo(solv, problem);
+#else
+                     {
+                       Queue pq;
+                       int j;
+                       queue_init(&pq);
+                       solver_findallproblemrules(solv, problem, &pq);
+                       for (j = 0; j < pq.count; j++)
+                         solver_printproblemruleinfo(solv, pq.elements[j]);
+                       queue_free(&pq);
+                     }
+#endif
+                     printf("\n");
+                     scnt = solver_solution_count(solv, problem);
+                     for (solution = 1; solution <= scnt; solution++)
+                       {
+                         printf("Solution %d:\n", solution);
+                         solver_printsolution(solv, problem, solution);
+                         printf("\n");
+                       }
+                   }
+               }
+             else
+               {
+                 Transaction *trans = solver_create_transaction(solv);
+                 printf("Transaction summary:\n\n");
+                 transaction_print(trans);
+                 transaction_free(trans);
+               }
+           }
+         queue_free(&job);
+         if ((resultflags & TESTCASE_RESULT_REUSE_SOLVER) != 0 && !feof(fp))
+           reusesolv = solv;
+         else
+           solver_free(solv);
+       }
+      if (reusesolv)
+       solver_free(reusesolv);
+      pool_free(pool);
+      fclose(fp);
+    }
+  queue_free(&solq);
+  exit(ex);
+}
diff --git a/libsolv-0.7.2/tools/updateinfoxml2solv.c b/libsolv-0.7.2/tools/updateinfoxml2solv.c
new file mode 100644 (file)
index 0000000..9bc038e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_updateinfoxml.h"
+#include "common_write.h"
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "updateinfoxml2solv [-h]\n"
+         "  reads a 'updateinfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
+         "  -h : print help & exit\n"
+        );
+  exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, flags = 0;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+
+  while ((c = getopt(argc, argv, "h")) >= 0)
+    {
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  if (repo_add_updateinfoxml(repo, stdin, flags))
+    {
+      fprintf(stderr, "updateinfoxml2solv: %s\n", pool_errstr(pool));
+      exit(1);
+    }
+  tool_write(repo, stdout);
+  pool_free(pool);
+  exit(0);
+}
index 80986a0a4133b0f542acb323712edfda61e73aea..25e1cca18488134dc2b967a93c66715034d47522 100644 (file)
 
 
 Name:           perl-BSSolv
-Version:        0.28.0
+Version:        0.37.0
 Release:        1.1
 Url:            https://github.com/openSUSE/perl-BSSolv
 Source:         %{name}-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 
-%if 0%{?mandriva_version}
-# force this version on mandriva
-BuildRequires:  libneon0.26-devel
-%endif
 %if 0%{?fedora_version}
-BuildRequires:  db4-devel
 BuildRequires:  perl-devel
 %endif
 %if 0%{?suse_version}
 Requires:       perl = %perl_version
-%if 0%{?suse_version} < 1030
-BuildRequires:  expat
-%else
-BuildRequires:  libexpat-devel
-%endif
-%else
-BuildRequires:  expat-devel
-%endif
-%if 0%{?rhel_version} || 0%{?centos_version}
-BuildRequires:  db4-devel
 %endif
 BuildRequires:  cmake
 BuildRequires:  gcc-c++
 BuildRequires:  perl
-BuildRequires:  rpm-devel
 BuildRequires:  xz-devel
 BuildRequires:  zlib-devel
+BuildRequires:  libzstd-devel
 #RHEL6 moved ExtUtils::MakeMaker outside the main perl package
 BuildRequires:  perl(ExtUtils::MakeMaker)
 # the testsuite uses the check framework
@@ -76,10 +61,6 @@ export CFLAGS="$RPM_OPT_FLAGS"
 export CXXFLAGS="$CFLAGS"
 
 CMAKE_FLAGS=
-%if 0%{?fedora_version} || 0%{?rhel_version} || 0%{?centos_version}
-CMAKE_FLAGS="-DFEDORA=1"
-%endif
-
 %if 0%{?rhel_version} || 0%{?centos_version}
 CFLAGS="$CFLAGS -DUSE_OWN_QSORT"
 %endif
@@ -89,17 +70,23 @@ cmake   $CMAKE_FLAGS \
        -DDISABLE_SHARED=1 \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_SKIP_RPATH=1 \
-       -DENABLE_RPMDB=1 \
+       -DENABLE_RPMPKG=1 \
        -DENABLE_DEBIAN=1 \
        -DENABLE_ARCHREPO=1 \
        -DENABLE_LZMA_COMPRESSION=1 \
+       -DENABLE_ZSTD_COMPRESSION=1 \
+       -DENABLE_COMPLEX_DEPS=1 \
        -DMULTI_SEMANTICS=1
 pushd src ; make ; popd
 pushd ext ; make ; popd
 popd
+
 perl Makefile.PL --bundled-libsolv
 make
 
+%check
+make test
+
 %install
 make DESTDIR=$RPM_BUILD_ROOT install_vendor
 %if 0%{?suse_version}  
@@ -123,123 +110,4 @@ find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \;
 %endif
 
 %changelog
-* Fri Apr  1 2016 mls@suse.de
-- update to version 0.28.0 (perl module 0.08 version)
-  * fix typo, rename obscpiostats to obscpiostorestats
-* Fri Apr  1 2016 mls@suse.de
-- update to version 0.27.0 (perl module 0.07 version)
-  * add delta storage support
-* Tue Mar 15 2016 mls@suse.de
-- update to version 0.26.0 (perl module 0.06 version)
-  * add preparehashes pool method to speed up the scheduler
-* Tue Aug 18 2015 mls@suse.de
-- update to version 0.25.0 (perl module 0.05 version)
-  * make checksums pass our writefilter
-* Tue Aug 18 2015 mls@suse.de
-- update to version 0.24.0 (perl module 0.04 version)
-  * allow setting of the dodcookie without a dodurl
-* Thu Jul 30 2015 mls@suse.de
-- update to version 0.23.0 (perl module 0.03 version)
-  * implement download on demand data updating
-* Thu Jun 11 2015 adrian@suse.de
-- update to version 0.22.0 (perl module 0.02 version)
-  * implement handling of conflicts (aka '!') deps in expander
-  * treat ARCH_ANY like ARCH_ALL
-  * improve conflictsinfo handling
-  * support --ignoreignore-- flag
-  * improved debug output
-* Thu Sep 18 2014 ro@suse.de
-- update to BSSolv.xs from GIT
-* Fri Oct 18 2013 mls@suse.de
-- update to libsolv-0.4.0 to get REL_MULTIARCH support
-* Wed Feb  6 2013 mls@suse.de
-- update to libsolv-0.2.4
-* Wed Nov 14 2012 mls@suse.de
-- update BSSolv.xs to get debugstr support
-* Tue Nov 13 2012 mls@suse.de
-- support 'ignoreconflicts' expandflag
-* Tue Nov 13 2012 mls@suse.de
-- use REPO_NO_LOCATION
-* Mon Nov 12 2012 mls@suse.de
-- update libsolv to current version to fix deb parsing
-- bump repocookie
-* Mon Oct 15 2012 mls@suse.de
-- update libsolv and BSSolv.xs to current version
-  * export all dependencies
-  * obey package conflicts when expanding
-* Fri Apr 27 2012 mls@suse.de
-- update BSSolv.xs so that the worker caches binaries again
-* Wed Apr 25 2012 mls@suse.de
-- bump version to 0.18.2
-- update to libsolv-0.1.0 to fix opensuse 11.4 builds
-* Wed Apr  4 2012 mls@suse.de
-- bump version to 0.18.1
-- update to current libsolv
-- enable arch linux support
-* Wed Nov 30 2011 adrian@suse.de
-- bump version to 0.18.0
-- base package on libsolv tar ball
-* Wed Nov 30 2011 mls@suse.de
-- update BSSolv.xs:
-  * fix prefer order handling bug
-  * add repo->tofile_fd
-* Wed Nov 16 2011 mls@suse.de
-- fix debian control file extraction, thanks djszapi!
-* Thu Aug 25 2011 mls@suse.de
-- fix debian dependency compare function
-* Tue Jun 28 2011 coolo@novell.com
-- add requires to correct perl version
-* Tue Feb 15 2011 mls@suse.de
-- define USE_OWN_QSORT instead of using glib
-* Mon Feb 14 2011 adrian@suse.de
-- update to 0.16.4
-* Thu Dec  9 2010 adrian@suse.de
-- update to 0.16.2
-- fix build for Factory
-* Fri Oct 29 2010 adrian@suse.de
-- follow the version of satsolver for this package
-* Sat Oct 23 2010 mrdocs@opensuse.org
-- fix the build with the correct source version
-* Tue Oct 19 2010 adrian@suse.de
-- adapt spec to version 0.16.0
-* Fri Jul 23 2010 adrian@suse.de
-- update BSSolv.xs from current build-service git repo
-* Fri May 14 2010 adrian@suse.de
-- adapt spec to version 0.15.0
-* Wed Apr  7 2010 mls@suse.de
-- adapt spec to version 0.14.17
-* Mon Mar 15 2010 chris@computersalat.de
-- fix spec
-  o new version 0.14.16 (zypp:Head)
-* Tue Mar  2 2010 chris@computersalat.de
-- hmm, cause of undocumented SOURCE changes
-  (satsolver-0.14.15 from zypp:Head),
-  util patch (SLES 10 fix) now obsolete
-  o hence removed
-* Sun Feb 28 2010 adrian@suse.de
-- fixed SLES 10 fix
-* Tue Feb 23 2010 chris@computersalat.de
-- fix spec
-  o new version 0.14.15 (zypp:Head)
-- reworked patch for SLE_10
-* Fri Feb 12 2010 chris@computersalat.de
-- spec mods
-  o added header
-  o fixed source version
-- fix build for SLE_10
-  o added satsolver-0.14.14-util.patch
-- BuildReq ruby-devel > 1.8.4
-  o /usr/bin/ruby: no such file to
-    load -- vendor-specific (LoadError)
-* Mon Dec 21 2009 mls@suse.de
-- add dod changes
-- fix bug in debian dep parsing
-- add support for whatprovides/whatrequires
-* Fri Oct 23 2009 mls@suse.de
-- strip trailing spaces in dep2id
-* Wed Oct 21 2009 mls@suse.de
-- add pkg2sizek
-* Wed Oct  7 2009 mls@suse.de
-- update BSSolv.xs
-* Tue Oct  6 2009 mls@suse.de
-- initial version
+